diff --git a/packages/keeper-bots/src/__mocks__/index.ts b/packages/keeper-bots/src/__mocks__/index.ts index f6aed07..b61f285 100644 --- a/packages/keeper-bots/src/__mocks__/index.ts +++ b/packages/keeper-bots/src/__mocks__/index.ts @@ -1,4 +1,4 @@ -import { CurrencyAmount, Percent, Token } from "@pancakeswap/sdk"; +import { CurrencyAmount, Fraction, Percent, Token } from "@pancakeswap/sdk"; import { RouteV3 } from "@uniswap/router-sdk"; import { Token as UniswapToken } from "@uniswap/sdk-core"; import { FeeAmount, Pool, Route as V3RouteSDK } from "@uniswap/v3-sdk"; @@ -113,11 +113,11 @@ export const mockTrade = { path: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c000cf6bb5389c92bdda8a3747ddb454cb7a64626c63" as const, inputToken: { address: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c" as const, - amount: 8904975230019520420n, + amount: new Fraction(8904975230019520420n, 1), }, outputToken: { address: "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63" as const, - amount: 517926942058379677423n, + amount: new Fraction(517926942058379677423n, 1), }, }; diff --git a/packages/keeper-bots/src/converter-bot/TokenConverter.test.ts b/packages/keeper-bots/src/converter-bot/TokenConverter.test.ts index 8a2188e..e98e24f 100644 --- a/packages/keeper-bots/src/converter-bot/TokenConverter.test.ts +++ b/packages/keeper-bots/src/converter-bot/TokenConverter.test.ts @@ -121,28 +121,53 @@ describe("Token Converter", () => { (tokenConverter.publicClient.simulateContract as jest.Mock).mockImplementation(() => ({ result: [1000000000000000000n, 1000000000000000000n], })); + const [trade, updatedAmountIn] = await tokenConverter.getBestTrade( + addresses.USDCPrimeConverter, + addresses.WBNB, + addresses.USDC, + 1000000000000000000000n, + ); - expect( - await tokenConverter.getBestTrade( - addresses.USDCPrimeConverter, - addresses.WBNB, - addresses.USDC, - 1000000000000000000000n, - ), - ).toEqual([ - { - inputToken: { + expect(trade.inputToken).toEqual({ + address: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + amount: { + currency: { address: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", - amount: "8", + chainId: 56, + decimals: 18, + isNative: false, + isToken: true, + name: undefined, + projectLink: undefined, + symbol: "WBNB", }, - outputToken: { + decimalScale: 1000000000000000000n, + denominator: 1n, + numerator: 8904975230019520420n, + }, + }); + expect(trade.outputToken).toEqual({ + address: "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63", + amount: { + currency: { address: "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63", - amount: "517", + chainId: 56, + decimals: 18, + isNative: false, + isToken: true, + name: undefined, + projectLink: undefined, + symbol: "XVS", }, - path: "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c630009c4bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + decimalScale: 1000000000000000000n, + denominator: 1n, + numerator: 517926942058379677423n, }, - [1000000000000000000n, 1000000000000000000n], - ]); + }); + expect(trade.path).toEqual( + "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c630009c4bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + ); + expect(updatedAmountIn).toEqual([1000000000000000000n, 1000000000000000000n]); }); test("should call getBestTrade again if price impact is high with lower amount", async () => { @@ -168,27 +193,53 @@ describe("Token Converter", () => { return new Percent(9n, 1000n); }); - expect( - await pancakeSwapProvider.getBestTrade( - addresses.USDCPrimeConverter, - addresses.WBNB, - addresses.USDC, - 1000000000000000000000n, - ), - ).toEqual([ - { - inputToken: { + const [trade, updatedAmountIn] = await pancakeSwapProvider.getBestTrade( + addresses.USDCPrimeConverter, + addresses.WBNB, + addresses.USDC, + 1000000000000000000000n, + ); + + expect(trade.inputToken).toEqual({ + address: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + amount: { + currency: { address: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", - amount: "8", + chainId: 56, + decimals: 18, + isNative: false, + isToken: true, + name: undefined, + projectLink: undefined, + symbol: "WBNB", }, - outputToken: { + decimalScale: 1000000000000000000n, + denominator: 1n, + numerator: 8904975230019520420n, + }, + }); + expect(trade.outputToken).toEqual({ + address: "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63", + amount: { + currency: { address: "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63", - amount: "517", + chainId: 56, + decimals: 18, + isNative: false, + isToken: true, + name: undefined, + projectLink: undefined, + symbol: "XVS", }, - path: "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c630009c4bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + decimalScale: 1000000000000000000n, + denominator: 1n, + numerator: 517926942058379677423n, }, - [1000000000000000000n, 1000000000000000000n], - ]); + }); + expect(trade.path).toEqual( + "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c630009c4bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + ); + expect(updatedAmountIn).toEqual([1000000000000000000n, 1000000000000000000n]); expect(pancakeSwapProviderMock).toHaveBeenNthCalledWith( 3, @@ -840,28 +891,54 @@ describe("Token Converter", () => { result: [1000000000000000000n, 1000000000000000000n], })); - expect( - await tokenConverter.prepareConversion( - addresses.USDCPrimeConverter, - addresses.WBNB, - addresses.USDC, - 1000000000000000000000n, - ), - ).toEqual({ - trade: { - inputToken: { - amount: "8", + const arbitrageArgs = await tokenConverter.prepareConversion( + addresses.USDCPrimeConverter, + addresses.WBNB, + addresses.USDC, + 1000000000000000000000n, + ); + + expect(arbitrageArgs?.amount).toEqual(1000000000000000000n); + expect(arbitrageArgs?.trade.inputToken).toEqual({ + address: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + amount: { + currency: { address: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + chainId: 56, + decimals: 18, + isNative: false, + isToken: true, + name: undefined, + projectLink: undefined, + symbol: "WBNB", }, - outputToken: { - amount: "517", + decimalScale: 1000000000000000000n, + denominator: 1n, + numerator: 8904975230019520420n, + }, + }); + expect(arbitrageArgs?.trade.outputToken).toEqual({ + address: "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63", + amount: { + currency: { address: "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63", + chainId: 56, + decimals: 18, + isNative: false, + isToken: true, + name: undefined, + projectLink: undefined, + symbol: "XVS", }, - path: "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c630009c4bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + decimalScale: 1000000000000000000n, + denominator: 1n, + numerator: 517926942058379677423n, }, - amount: 1000000000000000000n, - minIncome: 999999999999999992n, }); + expect(arbitrageArgs?.trade.path).toEqual( + "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c630009c4bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + ); + expect(arbitrageArgs?.minIncome).toEqual(-7904975230019520420n); expect(subscriberMock).toHaveBeenCalledWith({ type: "GetBestTrade", diff --git a/packages/keeper-bots/src/converter-bot/TokenConverter.ts b/packages/keeper-bots/src/converter-bot/TokenConverter.ts index 796559f..f4603c6 100644 --- a/packages/keeper-bots/src/converter-bot/TokenConverter.ts +++ b/packages/keeper-bots/src/converter-bot/TokenConverter.ts @@ -327,14 +327,14 @@ export class TokenConverter { * @param amount Amount to check/ request if an allowance has been granted */ async checkAndRequestAllowance(token: Address, owner: Address, spender: Address, amount: bigint) { - const approvalAmount = await this.publicClient.readContract({ + const allowance = await this.publicClient.readContract({ address: token, abi: erc20Abi, functionName: "allowance", args: [owner, spender], }); - if (approvalAmount < amount) { + if (allowance < amount) { const trx = await this.walletClient.writeContract({ address: token, abi: erc20Abi, @@ -444,16 +444,17 @@ export class TokenConverter { tradeAmount: { amountOut: tradeAmount && tradeAmount[0], amountIn: tradeAmount && tradeAmount[1] }, swap: { inputToken: { - amount: trade.inputToken.amount.toString(), + amount: trade.inputToken.amount.toFixed(0), token: trade.inputToken.address, }, outputToken: { - amount: trade.outputToken.amount.toString(), + amount: trade.outputToken.amount.toFixed(0), token: trade.outputToken.address, }, }, }; } + this.sendMessage({ type: "GetBestTrade", error, @@ -468,13 +469,11 @@ export class TokenConverter { if (trade && tradeAmount) { // the difference between the token you get from TokenConverter and the token you pay to the MM - const minIncome = BigInt( - new Fraction(tradeAmount[0], 1).subtract(trade.inputToken.amount).toFixed(0, { groupSeparator: "" }), - ); + const minIncome = new Fraction(tradeAmount[0], 1).subtract(trade.inputToken.amount); return { trade, amount: tradeAmount[0], - minIncome, + minIncome: BigInt(minIncome.toFixed(0, { groupSeparator: "" })), }; } } diff --git a/packages/keeper-bots/src/converter-bot/providers/pancake-swap.ts b/packages/keeper-bots/src/converter-bot/providers/pancake-swap.ts index 22da5c5..d93d65e 100644 --- a/packages/keeper-bots/src/converter-bot/providers/pancake-swap.ts +++ b/packages/keeper-bots/src/converter-bot/providers/pancake-swap.ts @@ -93,6 +93,7 @@ class PancakeSwapProvider extends SwapProvider { functionName: "getUpdatedAmountIn", args: [amount, swapToToken.address, swapFromToken.address], }); + try { const response = await SmartRouter.getBestTrade( CurrencyAmount.fromRawAmount(swapToToken, updatedAmountIn[1]), @@ -107,14 +108,15 @@ class PancakeSwapProvider extends SwapProvider { quoterOptimization: true, }, ); + if (response) { trade = { inputToken: { - amount: response.inputAmount.toFixed(0, { groupSeparator: "" }), + amount: response.inputAmount, address: response.inputAmount.currency.address, }, outputToken: { - amount: response.outputAmount.toFixed(0, { groupSeparator: "" }), + amount: response.outputAmount, address: response.outputAmount.currency.address, }, path: this.encodeExactInputPath(response.routes[0]), diff --git a/packages/keeper-bots/src/converter-bot/providers/swap-provider.ts b/packages/keeper-bots/src/converter-bot/providers/swap-provider.ts index 7cfcbe7..0480ece 100644 --- a/packages/keeper-bots/src/converter-bot/providers/swap-provider.ts +++ b/packages/keeper-bots/src/converter-bot/providers/swap-provider.ts @@ -26,7 +26,6 @@ class SwapProvider { getOutputCurrency =

(pool: P, inputToken: T): T => { // @ts-expect-error library types don't match const { token0, token1 } = pool; - console.log("token0.equals(inputToken)", token0.equals(inputToken)); return token0.equals(inputToken) ? token1 : token0; }; diff --git a/packages/keeper-bots/src/converter-bot/providers/uniswap.ts b/packages/keeper-bots/src/converter-bot/providers/uniswap.ts index 488e01e..ef30add 100644 --- a/packages/keeper-bots/src/converter-bot/providers/uniswap.ts +++ b/packages/keeper-bots/src/converter-bot/providers/uniswap.ts @@ -1,5 +1,6 @@ +import { Fraction } from "@pancakeswap/sdk"; import { IRoute } from "@uniswap/router-sdk"; -import { ChainId, Currency, CurrencyAmount, Fraction, Percent, Token, TradeType } from "@uniswap/sdk-core"; +import { ChainId, Currency, CurrencyAmount, Percent, Token, TradeType } from "@uniswap/sdk-core"; import { AlphaRouter, SwapOptionsSwapRouter02, SwapType } from "@uniswap/smart-order-router"; import { Pool, Route } from "@uniswap/v3-sdk"; import { ethers } from "ethers"; @@ -103,14 +104,16 @@ class UniswapProvider extends SwapProvider { trade = { inputToken: { - amount: BigInt( - new Fraction(inputCurrency.numerator, inputCurrency.denominator).toFixed(0, { groupSeparator: "" }), + amount: new Fraction( + BigInt(inputCurrency.numerator.toString()), + BigInt(inputCurrency.denominator.toString()), ), address: (inputCurrency?.currency as Token).address as Address, }, outputToken: { - amount: BigInt( - new Fraction(outputCurrency.numerator, outputCurrency.denominator).toFixed(0, { groupSeparator: "" }), + amount: new Fraction( + BigInt(outputCurrency.numerator.toString()), + BigInt(outputCurrency.denominator.toString()), ), address: (outputCurrency?.currency as Token).address as Address, }, diff --git a/packages/keeper-bots/src/converter-bot/types.ts b/packages/keeper-bots/src/converter-bot/types.ts index 8442252..0719842 100644 --- a/packages/keeper-bots/src/converter-bot/types.ts +++ b/packages/keeper-bots/src/converter-bot/types.ts @@ -1,3 +1,4 @@ +import { Fraction } from "@pancakeswap/sdk"; import { Address } from "viem"; import { BalanceResult } from "./queries/getTokenConvertersTokenBalances"; @@ -74,11 +75,11 @@ export type Message = export interface TradeRoute { inputToken: { - amount: bigint; + amount: Fraction; address: Address; }; outputToken: { - amount: bigint; + amount: Fraction; address: Address; }; path: Address;