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

fix: include slippage for swaps #18

Merged
merged 2 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/mira/addLiquidity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}

Expand All @@ -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) {
Expand All @@ -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());

Expand Down
43 changes: 39 additions & 4 deletions src/mira/swap.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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();

Expand Down Expand Up @@ -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,
{
Expand All @@ -89,4 +125,3 @@ export const swapExactInput = async ({

return `Successfully swapped ${amount} ${fromSymbol} for ${toSymbol}. Explorer link: ${getTxExplorerUrl(id)}`;
};

8 changes: 4 additions & 4 deletions src/swaylend/borrow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
26 changes: 13 additions & 13 deletions src/swaylend/supply.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)}`;
};
11 changes: 9 additions & 2 deletions src/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +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%)'),
}),
});

Expand Down Expand Up @@ -52,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%)'),
}),
});

Expand All @@ -61,5 +68,5 @@ export const tools = [
swapExactInputTool,
supplyCollateralTool,
borrowAssetTool,
addLiquidityTool
addLiquidityTool,
];
28 changes: 14 additions & 14 deletions test/add_liquidity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
),
);
},
);
16 changes: 10 additions & 6 deletions test/execute.test.ts
Original file line number Diff line number Diff line change
@@ -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,
},
);
18 changes: 15 additions & 3 deletions test/swap.test.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
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'));
},
);
Loading