From 3ce7d6ea05ac98f0ecf457d6df2485fa5ecd68e0 Mon Sep 17 00:00:00 2001 From: McSam Date: Wed, 10 Jan 2024 15:32:46 +0800 Subject: [PATCH 1/2] feat: lp-metadata --- programs/amm/Cargo.toml | 18 +- programs/amm/src/context.rs | 16 ++ ts-client/src/amm/constants.ts | 2 + ts-client/src/amm/idl.ts | 442 +++++++++++++++++++++++++-------- ts-client/src/amm/index.ts | 7 +- ts-client/src/amm/utils.ts | 8 + 6 files changed, 383 insertions(+), 110 deletions(-) diff --git a/programs/amm/Cargo.toml b/programs/amm/Cargo.toml index aaa6458f..95049092 100644 --- a/programs/amm/Cargo.toml +++ b/programs/amm/Cargo.toml @@ -26,20 +26,28 @@ overflow-checks = true [dependencies] anchor-lang = "0.28.0" anchor-spl = "0.28.0" -mercurial-vault = { git="https://github.com/mercurial-finance/mercurial_sdk", features= ["cpi" , "no-entrypoint"], rev = "c590d6ba19ecb58d80dbe8b33fa8056a1ddbff43" } +mercurial-vault = { git = "https://github.com/mercurial-finance/mercurial_sdk", features = [ + "cpi", + "no-entrypoint", +], rev = "c590d6ba19ecb58d80dbe8b33fa8056a1ddbff43" } spl-token-swap = { version = "3.0.0", features = ["no-entrypoint"] } -meteora-stable-swap-math = { git="https://github.com/mercurial-finance/stable-swap", rev = "f49a9166fd1b7afd14dded3cdd600fb19b4c6982", package="stable-swap-math"} -meteora-stable-swap-client = { git="https://github.com/mercurial-finance/stable-swap", rev = "f49a9166fd1b7afd14dded3cdd600fb19b4c6982", package="stable-swap-client" } +meteora-stable-swap-math = { git = "https://github.com/mercurial-finance/stable-swap", rev = "f49a9166fd1b7afd14dded3cdd600fb19b4c6982", package = "stable-swap-math" } +meteora-stable-swap-client = { git = "https://github.com/mercurial-finance/stable-swap", rev = "f49a9166fd1b7afd14dded3cdd600fb19b4c6982", package = "stable-swap-client" } meteora-marinade-sdk = { version = "0.1.0", features = ["cpi"] } -spl-stake-pool = { git = "https://github.com/solana-labs/solana-program-library", rev = "cd79bba17331235ab489bae56600043ea853c70b", features = ["no-entrypoint"] } +spl-stake-pool = { git = "https://github.com/solana-labs/solana-program-library", rev = "cd79bba17331235ab489bae56600043ea853c70b", features = [ + "no-entrypoint", +] } anyhow = "1.0.71" +mpl-token-metadata = "3.2.3" [dev-dependencies] solana-program-test = "1.16.12" solana-sdk = "1.16.12" solana-account-decoder = "1.16.12" solana-client = "1.16.12" -spl-associated-token-account = { version = "1.1.2", features = ["no-entrypoint"] } +spl-associated-token-account = { version = "1.1.2", features = [ + "no-entrypoint", +] } serde_json = "1.0.95" serde = "1.0.159" bincode = "1.3.3" \ No newline at end of file diff --git a/programs/amm/src/context.rs b/programs/amm/src/context.rs index 9e42a1d9..dbc6e494 100644 --- a/programs/amm/src/context.rs +++ b/programs/amm/src/context.rs @@ -291,6 +291,14 @@ pub struct InitializePermissionlessPoolWithFeeTier<'info> { )] pub admin_token_b_fee: Box>, + /// CHECK: LP mint metadata PDA. Metaplex do the checking. + #[account(mut)] + pub mint_metadata: UncheckedAccount<'info>, + + /// CHECK: Metadata program + #[account(address = mpl_token_metadata::ID)] + pub metadata_program: UncheckedAccount<'info>, + /// Admin account. This account will be the admin of the pool, and the payer for PDA during initialize pool. #[account(mut)] pub payer: Signer<'info>, @@ -466,6 +474,14 @@ pub struct InitializePermissionlessPool<'info> { )] pub admin_token_b_fee: Box>, + /// CHECK: LP mint metadata PDA. Metaplex do the checking. + #[account(mut)] + pub mint_metadata: UncheckedAccount<'info>, + + /// CHECK: Metadata program + #[account(address = mpl_token_metadata::ID)] + pub metadata_program: UncheckedAccount<'info>, + /// Admin account. This account will be the admin of the pool, and the payer for PDA during initialize pool. #[account(mut)] pub payer: Signer<'info>, diff --git a/ts-client/src/amm/constants.ts b/ts-client/src/amm/constants.ts index b187765e..d358557a 100644 --- a/ts-client/src/amm/constants.ts +++ b/ts-client/src/amm/constants.ts @@ -123,3 +123,5 @@ export const CONSTANT_PRODUCT_ALLOWED_TRADE_FEE_BPS = [25, 100, 400, 600]; export const STABLE_SWAP_DEFAULT_TRADE_FEE_BPS = 1; export const STABLE_SWAP_ALLOWED_TRADE_FEE_BPS = [1, 4, 10, 100]; + +export const METAPLEX_PROGRAM = new PublicKey('metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'); diff --git a/ts-client/src/amm/idl.ts b/ts-client/src/amm/idl.ts index 78355860..dc4d277f 100644 --- a/ts-client/src/amm/idl.ts +++ b/ts-client/src/amm/idl.ts @@ -1,5 +1,5 @@ export type Amm = { - version: '0.4.8'; + version: '0.4.12'; name: 'amm'; docs: ['Program for AMM']; instructions: [ @@ -43,18 +43,6 @@ export type Amm = { isSigner: false; docs: ['Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.']; }, - { - name: 'aTokenVault'; - isMut: true; - isSigner: false; - docs: ['Token vault account of vault A']; - }, - { - name: 'bTokenVault'; - isMut: true; - isSigner: false; - docs: ['Token vault account of vault B']; - }, { name: 'aVaultLpMint'; isMut: true; @@ -133,6 +121,16 @@ export type Amm = { isSigner: false; docs: ['Rent account.']; }, + { + name: 'mintMetadata'; + isMut: true; + isSigner: false; + }, + { + name: 'metadataProgram'; + isMut: false; + isSigner: false; + }, { name: 'vaultProgram'; isMut: false; @@ -165,14 +163,6 @@ export type Amm = { defined: 'CurveType'; }; }, - { - name: 'tokenAAmount'; - type: 'u64'; - }, - { - name: 'tokenBAmount'; - type: 'u64'; - }, ]; }, { @@ -301,6 +291,16 @@ export type Amm = { isSigner: false; docs: ['Rent account.']; }, + { + name: 'mintMetadata'; + isMut: true; + isSigner: false; + }, + { + name: 'metadataProgram'; + isMut: false; + isSigner: false; + }, { name: 'vaultProgram'; isMut: false; @@ -469,6 +469,16 @@ export type Amm = { isSigner: false; docs: ['Rent account.']; }, + { + name: 'mintMetadata'; + isMut: true; + isSigner: false; + }, + { + name: 'metadataProgram'; + isMut: false; + isSigner: false; + }, { name: 'vaultProgram'; isMut: false; @@ -1219,37 +1229,6 @@ export type Amm = { ]; args: []; }, - { - name: 'setAdminFeeAccount'; - docs: ['Update fee token account of the pool admin.']; - accounts: [ - { - name: 'pool'; - isMut: true; - isSigner: false; - docs: ['Pool account (PDA)']; - }, - { - name: 'newAdminTokenAFee'; - isMut: true; - isSigner: false; - docs: ['New admin fee token account for pool token A. Used to receive trading fee.']; - }, - { - name: 'newAdminTokenBFee'; - isMut: true; - isSigner: false; - docs: ['New admin fee token account for pool token B. Used to receive trading fee.']; - }, - { - name: 'admin'; - isMut: false; - isSigner: true; - docs: ['Admin account. Must be owner of the pool.']; - }, - ]; - args: []; - }, { name: 'getPoolInfo'; docs: ['Get the general information of the pool.']; @@ -1429,6 +1408,144 @@ export type Amm = { }, ]; }, + { + name: 'migrateFeeAccount'; + docs: ['Migrate old token fee owner to PDA']; + accounts: [ + { + name: 'pool'; + isMut: true; + isSigner: false; + docs: ['Pool account']; + }, + { + name: 'aVaultLp'; + isMut: false; + isSigner: false; + docs: ['A vault LP token account of the pool.']; + }, + { + name: 'adminTokenAFee'; + isMut: true; + isSigner: false; + docs: ['Admin fee token account for token A. Used to receive trading fee.']; + }, + { + name: 'adminTokenBFee'; + isMut: true; + isSigner: false; + docs: ['Admin fee token account for token B. Used to receive trading fee.']; + }, + { + name: 'tokenAMint'; + isMut: false; + isSigner: false; + docs: ['Token A mint']; + }, + { + name: 'tokenBMint'; + isMut: false; + isSigner: false; + docs: ['Token B mint']; + }, + { + name: 'newAdminTokenAFee'; + isMut: true; + isSigner: false; + docs: ['Token fee account. Controlled by pool a_vault_lp PDA.']; + }, + { + name: 'newAdminTokenBFee'; + isMut: true; + isSigner: false; + docs: ['Token fee account. Controlled by pool a_vault_lp PDA.']; + }, + { + name: 'admin'; + isMut: true; + isSigner: true; + docs: ['Admin account. Must be owner of the pool.']; + }, + { + name: 'treasuryTokenAFee'; + isMut: true; + isSigner: false; + docs: ['Treasury token a fee ATA.']; + }, + { + name: 'treasuryTokenBFee'; + isMut: true; + isSigner: false; + docs: ['Treasury token b fee ATA.']; + }, + { + name: 'treasury'; + isMut: false; + isSigner: true; + docs: ['Treasury signer']; + }, + { + name: 'tokenProgram'; + isMut: false; + isSigner: false; + docs: ['Token program.']; + }, + { + name: 'systemProgram'; + isMut: false; + isSigner: false; + docs: ['System program.']; + }, + ]; + args: []; + }, + { + name: 'createMintMetadata'; + docs: ['Create mint metadata account for old pools']; + accounts: [ + { + name: 'pool'; + isMut: false; + isSigner: false; + docs: ['Pool account']; + }, + { + name: 'lpMint'; + isMut: false; + isSigner: false; + docs: ['LP mint account of the pool']; + }, + { + name: 'aVaultLp'; + isMut: false; + isSigner: false; + docs: ['Vault A LP account of the pool']; + }, + { + name: 'mintMetadata'; + isMut: true; + isSigner: false; + }, + { + name: 'metadataProgram'; + isMut: false; + isSigner: false; + }, + { + name: 'systemProgram'; + isMut: false; + isSigner: false; + docs: ['System program.']; + }, + { + name: 'payer'; + isMut: true; + isSigner: true; + docs: ['Payer']; + }, + ]; + args: []; + }, ]; accounts: [ { @@ -2222,7 +2339,7 @@ export type Amm = { }; export const IDL: Amm = { - version: '0.4.8', + version: '0.4.12', name: 'amm', docs: ['Program for AMM'], instructions: [ @@ -2266,18 +2383,6 @@ export const IDL: Amm = { isSigner: false, docs: ['Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.'], }, - { - name: 'aTokenVault', - isMut: true, - isSigner: false, - docs: ['Token vault account of vault A'], - }, - { - name: 'bTokenVault', - isMut: true, - isSigner: false, - docs: ['Token vault account of vault B'], - }, { name: 'aVaultLpMint', isMut: true, @@ -2356,6 +2461,16 @@ export const IDL: Amm = { isSigner: false, docs: ['Rent account.'], }, + { + name: 'mintMetadata', + isMut: true, + isSigner: false, + }, + { + name: 'metadataProgram', + isMut: false, + isSigner: false, + }, { name: 'vaultProgram', isMut: false, @@ -2388,14 +2503,6 @@ export const IDL: Amm = { defined: 'CurveType', }, }, - { - name: 'tokenAAmount', - type: 'u64', - }, - { - name: 'tokenBAmount', - type: 'u64', - }, ], }, { @@ -2524,6 +2631,16 @@ export const IDL: Amm = { isSigner: false, docs: ['Rent account.'], }, + { + name: 'mintMetadata', + isMut: true, + isSigner: false, + }, + { + name: 'metadataProgram', + isMut: false, + isSigner: false, + }, { name: 'vaultProgram', isMut: false, @@ -2692,6 +2809,16 @@ export const IDL: Amm = { isSigner: false, docs: ['Rent account.'], }, + { + name: 'mintMetadata', + isMut: true, + isSigner: false, + }, + { + name: 'metadataProgram', + isMut: false, + isSigner: false, + }, { name: 'vaultProgram', isMut: false, @@ -3442,37 +3569,6 @@ export const IDL: Amm = { ], args: [], }, - { - name: 'setAdminFeeAccount', - docs: ['Update fee token account of the pool admin.'], - accounts: [ - { - name: 'pool', - isMut: true, - isSigner: false, - docs: ['Pool account (PDA)'], - }, - { - name: 'newAdminTokenAFee', - isMut: true, - isSigner: false, - docs: ['New admin fee token account for pool token A. Used to receive trading fee.'], - }, - { - name: 'newAdminTokenBFee', - isMut: true, - isSigner: false, - docs: ['New admin fee token account for pool token B. Used to receive trading fee.'], - }, - { - name: 'admin', - isMut: false, - isSigner: true, - docs: ['Admin account. Must be owner of the pool.'], - }, - ], - args: [], - }, { name: 'getPoolInfo', docs: ['Get the general information of the pool.'], @@ -3652,6 +3748,144 @@ export const IDL: Amm = { }, ], }, + { + name: 'migrateFeeAccount', + docs: ['Migrate old token fee owner to PDA'], + accounts: [ + { + name: 'pool', + isMut: true, + isSigner: false, + docs: ['Pool account'], + }, + { + name: 'aVaultLp', + isMut: false, + isSigner: false, + docs: ['A vault LP token account of the pool.'], + }, + { + name: 'adminTokenAFee', + isMut: true, + isSigner: false, + docs: ['Admin fee token account for token A. Used to receive trading fee.'], + }, + { + name: 'adminTokenBFee', + isMut: true, + isSigner: false, + docs: ['Admin fee token account for token B. Used to receive trading fee.'], + }, + { + name: 'tokenAMint', + isMut: false, + isSigner: false, + docs: ['Token A mint'], + }, + { + name: 'tokenBMint', + isMut: false, + isSigner: false, + docs: ['Token B mint'], + }, + { + name: 'newAdminTokenAFee', + isMut: true, + isSigner: false, + docs: ['Token fee account. Controlled by pool a_vault_lp PDA.'], + }, + { + name: 'newAdminTokenBFee', + isMut: true, + isSigner: false, + docs: ['Token fee account. Controlled by pool a_vault_lp PDA.'], + }, + { + name: 'admin', + isMut: true, + isSigner: true, + docs: ['Admin account. Must be owner of the pool.'], + }, + { + name: 'treasuryTokenAFee', + isMut: true, + isSigner: false, + docs: ['Treasury token a fee ATA.'], + }, + { + name: 'treasuryTokenBFee', + isMut: true, + isSigner: false, + docs: ['Treasury token b fee ATA.'], + }, + { + name: 'treasury', + isMut: false, + isSigner: true, + docs: ['Treasury signer'], + }, + { + name: 'tokenProgram', + isMut: false, + isSigner: false, + docs: ['Token program.'], + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + docs: ['System program.'], + }, + ], + args: [], + }, + { + name: 'createMintMetadata', + docs: ['Create mint metadata account for old pools'], + accounts: [ + { + name: 'pool', + isMut: false, + isSigner: false, + docs: ['Pool account'], + }, + { + name: 'lpMint', + isMut: false, + isSigner: false, + docs: ['LP mint account of the pool'], + }, + { + name: 'aVaultLp', + isMut: false, + isSigner: false, + docs: ['Vault A LP account of the pool'], + }, + { + name: 'mintMetadata', + isMut: true, + isSigner: false, + }, + { + name: 'metadataProgram', + isMut: false, + isSigner: false, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + docs: ['System program.'], + }, + { + name: 'payer', + isMut: true, + isSigner: true, + docs: ['Payer'], + }, + ], + args: [], + }, ], accounts: [ { diff --git a/ts-client/src/amm/index.ts b/ts-client/src/amm/index.ts index af8eb2c6..23c9b973 100644 --- a/ts-client/src/amm/index.ts +++ b/ts-client/src/amm/index.ts @@ -34,7 +34,7 @@ import { VaultProgram, WithdrawQuote, } from './types'; -import { ERROR, SEEDS, UNLOCK_AMOUNT_BUFFER, FEE_OWNER } from './constants'; +import { ERROR, SEEDS, UNLOCK_AMOUNT_BUFFER, FEE_OWNER, METAPLEX_PROGRAM } from './constants'; import { StableSwap, SwapCurve, TradeDirection } from './curve'; import { ConstantProductSwap } from './curve/constant-product'; import { @@ -55,6 +55,7 @@ import { generateCurveType, derivePoolAddress, chunkedFetchMultiplePoolAccount, + deriveMintMetadata, } from './utils'; type Opt = { @@ -253,6 +254,8 @@ export default class AmmImpl implements AmmImplementation { preInstructions = preInstructions.concat(wrapSOLInstruction(payer, payerTokenB, BigInt(tokenBAmount.toString()))); } + const [mintMetadata, _mintMetadataBump] = deriveMintMetadata(lpMint); + const createPermissionlessPoolTx = await ammProgram.methods .initializePermissionlessPoolWithFeeTier(curveType, tradeFeeBps, tokenAAmount, tokenBAmount) .accounts({ @@ -273,6 +276,8 @@ export default class AmmImpl implements AmmImplementation { payerPoolLp, aTokenVault, bTokenVault, + mintMetadata, + metadataProgram: METAPLEX_PROGRAM, feeOwner: FEE_OWNER, payer, rent: SYSVAR_RENT_PUBKEY, diff --git a/ts-client/src/amm/utils.ts b/ts-client/src/amm/utils.ts index 30eae345..bb3256bc 100644 --- a/ts-client/src/amm/utils.ts +++ b/ts-client/src/amm/utils.ts @@ -36,6 +36,7 @@ import { PERMISSIONLESS_AMP, STABLE_SWAP_DEFAULT_TRADE_FEE_BPS, CONSTANT_PRODUCT_DEFAULT_TRADE_FEE_BPS, + METAPLEX_PROGRAM, } from './constants'; import { ConstantProductSwap, StableSwap, SwapCurve, TradeDirection } from './curve'; import { @@ -563,6 +564,13 @@ export async function getTokensMintFromPoolAddress( }; } +export function deriveMintMetadata(lpMint: PublicKey) { + return PublicKey.findProgramAddressSync( + [Buffer.from('metadata'), METAPLEX_PROGRAM.toBuffer(), lpMint.toBuffer()], + METAPLEX_PROGRAM, + ); +} + export function derivePoolAddress( connection: Connection, tokenInfoA: TokenInfo, From 6d544e7c4d73ed2583de75d7e7ca7af1c3796cbe Mon Sep 17 00:00:00 2001 From: McSam Date: Wed, 10 Jan 2024 16:22:29 +0800 Subject: [PATCH 2/2] bump: version --- ts-client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts-client/package.json b/ts-client/package.json index 0734ac5d..a2ec33cc 100644 --- a/ts-client/package.json +++ b/ts-client/package.json @@ -1,6 +1,6 @@ { "name": "@mercurial-finance/dynamic-amm-sdk", - "version": "0.4.18", + "version": "0.4.19", "description": "Mercurial Vaults SDK is a typescript library that allows you to interact with Mercurial v2's AMM.", "main": "dist/cjs/index.js", "module": "dist/esm/index.js",