diff --git a/src/entities/trades/swapr-v3/SwaprV3.ts b/src/entities/trades/swapr-v3/SwaprV3.ts index ea678dad..5d75e5db 100644 --- a/src/entities/trades/swapr-v3/SwaprV3.ts +++ b/src/entities/trades/swapr-v3/SwaprV3.ts @@ -71,7 +71,7 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { static async getQuote( { amount, quoteCurrency, tradeType, maximumSlippage }: SwaprV3GetQuoteParams, - provider?: BaseProvider + provider?: BaseProvider, ): Promise { const chainId = tryGetChainId(amount, quoteCurrency) invariant(chainId, 'SwaprV3Trade.getQuote: chainId is required') @@ -87,7 +87,7 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { amount.currency.address, amount.currency.decimals, amount.currency.symbol, - amount.currency.name + amount.currency.name, ) invariant(quoteCurrency.address, `SwaprV3Trade.getQuote: quoteCurrency.address is required`) @@ -98,12 +98,12 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { quoteCurrency.address, quoteCurrency.decimals, quoteCurrency.symbol, - quoteCurrency.name + quoteCurrency.name, ) invariant( (await provider.getNetwork()).chainId == chainId, - `SwaprV3Trade.getQuote: currencies chainId does not match provider's chainId` + `SwaprV3Trade.getQuote: currencies chainId does not match provider's chainId`, ) const routes = await getRoutes(tokenIn, tokenOut, chainId) @@ -119,7 +119,7 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { tokenIn.address, tokenOut.address, parseUnits(amount.toSignificant(), amount.currency.decimals), - 0 + 0, ) .catch((error) => { console.error(`Error sending quoteExactInputSingle transaction: ${error}`) @@ -143,7 +143,7 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { tokenOut.address, amount.currency.address, parseUnits(amount.toSignificant(), amount.currency.decimals), - 0 + 0, ) .catch((error) => { console.error(`Error sending quoteExactOutputSingle transaction: ${error}`) @@ -194,21 +194,28 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { } public async swapTransaction(options: TradeOptions): Promise { - const to: string = validateAndParseAddress(options.recipient) - const amountIn: string = `0x${this.maximumAmountIn().raw.toString(16)}` - const amountOut: string = `0x${this.minimumAmountOut().raw.toString(16)}` + 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') + + 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() const baseParams = { - tokenIn: this.inputAmount.currency.address, - tokenOut: this.outputAmount.currency.address, - recipient: to, + 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, } + const value = isNativeIn ? amountIn : undefined + const exactInputSingleParams = { ...baseParams, amountIn: amountIn, @@ -223,7 +230,7 @@ export class SwaprV3Trade extends TradeWithSwapTransaction { const methodName = isTradeExactInput ? 'exactInputSingle' : 'exactOutputSingle' const params = isTradeExactInput ? exactInputSingleParams : exactOutputSingleParams - const populatedTransaction = await routerContract.populateTransaction[methodName](params) + const populatedTransaction = await routerContract.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 99aae0cf..e45f8c3d 100644 --- a/src/entities/trades/swapr-v3/swapr-v3.spec.ts +++ b/src/entities/trades/swapr-v3/swapr-v3.spec.ts @@ -4,6 +4,7 @@ import { SwaprV3Trade } from './SwaprV3' import { ChainId, TradeType } from '../../../constants' import { Percent, TokenAmount } from '../../fractions' import { Token } from '../../token' +import { Currency } from '../../currency' const maximumSlippage = new Percent('3', '100') const tokenWXDAI = new Token(ChainId.GNOSIS, '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', 18, 'WXDAI', 'WXDAI') @@ -80,21 +81,37 @@ describe('SwaprV3', () => { expect(trade?.inputAmount.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 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) + }) + + // 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', () => { @@ -114,8 +131,27 @@ describe('SwaprV3', () => { account: recipient, } + const swap = await trade?.swapTransaction(swapOptions) + expect(swap !== undefined) + }) + test('should return a swap on gnosis with 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_INPUT, + }) + + const swapOptions = { + recipient: recipient, + account: recipient, + } + const swap = await trade?.swapTransaction(swapOptions) expect(swap !== undefined) }) }) -}) +}) \ No newline at end of file