From 9124732f9373fb1f2ec1553a458b9c1712ef6bd1 Mon Sep 17 00:00:00 2001 From: MGrgr Date: Thu, 11 Jan 2024 22:50:06 +0300 Subject: [PATCH 1/3] feat: create token metadata --- src/components/CreatePool/CreateSwapCard.vue | 35 +- src/hooks/create-swap-pool.ts | 359 +++++++++++++++---- 2 files changed, 321 insertions(+), 73 deletions(-) diff --git a/src/components/CreatePool/CreateSwapCard.vue b/src/components/CreatePool/CreateSwapCard.vue index 7a3b2b3..1bc32f8 100644 --- a/src/components/CreatePool/CreateSwapCard.vue +++ b/src/components/CreatePool/CreateSwapCard.vue @@ -3,7 +3,16 @@ import { Keypair, PublicKey } from '@solana/web3.js' import type { TokenData } from '@/config' -const { state, createTokenSwap, createPoolAccounts, generateSwapKeypair, createPoolMint } = useCreateSwap() +const { + state, + createTokenSwap, + createPoolAccounts, + generateSwapKeypair, + createPoolMint, + metadataState, + createMetadataLPT, + updateMetadataLPT, +} = useCreateSwap() const { handleSearchToken, tokens } = useToken() const userStore = useUserStore() @@ -16,6 +25,7 @@ function setToken(field: 'tokenA' | 'tokenB', t: TokenData) { } const expandedTokenSwap = ref(false) +const expandedPoolMint = ref(false) const tokenSwapSecret = ref('') function setTokenSwap() { if (tokenSwapSecret.value) { @@ -129,7 +139,7 @@ function setPoolMint() { Copy Pool Mint public key @@ -140,8 +150,25 @@ function setPoolMint() { +
+
LP token metadata
+ + + + + +
+ + Update LP token metadata + + + Create LP token metadata + +
+
+
- + Create Pool token accounts
@@ -153,7 +180,7 @@ function setPoolMint() {
- + Create Pool
diff --git a/src/hooks/create-swap-pool.ts b/src/hooks/create-swap-pool.ts index 8c522ed..c28cad7 100644 --- a/src/hooks/create-swap-pool.ts +++ b/src/hooks/create-swap-pool.ts @@ -1,6 +1,8 @@ import { useAnchorWallet, useWallet } from 'solana-wallets-vue' import { Keypair, PublicKey, Transaction } from '@solana/web3.js' import { CurveType } from '@albus-finance/swap-sdk' +import type { DataV2 } from '@metaplex-foundation/mpl-token-metadata' +import { PROGRAM_ID, createCreateMetadataAccountV3Instruction, createUpdateMetadataAccountV2Instruction } from '@metaplex-foundation/mpl-token-metadata' import { getCreateMintTx, getOrInitAssociatedTokenAddress, sendTransaction } from '@/utils' import { LP_DECIMALS, type PolicyItem, type TokenData } from '@/config' @@ -33,6 +35,13 @@ export function useCreateSwap() { swapTokenB: undefined, }) + const metadataState = reactive({ + name: '', + symbol: '', + metadataUrl: '', + isMutable: false, + }) + async function generateSwapKeypair() { if (!publicKey.value || !wallet.value) { return @@ -48,29 +57,56 @@ export function useCreateSwap() { } const swapAuthority = swapStore.swapClient.swapAuthority(state.tokenSwap.publicKey) const tx = new Transaction() - const poolMint = await getCreateMintTx(connectionStore.connection, tx, publicKey.value, swapAuthority, LP_DECIMALS) - console.log('[create swap] poolMint = ', poolMint.publicKey.toBase58()) - if (tx.instructions.length > 0) { - await monitorTransaction( - sendTransaction(connectionStore.connection, wallet.value!, tx.instructions, [poolMint]), - { - onSuccess: () => { - state.poolMint = poolMint.publicKey - notify({ - type: 'positive', - message: 'Pool mint created successfully.', - }) + + state.creating = true + try { + const poolMint = await getCreateMintTx(connectionStore.connection, tx, publicKey.value, swapAuthority, LP_DECIMALS) + console.log('[create swap] poolMint = ', poolMint.publicKey.toBase58()) + if (tx.instructions.length > 0) { + await monitorTransaction( + sendTransaction(connectionStore.connection, wallet.value!, tx.instructions, [poolMint]), + { + onSuccess: () => { + state.poolMint = poolMint.publicKey + notify({ + type: 'positive', + message: 'Pool mint created successfully.', + }) + }, }, - }, - ) - } else { - state.poolMint = poolMint.publicKey + ) + } else { + state.poolMint = poolMint.publicKey + } + } catch (e) { + console.error(e) + notify({ + type: 'negative', + message: `${e}`, + }) + } finally { + state.creating = false } } async function createPoolAccounts() { - if (!publicKey.value || !wallet.value || !state.tokenSwap || !state.poolMint) { - return + if (!publicKey.value || !wallet.value) { + return notify({ + type: 'negative', + message: 'Connect wallet', + }) + } + if (!state.tokenSwap) { + return notify({ + type: 'negative', + message: 'Define tokenSwap', + }) + } + if (!state.poolMint) { + return notify({ + type: 'negative', + message: 'Define pool mint', + }) } if (!state.tokenA || !state.tokenB) { return notify({ @@ -80,32 +116,44 @@ export function useCreateSwap() { } const swapAuthority = swapStore.swapClient.swapAuthority(state.tokenSwap.publicKey) const tx = new Transaction() - const poolFeeAccount = await getOrInitAssociatedTokenAddress(connectionStore.connection, tx, state.poolMint, publicKey.value) - const swapTokenA = await getOrInitAssociatedTokenAddress(connectionStore.connection, tx, new PublicKey(state.tokenA.mint), swapAuthority, publicKey.value, true) - const swapTokenB = await getOrInitAssociatedTokenAddress(connectionStore.connection, tx, new PublicKey(state.tokenB.mint), swapAuthority, publicKey.value, true) - console.log('[create swap] poolFeeAccount = ', poolFeeAccount.toBase58()) - console.log('[create swap] swapTokenA = ', swapTokenA.toBase58()) - console.log('[create swap] swapTokenB = ', swapTokenB.toBase58()) - if (tx.instructions.length > 0) { - await monitorTransaction( - sendTransaction(connectionStore.connection, wallet.value!, tx.instructions), - { - commitment: 'finalized', - onSuccess: () => { - state.poolFeeAccount = poolFeeAccount - state.swapTokenA = swapTokenA - state.swapTokenB = swapTokenB - notify({ - type: 'positive', - message: 'Pool accounts created successfully.', - }) + + state.creating = true + try { + const poolFeeAccount = await getOrInitAssociatedTokenAddress(connectionStore.connection, tx, state.poolMint, publicKey.value) + const swapTokenA = await getOrInitAssociatedTokenAddress(connectionStore.connection, tx, new PublicKey(state.tokenA.mint), swapAuthority, publicKey.value, true) + const swapTokenB = await getOrInitAssociatedTokenAddress(connectionStore.connection, tx, new PublicKey(state.tokenB.mint), swapAuthority, publicKey.value, true) + console.log('[create swap] poolFeeAccount = ', poolFeeAccount.toBase58()) + console.log('[create swap] swapTokenA = ', swapTokenA.toBase58()) + console.log('[create swap] swapTokenB = ', swapTokenB.toBase58()) + if (tx.instructions.length > 0) { + await monitorTransaction( + sendTransaction(connectionStore.connection, wallet.value!, tx.instructions), + { + commitment: 'finalized', + onSuccess: () => { + state.poolFeeAccount = poolFeeAccount + state.swapTokenA = swapTokenA + state.swapTokenB = swapTokenB + notify({ + type: 'positive', + message: 'Pool accounts created successfully.', + }) + }, }, - }, - ) - } else { - state.poolFeeAccount = poolFeeAccount - state.swapTokenA = swapTokenA - state.swapTokenB = swapTokenB + ) + } else { + state.poolFeeAccount = poolFeeAccount + state.swapTokenA = swapTokenA + state.swapTokenB = swapTokenB + } + } catch (e) { + console.error(e) + notify({ + type: 'negative', + message: `${e}`, + }) + } finally { + state.creating = false } /** * transfer tokens to pool token accounts @@ -157,32 +205,191 @@ export function useCreateSwap() { hostFeeDenominator: state.hostFeeDenominator, }, }) - const tokenSwapRes = await swapStore.swapClient.createTokenSwap({ - tokenSwap: state.tokenSwap, - poolMint: state.poolMint, - poolFee: state.poolFeeAccount, - destination: state.poolFeeAccount, - tokenA: state.swapTokenA, - tokenB: state.swapTokenB, - policy: state.policy.pubkey, - curveType: CurveType.ConstantProduct, - curveParameters: [], - fees: { - tradeFeeNumerator: state.tradeFeeNumerator, - tradeFeeDenominator: state.tradeFeeDenominator, - ownerTradeFeeNumerator: state.ownerTradeFeeNumerator, - ownerTradeFeeDenominator: state.ownerTradeFeeDenominator, - ownerWithdrawFeeNumerator: state.ownerWithdrawFeeNumerator, - ownerWithdrawFeeDenominator: state.ownerWithdrawFeeDenominator, - hostFeeNumerator: state.hostFeeNumerator, - hostFeeDenominator: state.hostFeeDenominator, - }, - }) - notify({ - type: 'positive', - message: `Swap Pool created successfully. ${state.tokenSwap?.publicKey.toBase58()}`, - }) - console.log('[create swap] tokenSwap result = ', tokenSwapRes) + + state.creating = true + try { + const tokenSwapRes = await swapStore.swapClient.createTokenSwap({ + tokenSwap: state.tokenSwap, + poolMint: state.poolMint, + poolFee: state.poolFeeAccount, + destination: state.poolFeeAccount, + tokenA: state.swapTokenA, + tokenB: state.swapTokenB, + policy: state.policy.pubkey, + curveType: CurveType.ConstantProduct, + curveParameters: [], + fees: { + tradeFeeNumerator: state.tradeFeeNumerator, + tradeFeeDenominator: state.tradeFeeDenominator, + ownerTradeFeeNumerator: state.ownerTradeFeeNumerator, + ownerTradeFeeDenominator: state.ownerTradeFeeDenominator, + ownerWithdrawFeeNumerator: state.ownerWithdrawFeeNumerator, + ownerWithdrawFeeDenominator: state.ownerWithdrawFeeDenominator, + hostFeeNumerator: state.hostFeeNumerator, + hostFeeDenominator: state.hostFeeDenominator, + }, + }) + notify({ + type: 'positive', + message: `Swap Pool created successfully. ${state.tokenSwap?.publicKey.toBase58()}`, + }) + console.log('[create swap] tokenSwap result = ', tokenSwapRes) + } catch (e) { + console.error(e) + notify({ + type: 'negative', + message: `${e}`, + }) + } finally { + state.creating = false + } + } + + async function createMetadataLPT() { + if (!publicKey.value || !wallet.value) { + return notify({ + type: 'negative', + message: 'Connect wallet', + }) + } + if (!state.poolMint) { + return notify({ + type: 'negative', + message: 'Define pool mint', + }) + } + + state.creating = true + try { + const createMetadataInstruction = createCreateMetadataAccountV3Instruction( + { + metadata: PublicKey.findProgramAddressSync( + [ + // eslint-disable-next-line n/prefer-global/buffer + Buffer.from('metadata'), + PROGRAM_ID.toBuffer(), + state.poolMint.toBuffer(), + ], + PROGRAM_ID, + )[0], + mint: state.poolMint, + mintAuthority: publicKey.value, + payer: publicKey.value, + updateAuthority: publicKey.value, + }, + { + createMetadataAccountArgsV3: { + data: { + name: metadataState.name, + symbol: metadataState.symbol, + uri: metadataState.metadataUrl, + creators: null, + sellerFeeBasisPoints: 0, + uses: null, + collection: null, + }, + isMutable: metadataState.isMutable, + collectionDetails: null, + }, + }, + ) + await monitorTransaction( + sendTransaction(connectionStore.connection, wallet.value!, [createMetadataInstruction]), + { + commitment: 'finalized', + onSuccess: () => { + notify({ + type: 'positive', + message: 'LP token metadata created', + }) + }, + }, + ) + } catch (e) { + console.error(e) + notify({ + type: 'negative', + message: `${e}`, + }) + } finally { + state.creating = false + } + } + + async function updateMetadataLPT() { + if (!publicKey.value || !wallet.value) { + return notify({ + type: 'negative', + message: 'Connect wallet', + }) + } + if (!state.poolMint) { + return notify({ + type: 'negative', + message: 'Define pool mint', + }) + } + + state.creating = true + try { + const mint = new PublicKey(state.poolMint) + + const metadataPDA = PublicKey.findProgramAddressSync( + [ + // eslint-disable-next-line n/prefer-global/buffer + Buffer.from('metadata'), + PROGRAM_ID.toBuffer(), + mint.toBuffer(), + ], + PROGRAM_ID, + )[0] + + const tokenMetadata = { + name: metadataState.name, + symbol: metadataState.symbol, + uri: metadataState.metadataUrl, + sellerFeeBasisPoints: 0, + creators: null, + collection: null, + uses: null, + } as DataV2 + + const updateMetadataInstruction = createUpdateMetadataAccountV2Instruction( + { + metadata: metadataPDA, + updateAuthority: publicKey.value, + }, + { + updateMetadataAccountArgsV2: { + data: tokenMetadata, + updateAuthority: publicKey.value, + primarySaleHappened: true, + isMutable: true, + }, + }, + ) + + await monitorTransaction( + sendTransaction(connectionStore.connection, wallet.value!, [updateMetadataInstruction]), + { + commitment: 'finalized', + onSuccess: () => { + notify({ + type: 'positive', + message: 'LP token metadata updated', + }) + }, + }, + ) + } catch (e) { + console.error(e) + notify({ + type: 'negative', + message: `${e}`, + }) + } finally { + state.creating = false + } } function reset() { @@ -197,15 +404,22 @@ export function useCreateSwap() { state.policy = undefined state.tokenA = undefined state.tokenB = undefined + + metadataState.name = '' + metadataState.symbol = '' + metadataState.metadataUrl = '' } return { state, + metadataState, reset, generateSwapKeypair, createPoolMint, createPoolAccounts, createTokenSwap, + createMetadataLPT, + updateMetadataLPT, } } @@ -229,3 +443,10 @@ interface CreateSwapState { swapTokenA: PublicKey | undefined swapTokenB: PublicKey | undefined } + +interface LPTMetadataState { + name: string + symbol: string + metadataUrl: string + isMutable: boolean +} From d501fba53628e7cd6687c75d5ef668dbff560b00 Mon Sep 17 00:00:00 2001 From: MGrgr Date: Fri, 12 Jan 2024 12:26:30 +0300 Subject: [PATCH 2/3] fix: card header fontsize --- src/assets/styles/components/_liquidity.scss | 4 ++-- src/assets/styles/components/_swap.scss | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/assets/styles/components/_liquidity.scss b/src/assets/styles/components/_liquidity.scss index 2589d06..833940b 100644 --- a/src/assets/styles/components/_liquidity.scss +++ b/src/assets/styles/components/_liquidity.scss @@ -11,8 +11,8 @@ font-family: $font-secondary; @media(min-width: $breakpoint-md) { - font-size: 23px; - line-height: 28px; + font-size: 16px; + line-height: 20px; } } } diff --git a/src/assets/styles/components/_swap.scss b/src/assets/styles/components/_swap.scss index 15215a7..6122bab 100644 --- a/src/assets/styles/components/_swap.scss +++ b/src/assets/styles/components/_swap.scss @@ -45,11 +45,11 @@ $swap-input-focused-color: rgba($secondary, 0.7) !important; height: 48px; padding: 0; background-color: $primary; - font-size: 23px; + font-size: 16px; text-transform: uppercase; font-family: $font-secondary; font-weight: 500; - line-height: 28px; + line-height: 20px; color: #ffffff; display: flex; align-items: center; From 67a189515d5bcec91513c974b8915e6c921211ff Mon Sep 17 00:00:00 2001 From: MGrgr Date: Fri, 12 Jan 2024 18:43:27 +0300 Subject: [PATCH 3/3] fix: create LP token with metadata --- src/components/CreatePool/CreateSwapCard.vue | 32 +-- src/hooks/create-swap-pool.ts | 217 ++++++------------- 2 files changed, 75 insertions(+), 174 deletions(-) diff --git a/src/components/CreatePool/CreateSwapCard.vue b/src/components/CreatePool/CreateSwapCard.vue index 1bc32f8..eb7ff2e 100644 --- a/src/components/CreatePool/CreateSwapCard.vue +++ b/src/components/CreatePool/CreateSwapCard.vue @@ -10,8 +10,6 @@ const { generateSwapKeypair, createPoolMint, metadataState, - createMetadataLPT, - updateMetadataLPT, } = useCreateSwap() const { handleSearchToken, tokens } = useToken() @@ -71,7 +69,7 @@ function setPoolMint() { option-value="mint" option-label="name" >