Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Create permissioned vault with authority #11

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Binary file modified bun.lockb
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"rpcUrl": "https://api.mainnet-beta.solana.com",
"dryRun": true,
"keypairFilePath": "keypair.json",
"computeUnitPriceMicroLamports": 100000,
"baseMint": "3B5wuUrMEi5yATD7on46hKfej3pfmd7t1RKgrsN3pump",
"quoteSymbol": "SOL",
"dynamicAmm": {
"baseAmount": "100",
"quoteAmount": "0.001",
"tradeFeeNumerator": 2500,
"activationType": "timestamp",
"activationPoint": null,
"hasAlphaVault": true
},
"alphaVault": {
"poolType": "dynamic",
"alphaVaultType": "fcfs",
"depositingPoint": 1733547099,
"startVestingPoint": 1733548099,
"endVestingPoint": 1733549099,
"maxDepositCap": 100,
"individualDepositingCap": 1,
"escrowFee": 0,
"whitelistMode": "permissioned_with_authority",
"whitelistFilepath": "./config/whitelist_wallet.csv"
}
}
2 changes: 2 additions & 0 deletions config/whitelist_wallet.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
address,maxAmount
ETp2wTykSe3iGYzPCn6upP8NVB7a1pe6WTZidGNJH7KC,0.5
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"test": "bun test",
"create-dynamic-amm-pool": "bun run src/create_pool.ts --config ./config/create_dynamic_amm_pool.json",
"create-dlmm-pool": "bun run src/create_pool.ts --config ./config/create_dlmm_pool.json",
"start-test-validator": "solana-test-validator --bind-address 0.0.0.0 --account-dir ./src/tests/artifacts/accounts --bpf-program LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ ./src/tests/artifacts/lb_clmm.so --bpf-program Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB ./src/tests/artifacts/dynamic_amm.so --bpf-program 24Uqj9JCLxUeoC3hGfh5W3s9FM9uCHDS2SG3LYwBpyTi ./src/tests/artifacts/dynamic_vault.so --bpf-program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s ./src/tests/artifacts/metaplex.so --mint bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1 --reset"
"start-test-validator": "solana-test-validator --bind-address 0.0.0.0 --account-dir ./src/tests/artifacts/accounts --bpf-program LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ ./src/tests/artifacts/lb_clmm.so --bpf-program Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB ./src/tests/artifacts/dynamic_amm.so --bpf-program 24Uqj9JCLxUeoC3hGfh5W3s9FM9uCHDS2SG3LYwBpyTi ./src/tests/artifacts/dynamic_vault.so --bpf-program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s ./src/tests/artifacts/metaplex.so --bpf-program SNPmGgnywBvvrAKMLundzG6StojyHTHDLu7T4sdhP4k ./src/tests/artifacts/alpha_vault.so --mint bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1 --reset"
},
"dependencies": {
"@coral-xyz/anchor": "^0.28.0",
Expand All @@ -20,6 +20,7 @@
"@types/jest": "^29.5.14",
"ajv": "^8.17.1",
"bn.js": "^5.2.1",
"csv-parse": "^5.6.0",
"decimal.js": "^10.4.3"
},
"author": "",
Expand Down
262 changes: 90 additions & 172 deletions src/create_alpha_vault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,19 @@ import {
parseConfigFromCli,
getAlphaVaultPoolType,
modifyComputeUnitPriceIx,
AlphaVaultTypeConfig,
PoolTypeConfig,
toAlphaVaulSdkPoolType,
WhitelistModeConfig,
parseCsv,
} from ".";
import { Wallet } from "@coral-xyz/anchor";
import { AnchorProvider, Wallet } from "@coral-xyz/anchor";

