From 489c1981fce416d20be8367852bd49459fcc13d0 Mon Sep 17 00:00:00 2001 From: PraneshASP Date: Mon, 23 Dec 2024 20:57:09 +0530 Subject: [PATCH 1/2] fix: include slippage for swaps --- src/mira/swap.ts | 43 +++++++++++++++++++++++++++++++++++++++---- src/tools.ts | 1 + test/swap.test.ts | 24 ++++++++++++++++++++---- 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/mira/swap.ts b/src/mira/swap.ts index f62bf86..0caf07e 100644 --- a/src/mira/swap.ts +++ b/src/mira/swap.ts @@ -1,6 +1,6 @@ import { bn, Provider } from 'fuels'; import { getAllVerifiedFuelAssets } from '../utils/assets.js'; -import { buildPoolId, MiraAmm } from 'mira-dex-ts'; +import { buildPoolId, MiraAmm, ReadonlyMiraAmm } from 'mira-dex-ts'; import { setupWallet } from '../utils/setup.js'; import { getTxExplorerUrl } from '../utils/explorer.js'; @@ -13,16 +13,19 @@ export type SwapExactInputParams = { amount: string; fromSymbol: string; toSymbol: string; + slippage?: number; }; export const swapExactInput = async ({ amount, fromSymbol, toSymbol, + slippage = 0.01, }: { amount: string; fromSymbol: string; toSymbol: string; + slippage?: number; }) => { const assets = await getAllVerifiedFuelAssets(); @@ -63,18 +66,51 @@ export const swapExactInput = async ({ const amountInWei = bn.parseUnits(amount, fromAssetDecimals); - const poolId = buildPoolId(fromAssetId, toAssetId, true); + let isStable = + fromAsset.symbol.includes('USD') && toAsset.symbol.includes('USD'); + + const poolId = buildPoolId(fromAssetId, toAssetId, isStable); const miraAmm = new MiraAmm(wallet); const deadline = await futureDeadline(provider); + const miraAmmReader = new ReadonlyMiraAmm(provider); + + // Calculate the expected output amount + const result = await miraAmmReader.getAmountsOut( + { bits: fromAssetId }, + amountInWei, + [poolId], + ); + + if (!result || result.length === 0 || !result[0] || result[0].length < 2) { + throw new Error('Failed to calculate output amount'); + } + + let amountOutWei; + if (result[1] && result[1][0].bits === toAssetId) { + amountOutWei = result[1][1]; + } else if (result[0][0].bits === toAssetId) { + amountOutWei = result[0][1]; + } + + if (!amountOutWei) { + throw new Error('Failed to calculate output amount'); + } + + console.log('Amount In (Wei):', amountInWei.toString()); + console.log('Estimated Amount Out (Wei):', amountOutWei.toString()); + + const minAmountOut = amountOutWei + .mul(bn(100 - Math.floor(slippage * 100))) + .div(bn(100)); const req = await miraAmm.swapExactInput( amountInWei, { bits: fromAssetId, }, - 0, + minAmountOut, [poolId], deadline, { @@ -89,4 +125,3 @@ export const swapExactInput = async ({ return `Successfully swapped ${amount} ${fromSymbol} for ${toSymbol}. Explorer link: ${getTxExplorerUrl(id)}`; }; - diff --git a/src/tools.ts b/src/tools.ts index 334bfa8..62259d7 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -25,6 +25,7 @@ export const swapExactInputTool = tool(swapExactInput, { .string() .describe('The asset symbol to swap from. eg. USDC, ETH'), toSymbol: z.string().describe('The asset symbol to swap to. eg. USDC, ETH'), + slippage: z.number().optional().describe('Slippage tolerance (default: 0.01 for 1%)'), }), }); diff --git a/test/swap.test.ts b/test/swap.test.ts index b895103..0f90acc 100644 --- a/test/swap.test.ts +++ b/test/swap.test.ts @@ -1,18 +1,34 @@ import { test } from 'vitest'; import { swapExactInput } from '../src/mira/swap.js'; +import { FuelAgent } from '../src/FuelAgent.js'; test( 'swap exact input', + { + timeout: 30000, + }, async () => { console.log( await swapExactInput({ - amount: '5', - fromSymbol: 'USDT', + amount: '1', + fromSymbol: 'USDC', toSymbol: 'ETH', }), ); }, +); + +test( + 'add 0.1 USDC liquidity to USDC/USDT pool', { - timeout: 30000, + timeout: 60000, }, -); + async () => { + const agent = new FuelAgent(); + console.log( + await agent.execute( + 'Swap 0.1 USDC to ETH with 5% slippage', + ), + ); + }, +); \ No newline at end of file From aa9654805c52351608897a5c65c8806c572bc10f Mon Sep 17 00:00:00 2001 From: PraneshASP Date: Mon, 23 Dec 2024 20:59:28 +0530 Subject: [PATCH 2/2] chore: fmt --- src/mira/addLiquidity.ts | 17 ++++++++++++----- src/swaylend/borrow.ts | 8 ++++---- src/swaylend/supply.ts | 26 +++++++++++++------------- src/tools.ts | 12 +++++++++--- test/add_liquidity.test.ts | 28 ++++++++++++++-------------- test/execute.test.ts | 16 ++++++++++------ test/swap.test.ts | 10 +++------- 7 files changed, 65 insertions(+), 52 deletions(-) diff --git a/src/mira/addLiquidity.ts b/src/mira/addLiquidity.ts index bf9bb77..c83f1c0 100644 --- a/src/mira/addLiquidity.ts +++ b/src/mira/addLiquidity.ts @@ -41,7 +41,10 @@ export const addLiquidity = async ({ const asset0Decimals = asset0.decimals; const asset1Decimals = asset1.decimals; - if (typeof asset0Decimals !== 'number' || typeof asset1Decimals !== 'number') { + if ( + typeof asset0Decimals !== 'number' || + typeof asset1Decimals !== 'number' + ) { throw new Error('Invalid asset decimals'); } @@ -59,7 +62,7 @@ export const addLiquidity = async ({ const result = await miraAmmReader.getAmountsOut( { bits: asset0Id }, amount0InWei, - [poolId] + [poolId], ); if (!result || result.length === 0 || !result[0] || result[0].length < 2) { @@ -81,9 +84,13 @@ export const addLiquidity = async ({ console.log('Estimated Amount1 (Wei):', amount1InWei.toString()); // Calculate minimum amounts with slippage - const minAmount0 = amount0InWei.mul(bn(100 - Math.floor(slippage * 100))).div(bn(100)); - const minAmount1 = amount1InWei.mul(bn(100 - Math.floor(slippage * 100))).div(bn(100)); - + const minAmount0 = amount0InWei + .mul(bn(100 - Math.floor(slippage * 100))) + .div(bn(100)); + const minAmount1 = amount1InWei + .mul(bn(100 - Math.floor(slippage * 100))) + .div(bn(100)); + console.log('Min Amount0 (Wei):', minAmount0.toString()); console.log('Min Amount1 (Wei):', minAmount1.toString()); diff --git a/src/swaylend/borrow.ts b/src/swaylend/borrow.ts index 0857c08..2a191ce 100644 --- a/src/swaylend/borrow.ts +++ b/src/swaylend/borrow.ts @@ -59,12 +59,12 @@ export const borrowAsset = async ({ amount }: BorrowAssetParams) => { '0x1c86fdd9e0e7bc0d2ae1bf6817ef4834ffa7247655701ee1b031b52a24c523da', wallet, ); - + // fetch oracle fee const { value: fee } = await marketContract.functions - .update_fee(updateData) - .addContracts([pythContract]) - .get(); + .update_fee(updateData) + .addContracts([pythContract]) + .get(); // before initiating the borrow make sure the wallet has some small amount of USDC for the oracle fee const priceUpdateData: PriceDataUpdateInput = { diff --git a/src/swaylend/supply.ts b/src/swaylend/supply.ts index 4509bc0..a2fdb61 100644 --- a/src/swaylend/supply.ts +++ b/src/swaylend/supply.ts @@ -25,17 +25,17 @@ export const supplyCollateral = async ({ const weiAmount = bn.parseUnits(amount, asset?.decimals); - const tx = await marketContract.functions - .supply_collateral() - .callParams({ - forward: { - assetId: assetId, - amount: weiAmount, - } as any, - }) - .call(); - - const { transactionId } = await tx.waitForResult(); - - return `Successfully supplied ${amount} ${symbol} as collateral. Explorer link: ${getTxExplorerUrl(transactionId)}`; + const tx = await marketContract.functions + .supply_collateral() + .callParams({ + forward: { + assetId: assetId, + amount: weiAmount, + } as any, + }) + .call(); + + const { transactionId } = await tx.waitForResult(); + + return `Successfully supplied ${amount} ${symbol} as collateral. Explorer link: ${getTxExplorerUrl(transactionId)}`; }; diff --git a/src/tools.ts b/src/tools.ts index 62259d7..39683a6 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -25,7 +25,10 @@ export const swapExactInputTool = tool(swapExactInput, { .string() .describe('The asset symbol to swap from. eg. USDC, ETH'), toSymbol: z.string().describe('The asset symbol to swap to. eg. USDC, ETH'), - slippage: z.number().optional().describe('Slippage tolerance (default: 0.01 for 1%)'), + slippage: z + .number() + .optional() + .describe('Slippage tolerance (default: 0.01 for 1%)'), }), }); @@ -53,7 +56,10 @@ export const addLiquidityTool = tool(addLiquidity, { amount0: z.string().describe('The amount of the first asset to add'), asset0Symbol: z.string().describe('The symbol of the first asset'), asset1Symbol: z.string().describe('The symbol of the second asset'), - slippage: z.number().optional().describe('Slippage tolerance (default: 0.01 for 1%)'), + slippage: z + .number() + .optional() + .describe('Slippage tolerance (default: 0.01 for 1%)'), }), }); @@ -62,5 +68,5 @@ export const tools = [ swapExactInputTool, supplyCollateralTool, borrowAssetTool, - addLiquidityTool + addLiquidityTool, ]; diff --git a/test/add_liquidity.test.ts b/test/add_liquidity.test.ts index 41e9066..399fc5b 100644 --- a/test/add_liquidity.test.ts +++ b/test/add_liquidity.test.ts @@ -15,20 +15,20 @@ test( asset1Symbol: 'USDT', }), ); - }, + }, ); test( - 'add 0.1 USDC liquidity to USDC/USDT pool', - { - timeout: 60000, - }, - async () => { - const agent = new FuelAgent(); - console.log( - await agent.execute( - 'Add liquidity into USDC/USDT pool for 0.1 USDC with 5% slippage', - ), - ); - }, - ); + 'add 0.1 USDC liquidity to USDC/USDT pool', + { + timeout: 60000, + }, + async () => { + const agent = new FuelAgent(); + console.log( + await agent.execute( + 'Add liquidity into USDC/USDT pool for 0.1 USDC with 5% slippage', + ), + ); + }, +); diff --git a/test/execute.test.ts b/test/execute.test.ts index 3576219..bff0142 100644 --- a/test/execute.test.ts +++ b/test/execute.test.ts @@ -1,9 +1,13 @@ import { test } from 'vitest'; import { FuelAgent } from '../dist/index.js'; -test('execute swap', async () => { - const agent = new FuelAgent(); - console.log(await agent.execute('swap 5 usdc for eth')); -}, { - timeout: 60000, -}); +test( + 'execute swap', + async () => { + const agent = new FuelAgent(); + console.log(await agent.execute('swap 5 usdc for eth')); + }, + { + timeout: 60000, + }, +); diff --git a/test/swap.test.ts b/test/swap.test.ts index 0f90acc..371d8fb 100644 --- a/test/swap.test.ts +++ b/test/swap.test.ts @@ -21,14 +21,10 @@ test( test( 'add 0.1 USDC liquidity to USDC/USDT pool', { - timeout: 60000, + timeout: 60000, }, async () => { const agent = new FuelAgent(); - console.log( - await agent.execute( - 'Swap 0.1 USDC to ETH with 5% slippage', - ), - ); + console.log(await agent.execute('Swap 0.1 USDC to ETH with 5% slippage')); }, -); \ No newline at end of file +);