diff --git a/CHANGELOG.md b/CHANGELOG.md index 85de7c4..5c9c0d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Security +## @mercurial-finance/dynamic-amm-sdk [1.1.12] - PR[#173](https://github.com/mercurial-finance/mercurial-dynamic-amm-sdk/pull/173) + +### Added + +- New function `swapAndStakeForFee` + ## @mercurial-finance/dynamic-amm-sdk [1.1.11] - PR[#170](https://github.com/mercurial-finance/mercurial-dynamic-amm-sdk/pull/170) ### Fixed diff --git a/ts-client/package.json b/ts-client/package.json index 131ec6c..8cef683 100644 --- a/ts-client/package.json +++ b/ts-client/package.json @@ -1,6 +1,6 @@ { "name": "@mercurial-finance/dynamic-amm-sdk", - "version": "1.1.11", + "version": "1.1.12", "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", diff --git a/ts-client/src/amm/index.ts b/ts-client/src/amm/index.ts index 83d04ad..546d48c 100644 --- a/ts-client/src/amm/index.ts +++ b/ts-client/src/amm/index.ts @@ -1025,7 +1025,7 @@ export default class AmmImpl implements AmmImplementation { const preInstructions: TransactionInstruction[] = []; const initFeeVaultParams = opt?.feeVault ? { ...opt.feeVault, padding: new Array(64).fill(0) } : undefined; - + const createFeeVaultIxs = await StakeForFee.createFeeVaultInstructions( connection, poolPubkey, @@ -1987,6 +1987,97 @@ export default class AmmImpl implements AmmImplementation { }).add(swapTx); } + /** + * `swap` is a function that takes in a `PublicKey` of the owner, a `PublicKey` of the input token + * mint, an `BN` of the input amount of lamports, and an `BN` of the output amount of lamports. It + * returns a `Promise` of the swap transaction + * @param {PublicKey} owner - The public key of the user who is swapping + * @param {PublicKey} inTokenMint - The mint of the token you're swapping from. + * @param {BN} inAmountLamport - The amount of the input token you want to swap. + * @param {BN} outAmountLamport - The minimum amount of the output token you want to receive. + * @param {PublicKey} [referralOwner] - The referrer wallet will receive the host fee, fee will be transferred to ATA of referrer wallet. + * @returns A transaction object + */ + public async swapAndStakeForFee( + owner: PublicKey, + inTokenMint: PublicKey, + inAmountLamport: BN, + outAmountLamport: BN, + stakeForFee: StakeForFee, + ): Promise { + const resultTxs: Transaction[] = []; + const [sourceToken, destinationToken] = this.tokenAMint.address.equals(inTokenMint) + ? [this.poolState.tokenAMint, this.poolState.tokenBMint] + : [this.poolState.tokenBMint, this.poolState.tokenAMint]; + + const protocolTokenFee = this.tokenAMint.address.equals(inTokenMint) + ? this.poolState.protocolTokenAFee + : this.poolState.protocolTokenBFee; + + let preInstructions: Array = []; + const [[userSourceToken, createUserSourceIx], [userDestinationToken, createUserDestinationIx]] = + await this.createATAPreInstructions(owner, [sourceToken, destinationToken]); + + createUserSourceIx && preInstructions.push(createUserSourceIx); + createUserDestinationIx && preInstructions.push(createUserDestinationIx); + + if (sourceToken.equals(NATIVE_MINT)) { + preInstructions = preInstructions.concat( + wrapSOLInstruction(owner, userSourceToken, BigInt(inAmountLamport.toString())), + ); + } + + const postInstructions: Array = []; + if (NATIVE_MINT.equals(destinationToken)) { + const unwrapSOLIx = await unwrapSOLInstruction(owner); + unwrapSOLIx && postInstructions.push(unwrapSOLIx); + } + + const remainingAccounts = this.swapCurve.getRemainingAccounts(); + + const swapTx = await this.program.methods + .swap(inAmountLamport, outAmountLamport) + .accounts({ + aTokenVault: this.vaultA.vaultState.tokenVault, + bTokenVault: this.vaultB.vaultState.tokenVault, + aVault: this.poolState.aVault, + bVault: this.poolState.bVault, + aVaultLp: this.poolState.aVaultLp, + bVaultLp: this.poolState.bVaultLp, + aVaultLpMint: this.vaultA.vaultState.lpMint, + bVaultLpMint: this.vaultB.vaultState.lpMint, + userSourceToken, + userDestinationToken, + user: owner, + protocolTokenFee, + pool: this.address, + tokenProgram: TOKEN_PROGRAM_ID, + vaultProgram: this.vaultProgram.programId, + }) + .remainingAccounts(remainingAccounts) + .preInstructions(preInstructions) + .postInstructions(postInstructions) + .transaction(); + + resultTxs.push( + new Transaction({ + feePayer: owner, + ...(await this.program.provider.connection.getLatestBlockhash(this.program.provider.connection.commitment)), + }).add(swapTx), + ); + + const stakeTx = await stakeForFee.stake(outAmountLamport, owner); + + resultTxs.push( + new Transaction({ + feePayer: owner, + ...(await this.program.provider.connection.getLatestBlockhash(this.program.provider.connection.commitment)), + }).add(stakeTx), + ); + + return resultTxs; + } + /** * `getDepositQuote` is a function that takes in a tokenAInAmount, tokenBInAmount, balance, and * slippage, and returns a poolTokenAmountOut, tokenAInAmount, and tokenBInAmount. `tokenAInAmount` or `tokenBAmount`