import { BN } from "bn.js";
import AlphaVault, { PoolType } from "@meteora-ag/alpha-vault";
import AlphaVault, {
PoolType,
WalletDepositCap,
} from "@meteora-ag/alpha-vault";
import {
LBCLMM_PROGRAM_IDS,
deriveCustomizablePermissionlessLbPair,
Expand All @@ -31,6 +39,11 @@ import {
deriveCustomizablePermissionlessConstantProductPoolAddress,
createProgram,
} from "@mercurial-finance/dynamic-amm-sdk/dist/cjs/src/amm/utils";
import {
createFcfsAlphaVault,
createPermissionedAlphaVaultWithAuthority,
createProrataAlphaVault,
} from "./libs/create_alpha_vault_utils";

async function main() {
let config: MeteoraConfig = parseConfigFromCli();
Expand All @@ -45,6 +58,9 @@ async function main() {

const connection = new Connection(config.rpcUrl, DEFAULT_COMMITMENT_LEVEL);
const wallet = new Wallet(keypair);
const provider = new AnchorProvider(connection, wallet, {
commitment: connection.commitment,
});

if (!config.baseMint) {
throw new Error("Missing baseMint in configuration");
Expand All @@ -59,17 +75,16 @@ async function main() {
if (!config.alphaVault) {
throw new Error("Missing alpha vault in configuration");
}

const poolType = getAlphaVaultPoolType(config.alphaVault.poolType);
const poolType = config.alphaVault.poolType;

let poolKey: PublicKey;
if (poolType == PoolType.DYNAMIC) {
if (poolType == PoolTypeConfig.Dynamic) {
poolKey = deriveCustomizablePermissionlessConstantProductPoolAddress(
baseMint,
quoteMint,
createProgram(connection).ammProgram.programId,
);
} else if (poolType == PoolType.DLMM) {
} else if (poolType == PoolTypeConfig.Dlmm) {
[poolKey] = deriveCustomizablePermissionlessLbPair(
baseMint,
quoteMint,
Expand All @@ -79,181 +94,84 @@ async function main() {
throw new Error(`Invalid pool type ${poolType}`);
}

console.log(
`\n> Pool address: ${poolKey}, pool type ${config.alphaVault.poolType}`,
);

let initAlphaVaultTx: Transaction | null = null;
if (config.alphaVault.alphaVaultType == "fcfs") {
initAlphaVaultTx = await createFcfsAlphaVault(
connection,
wallet,
poolType,
poolKey,
baseMint,
quoteMint,
quoteDecimals,
config.alphaVault as FcfsAlphaVaultConfig,
console.log(`\n> Pool address: ${poolKey}, pool type ${poolType}`);

// create permissioned alpha vault with authority
if (
config.alphaVault.whitelistMode ==
WhitelistModeConfig.PermissionedWithAuthority
) {
if (!config.alphaVault.whitelistFilepath) {
throw new Error("Missing whitelist filepath in configuration");
}

interface WhitelistCsv {
address: string;
maxAmount: string;
}
const whitelistListCsv: Array<WhitelistCsv> = await parseCsv(
config.alphaVault.whitelistFilepath,
);
} else if (config.alphaVault.alphaVaultType == "prorata") {
initAlphaVaultTx = await createProrataAlphaVault(

const whitelistList: Array<WalletDepositCap> = new Array(0);
for (const item of whitelistListCsv) {
whitelistList.push({
address: new PublicKey(item.address),
maxAmount: getAmountInLamports(item.maxAmount, quoteDecimals),
});
}

await createPermissionedAlphaVaultWithAuthority(
connection,
wallet,
poolType,
config.alphaVault.alphaVaultType,
toAlphaVaulSdkPoolType(poolType),
poolKey,
baseMint,
quoteMint,
quoteDecimals,
config.alphaVault as ProrataAlphaVaultConfig,
);
} else {
throw new Error(
`Invalid alpha vault type ${config.alphaVault.alphaVaultType}`,
);
}
modifyComputeUnitPriceIx(
initAlphaVaultTx,
config.computeUnitPriceMicroLamports,
);

if (config.dryRun) {
console.log(`\n> Simulating init alpha vault tx...`);
await runSimulateTransaction(connection, [wallet.payer], wallet.publicKey, [
initAlphaVaultTx,
]);
} else {
console.log(`>> Sending init alpha vault transaction...`);
const initAlphaVaulTxHash = await sendAndConfirmTransaction(
connection,
initAlphaVaultTx,
[wallet.payer],
).catch((err) => {
console.error(err);
throw err;
});
console.log(
`>>> Alpha vault initialized successfully with tx hash: ${initAlphaVaulTxHash}`,
config.alphaVault,
whitelistList,
config.dryRun,
config.computeUnitPriceMicroLamports,
);
} else if (
config.alphaVault.whitelistMode == WhitelistModeConfig.Permissionless
) {
if (config.alphaVault.alphaVaultType == AlphaVaultTypeConfig.Fcfs) {
await createFcfsAlphaVault(
connection,
wallet,
toAlphaVaulSdkPoolType(poolType),
poolKey,
baseMint,
quoteMint,
quoteDecimals,
config.alphaVault as FcfsAlphaVaultConfig,
config.dryRun,
config.computeUnitPriceMicroLamports,
);
} else if (
config.alphaVault.alphaVaultType == AlphaVaultTypeConfig.Prorata
) {
await createProrataAlphaVault(
connection,
wallet,
toAlphaVaulSdkPoolType(poolType),
poolKey,
baseMint,
quoteMint,
quoteDecimals,
config.alphaVault as ProrataAlphaVaultConfig,
config.dryRun,
config.computeUnitPriceMicroLamports,
);
} else {
throw new Error(
`Invalid alpha vault type ${config.alphaVault.alphaVaultType}`,
);
}
}
}

async function createFcfsAlphaVault(
connection: Connection,
wallet: Wallet,
poolType: PoolType,
poolAddress: PublicKey,
baseMint: PublicKey,
quoteMint: PublicKey,
quoteDecimals: number,
params: FcfsAlphaVaultConfig,
): Promise<Transaction> {
let maxDepositingCap = getAmountInLamports(
params.maxDepositCap,
quoteDecimals,
);
let individualDepositingCap = getAmountInLamports(
params.individualDepositingCap,
quoteDecimals,
);
let escrowFee = getAmountInLamports(params.escrowFee, quoteDecimals);
let whitelistMode = getAlphaVaultWhitelistMode(params.whitelistMode);

console.log(`\n> Initializing FcfsAlphaVault...`);
console.log(`- Using poolType: ${poolType}`);
console.log(`- Using poolMint ${poolAddress}`);
console.log(`- Using baseMint ${baseMint}`);
console.log(`- Using quoteMint ${quoteMint}`);
console.log(`- Using depositingPoint ${params.depositingPoint}`);
console.log(`- Using startVestingPoint ${params.startVestingPoint}`);
console.log(`- Using endVestingPoint ${params.endVestingPoint}`);
console.log(
`- Using maxDepositingCap ${params.maxDepositCap}. In lamports ${maxDepositingCap}`,
);
console.log(
`- Using individualDepositingCap ${params.individualDepositingCap}. In lamports ${individualDepositingCap}`,
);
console.log(
`- Using escrowFee ${params.escrowFee}. In lamports ${escrowFee}`,
);
console.log(
`- Using whitelistMode ${params.whitelistMode}. In value ${whitelistMode}`,
);

const tx = await AlphaVault.createCustomizableFcfsVault(
connection,
{
quoteMint,
baseMint,
poolAddress,
poolType,
depositingPoint: new BN(params.depositingPoint),
startVestingPoint: new BN(params.startVestingPoint),
endVestingPoint: new BN(params.endVestingPoint),
maxDepositingCap,
individualDepositingCap,
escrowFee,
whitelistMode,
},
wallet.publicKey,
{
cluster: "mainnet-beta",
},
);
return tx;
}

async function createProrataAlphaVault(
connection: Connection,
wallet: Wallet,
poolType: PoolType,
poolAddress: PublicKey,
baseMint: PublicKey,
quoteMint: PublicKey,
quoteDecimals: number,
params: ProrataAlphaVaultConfig,
): Promise<Transaction> {
let maxBuyingCap = getAmountInLamports(params.maxBuyingCap, quoteDecimals);
let escrowFee = getAmountInLamports(params.escrowFee, quoteDecimals);
let whitelistMode = getAlphaVaultWhitelistMode(params.whitelistMode);

console.log(`\n> Initializing ProrataAlphaVault...`);
console.log(`- Using poolType: ${poolType}`);
console.log(`- Using poolMint ${poolAddress}`);
console.log(`- Using baseMint ${baseMint}`);
console.log(`- Using quoteMint ${quoteMint}`);
console.log(`- Using depositingPoint ${params.depositingPoint}`);
console.log(`- Using startVestingPoint ${params.startVestingPoint}`);
console.log(`- Using endVestingPoint ${params.endVestingPoint}`);
console.log(
`- Using maxBuyingCap ${params.maxBuyingCap}. In lamports ${maxBuyingCap}`,
);
console.log(
`- Using escrowFee ${params.escrowFee}. In lamports ${escrowFee}`,
);
console.log(
`- Using whitelistMode ${params.whitelistMode}. In value ${whitelistMode}`,
);

const tx = await AlphaVault.createCustomizableProrataVault(
connection,
{
quoteMint,
baseMint,
poolAddress,
poolType,
depositingPoint: new BN(params.depositingPoint),
startVestingPoint: new BN(params.startVestingPoint),
endVestingPoint: new BN(params.endVestingPoint),
maxBuyingCap,
escrowFee,
whitelistMode,
},
wallet.publicKey,
{
cluster: "mainnet-beta",
},
);
return tx;
}

main();
3 changes: 3 additions & 0 deletions src/libs/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ const CONFIG_SCHEMA: JSONSchemaType<MeteoraConfig> = {
"permissioned_with_authority",
],
},
whitelistFilepath: { type: "string", nullable: true },
},
required: [
"poolType",
Expand Down Expand Up @@ -293,6 +294,7 @@ export interface FcfsAlphaVaultConfig {
escrowFee: number;
// whitelist mode: permissionless / permission_with_merkle_proof / permission_with_authority
whitelistMode: WhitelistModeConfig;
whitelistFilepath?: string;
}

export interface ProrataAlphaVaultConfig {
Expand All @@ -310,6 +312,7 @@ export interface ProrataAlphaVaultConfig {
escrowFee: number;
// whitelist mode: permissionless / permission_with_merkle_proof / permission_with_authority
whitelistMode: WhitelistModeConfig;
whitelistFilepath?: string;
}

export interface LockLiquidityConfig {
Expand Down
Loading
Loading