diff --git a/src/entities/trades/swapr-v3/SwaprV3.ts b/src/entities/trades/swapr-v3/SwaprV3.ts index 5d75e5db..e5bb8c57 100644 --- a/src/entities/trades/swapr-v3/SwaprV3.ts +++ b/src/entities/trades/swapr-v3/SwaprV3.ts @@ -20,6 +20,7 @@ import { getRoutes } from './routes' import { maximumSlippage as defaultMaximumSlippage } from '../constants' import { Currency } from '../../currency' import { Token, WXDAI } from '../../token' +import JSBI from 'jsbi' interface SwaprV3ConstructorParams { maximumSlippage: Percent @@ -38,6 +39,7 @@ export interface SwaprV3GetQuoteParams { maximumSlippage?: Percent recipient?: string } +const ALGEBRA_FEE_PARTS_PER_MILLION = JSBI.BigInt(1_000_000) export class SwaprV3Trade extends TradeWithSwapTransaction { public constructor({ @@ -79,8 +81,13 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { maximumSlippage = maximumSlippage ?? defaultMaximumSlippage provider = provider ?? getProvider(chainId) + invariant( + (await provider.getNetwork()).chainId == chainId, + `SwaprV3Trade.getQuote: currencies chainId does not match provider's chainId`, + ) + invariant(amount.currency.address, `SwaprV3Trade.getQuote: amount.currency.address is required`) - const tokenIn = Currency.isNative(amount.currency) + const setToken = Currency.isNative(amount.currency) ? WXDAI[ChainId.GNOSIS] : new Token( ChainId.GNOSIS, @@ -91,7 +98,7 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { ) invariant(quoteCurrency.address, `SwaprV3Trade.getQuote: quoteCurrency.address is required`) - const tokenOut = Currency.isNative(quoteCurrency) + const quoteToken = Currency.isNative(quoteCurrency) ? WXDAI[ChainId.GNOSIS] : new Token( ChainId.GNOSIS, @@ -101,26 +108,18 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { quoteCurrency.name, ) - invariant( - (await provider.getNetwork()).chainId == chainId, - `SwaprV3Trade.getQuote: currencies chainId does not match provider's chainId`, - ) - - const routes = await getRoutes(tokenIn, tokenOut, chainId) + const routes = await getRoutes(setToken, quoteToken, chainId) const fee = routes?.length > 0 && routes[0].pools.length > 0 - ? new Percent(routes[0].pools[0].fee.toString(), '1000000') - : new Percent('0', '0') + ? new Percent(routes[0].pools[0].fee.toString(), ALGEBRA_FEE_PARTS_PER_MILLION) + : new Percent('0', '1') + + const parsedAmount = parseUnits(amount.toSignificant(), amount.currency.decimals) if (tradeType === TradeType.EXACT_INPUT) { const quotedAmountOut = await getQuoterContract() - .callStatic.quoteExactInputSingle( - tokenIn.address, - tokenOut.address, - parseUnits(amount.toSignificant(), amount.currency.decimals), - 0, - ) + .callStatic.quoteExactInputSingle(setToken.address, quoteToken.address, parsedAmount, 0) .catch((error) => { console.error(`Error sending quoteExactInputSingle transaction: ${error}`) return null @@ -130,21 +129,16 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { return new SwaprV3Trade({ maximumSlippage, inputAmount: amount, - outputAmount: new TokenAmount(tokenOut, quotedAmountOut), + outputAmount: new TokenAmount(quoteToken, quotedAmountOut), tradeType: tradeType, chainId: chainId, - priceImpact: new Percent('0', '1000'), + priceImpact: new Percent('0', '100'), fee, }) } } else { const quotedAmountIn = await getQuoterContract() - .callStatic.quoteExactOutputSingle( - tokenOut.address, - amount.currency.address, - parseUnits(amount.toSignificant(), amount.currency.decimals), - 0, - ) + .callStatic.quoteExactOutputSingle(quoteToken.address, setToken.address, parsedAmount, 0) .catch((error) => { console.error(`Error sending quoteExactOutputSingle transaction: ${error}`) return null @@ -153,11 +147,11 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { if (quotedAmountIn) { return new SwaprV3Trade({ maximumSlippage, - inputAmount: new TokenAmount(tokenOut, quotedAmountIn), + inputAmount: new TokenAmount(quoteToken, quotedAmountIn), outputAmount: amount, tradeType: tradeType, chainId: chainId, - priceImpact: new Percent('0', '1000'), + priceImpact: new Percent('0', '100'), fee: fee, }) } @@ -196,22 +190,26 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { public async swapTransaction(options: TradeOptions): Promise { const isNativeIn = Currency.isNative(this.inputAmount.currency) const isNativeOut = Currency.isNative(this.outputAmount.currency) - invariant(!(isNativeIn && isNativeOut), 'SwaprV3Trade.swapTransaction: the router does not support both native in and out') + invariant( + !(isNativeIn && isNativeOut), + 'SwaprV3Trade.swapTransaction: the router does not support both native in and out', + ) const recipient = validateAndParseAddress(options.recipient) const amountIn = `0x${this.maximumAmountIn().raw.toString(16)}` const amountOut = `0x${this.minimumAmountOut().raw.toString(16)}` const isTradeExactInput = this.tradeType === TradeType.EXACT_INPUT - const routerContract = getRouterContract() + // Swapr Algebra Contract fee param is uint24 type + const algebraFee = this.fee.multiply(ALGEBRA_FEE_PARTS_PER_MILLION).toSignificant(1) const baseParams = { - tokenIn: isNativeIn ? WXDAI[ChainId.GNOSIS].address : this.inputAmount.currency.address, + tokenIn: isNativeIn ? WXDAI[ChainId.GNOSIS].address : this.inputAmount.currency.address, tokenOut: isNativeOut ? WXDAI[ChainId.GNOSIS].address : this.outputAmount.currency.address, recipient, deadline: dayjs().add(30, 'm').unix(), sqrtPriceLimitX96: 0, - fee: this.fee, + fee: algebraFee, } const value = isNativeIn ? amountIn : undefined @@ -230,7 +228,7 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { const methodName = isTradeExactInput ? 'exactInputSingle' : 'exactOutputSingle' const params = isTradeExactInput ? exactInputSingleParams : exactOutputSingleParams - const populatedTransaction = await routerContract.populateTransaction[methodName](params, { value }) + const populatedTransaction = await getRouterContract().populateTransaction[methodName](params, { value }) return populatedTransaction } diff --git a/src/entities/trades/swapr-v3/swapr-v3.spec.ts b/src/entities/trades/swapr-v3/swapr-v3.spec.ts index e45f8c3d..581e64be 100644 --- a/src/entities/trades/swapr-v3/swapr-v3.spec.ts +++ b/src/entities/trades/swapr-v3/swapr-v3.spec.ts @@ -18,7 +18,7 @@ const recipient = NULL_ADDRESS describe('SwaprV3', () => { describe('Quote', () => { - test('should return a EXACT INPUT quote on Gnosis for USDC - WXDAI', async () => { + test('should return a EXACT INPUT quote for USDC - WXDAI', async () => { const currencyAmount = new TokenAmount(tokenUSDC, parseUnits('2.59', 6).toString()) const trade = await SwaprV3Trade.getQuote({ amount: currencyAmount, @@ -34,7 +34,7 @@ describe('SwaprV3', () => { expect(trade?.outputAmount.currency.address).toBe(tokenWXDAI.address) }) - test('should return a EXACT INPUT quote on Gnosis for WETH - WXDAI', async () => { + test('should return a EXACT INPUT quote for WETH - WXDAI', async () => { const currencyAmount = new TokenAmount(tokenWETH, parseUnits('1', 18).toString()) const trade = await SwaprV3Trade.getQuote({ amount: currencyAmount, @@ -50,7 +50,7 @@ describe('SwaprV3', () => { expect(trade?.outputAmount.currency.address).toBe(tokenWXDAI.address) }) - test('should return a EXACT INPUT quote on Gnosis for SWPR - WXDAI', async () => { + test('should return a EXACT INPUT quote for SWPR - WXDAI', async () => { const currencyAmount = new TokenAmount(tokenWXDAI, parseUnits('1', 18).toString()) const trade = await SwaprV3Trade.getQuote({ amount: currencyAmount, @@ -66,7 +66,7 @@ describe('SwaprV3', () => { expect(trade?.outputAmount.currency.address).toBe(tokenSWPR.address) }) - test('should return a exact output quote on Gnosis for WXDAI - USDC', async () => { + test('should return a exact output quote for WXDAI - USDC', async () => { const currencyAmount = new TokenAmount(tokenWXDAI, parseUnits('2', 18).toString()) const trade = await SwaprV3Trade.getQuote({ quoteCurrency: tokenUSDC, @@ -81,41 +81,41 @@ describe('SwaprV3', () => { expect(trade?.inputAmount.currency.address).toBe(tokenUSDC.address) }) - test('should return a exact input quote for a native token XDAI - USDC', async () => { - const currencyAmount = new TokenAmount(tokenUSDC, parseUnits('2', 6).toString()) - const trade = await SwaprV3Trade.getQuote({ - quoteCurrency: Currency.getNative(ChainId.GNOSIS), - amount: currencyAmount, - maximumSlippage, - recipient, - tradeType: TradeType.EXACT_OUTPUT, - }) + test('should return a exact input quote for a native token XDAI - USDC', async () => { + const currencyAmount = new TokenAmount(tokenUSDC, parseUnits('2', 6).toString()) + const trade = await SwaprV3Trade.getQuote({ + quoteCurrency: Currency.getNative(ChainId.GNOSIS), + amount: currencyAmount, + maximumSlippage, + recipient, + tradeType: TradeType.EXACT_OUTPUT, + }) - expect(trade).toBeDefined() - expect(trade?.chainId).toEqual(ChainId.GNOSIS) - expect(trade?.tradeType).toEqual(TradeType.EXACT_OUTPUT) - expect(trade?.outputAmount.currency.address).toBe(tokenUSDC.address) - }) + expect(trade).toBeDefined() + expect(trade?.chainId).toEqual(ChainId.GNOSIS) + expect(trade?.tradeType).toEqual(TradeType.EXACT_OUTPUT) + expect(trade?.outputAmount.currency.address).toBe(tokenUSDC.address) + }) - // test('should return a EXACT INPUT quote on Gnosis for GNO - WETH', async () => { - // const currencyAmount = new TokenAmount(tokenGNO, parseUnits('1', 18).toString()) - // const trade = await SwaprV3Trade.getQuote({ - // amount: currencyAmount, - // quoteCurrency: tokenWETH, - // maximumSlippage, - // recipient, - // tradeType: TradeType.EXACT_INPUT, - // }) - - // expect(trade).toBeDefined() - // expect(trade?.chainId).toEqual(ChainId.GNOSIS) - // expect(trade?.tradeType).toEqual(TradeType.EXACT_INPUT) - // expect(trade?.outputAmount.currency.address).toBe(tokenWETH.address) - // }) + // test('should return a EXACT INPUT quote on Gnosis for GNO - WETH', async () => { + // const currencyAmount = new TokenAmount(tokenGNO, parseUnits('1', 18).toString()) + // const trade = await SwaprV3Trade.getQuote({ + // amount: currencyAmount, + // quoteCurrency: tokenWETH, + // maximumSlippage, + // recipient, + // tradeType: TradeType.EXACT_INPUT, + // }) + + // expect(trade).toBeDefined() + // expect(trade?.chainId).toEqual(ChainId.GNOSIS) + // expect(trade?.tradeType).toEqual(TradeType.EXACT_INPUT) + // expect(trade?.outputAmount.currency.address).toBe(tokenWETH.address) + // }) }) describe('Swap', () => { - test('should return a swap for Gnosis for USDC - WXDAI', async () => { + test('should return a swap EXACT INPUT for USDC - WXDAI', async () => { const currencyAmount = new TokenAmount(tokenUSDC, parseUnits('2', 6).toString()) const trade = await SwaprV3Trade.getQuote({ @@ -134,7 +134,30 @@ describe('SwaprV3', () => { const swap = await trade?.swapTransaction(swapOptions) expect(swap !== undefined) }) - test('should return a swap on gnosis with native token XDAI - USDC', async () => { + test('should return a swap EXACT OUTPUT for USDC - WXDAI', async () => { + const currencyAmount = new TokenAmount(tokenWXDAI, parseUnits('2', 18).toString()) + const trade = await SwaprV3Trade.getQuote({ + quoteCurrency: tokenUSDC, + amount: currencyAmount, + maximumSlippage, + recipient, + tradeType: TradeType.EXACT_OUTPUT, + }) + + expect(trade).toBeDefined() + expect(trade?.chainId).toEqual(ChainId.GNOSIS) + expect(trade?.tradeType).toEqual(TradeType.EXACT_OUTPUT) + expect(trade?.inputAmount.currency.address).toBe(tokenUSDC.address) + + const swapOptions = { + recipient: recipient, + account: recipient, + } + + const swap = await trade?.swapTransaction(swapOptions) + expect(swap !== undefined) + }) + test('should return a swap EXACT INPUT for XDAI - USDC', async () => { const currencyAmount = new TokenAmount(tokenUSDC, parseUnits('2', 6).toString()) const trade = await SwaprV3Trade.getQuote({ @@ -154,4 +177,4 @@ describe('SwaprV3', () => { expect(swap !== undefined) }) }) -}) \ No newline at end of file +})