Skip to content

Commit

Permalink
Merge pull request #327 from SwaprHQ/liq-2-add-swapr-v3-to-eco-router…
Browse files Browse the repository at this point in the history
…-on-swapr-sdk

Add swapr liquidity v3 support on eco router
  • Loading branch information
Diogomartf authored Jan 4, 2024
2 parents 47c8506 + abbc194 commit b3281cf
Show file tree
Hide file tree
Showing 22 changed files with 3,272 additions and 48 deletions.
277 changes: 239 additions & 38 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"dayjs": "^1.11.0",
"debug": "^4.3.4",
"decimal.js-light": "^2.5.1",
"graphql-request": "^4.3.0",
"graphql-request": "^6.1.0",
"jsbi": "^3.1.1",
"lodash.flatmap": "^4.5.0",
"memoizee": "^0.4.15",
Expand All @@ -62,7 +62,7 @@
"devDependencies": {
"@graphql-codegen/cli": "2.6.2",
"@graphql-codegen/typescript": "2.5.1",
"@graphql-codegen/typescript-graphql-request": "^4.4.10",
"@graphql-codegen/typescript-graphql-request": "^6.0.1",
"@graphql-codegen/typescript-operations": "^2.4.2",
"@testing-library/jest-dom": "^5.16.4",
"@types/big.js": "^4.0.5",
Expand Down
Empty file.
2 changes: 1 addition & 1 deletion src/entities/trades/gnosis-protocol/CoWTrade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export class CoWTrade extends Trade {
invariant(!tokenIn.equals(tokenOut), 'CURRENCY')

// const etherOut = this.outputAmount.currency === nativeCurrency
// // the router does not support both ether in and out
// the router does not support both ether in and out
// invariant(!(etherIn && etherOut), 'ETHER_IN_OUT')
try {
const quoteResponse = await CoWTrade.getCowSdk(chainId).cowApi.getQuote({
Expand Down
1 change: 1 addition & 0 deletions src/entities/trades/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export { BaseRoutablePlatform, RoutablePlatform, UniswapV2RoutablePlatform } fro
export * from './uniswap'
export * from './uniswap-v2'
export * from './velodrome'
export * from './swapr-v3'
7 changes: 4 additions & 3 deletions src/entities/trades/routable-platform/RoutablePlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@ export class RoutablePlatform extends BaseRoutablePlatform {
],
'1Inch'
)
public static readonly COW = new RoutablePlatform([ChainId.MAINNET, ChainId.XDAI], 'CoW')
public static readonly CURVE = new RoutablePlatform([ChainId.MAINNET, ChainId.ARBITRUM_ONE, ChainId.XDAI], 'Curve')
public static readonly COW = new RoutablePlatform([ChainId.MAINNET, ChainId.GNOSIS], 'CoW')
public static readonly CURVE = new RoutablePlatform([ChainId.MAINNET, ChainId.ARBITRUM_ONE, ChainId.GNOSIS], 'Curve')
/**
* @deprecated Use {@link RoutablePlatform.COW} instead.
*/
public static readonly GNOSIS_PROTOCOL = new RoutablePlatform([ChainId.MAINNET, ChainId.XDAI], 'CoW')
public static readonly GNOSIS_PROTOCOL = new RoutablePlatform([ChainId.MAINNET, ChainId.GNOSIS], 'CoW')
public static readonly UNISWAP = new RoutablePlatform(
[ChainId.MAINNET, ChainId.ARBITRUM_ONE, ChainId.POLYGON, ChainId.OPTIMISM_MAINNET],
'Uniswap'
)

public static readonly VELODROME = new RoutablePlatform([ChainId.OPTIMISM_MAINNET], 'Velodrome')
public static readonly SWAPR_V3 = new RoutablePlatform([ChainId.GNOSIS], 'Swapr V3')
}
230 changes: 230 additions & 0 deletions src/entities/trades/swapr-v3/SwaprV3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import type { BaseProvider } from '@ethersproject/providers'
import dayjs from 'dayjs'

import { Fraction, validateAndParseAddress } from '@uniswap/sdk-core'
import invariant from 'tiny-invariant'

import { CurrencyAmount, Percent, Price, TokenAmount } from '../../fractions'

import { TradeWithSwapTransaction } from '../interfaces/trade'
import { RoutablePlatform } from '../routable-platform'
import { getProvider, tryGetChainId } from '../utils'
import { ChainId, ONE, TradeType } from '../../../constants'

import { UnsignedTransaction } from 'ethers'
import { TradeOptions } from '../interfaces/trade-options'
import { parseUnits } from '@ethersproject/units'
import { SWAPR_ALGEBRA_CONTRACTS } from './constants'
import { getQuoterContract, getRouterContract } from './contracts'
import { getRoutes } from './routes'
import { maximumSlippage as defaultMaximumSlippage } from '../constants'
import { Currency } from '../../currency'
import { Token, WXDAI } from '../../token'

interface SwaprV3ConstructorParams {
maximumSlippage: Percent
inputAmount: CurrencyAmount
outputAmount: CurrencyAmount
tradeType: TradeType
chainId: number
priceImpact: Percent
fee: Percent
}

export interface SwaprV3GetQuoteParams {
amount: CurrencyAmount
quoteCurrency: Currency
tradeType: TradeType
maximumSlippage?: Percent
recipient?: string
}

export class SwaprV3Trade extends TradeWithSwapTransaction {
public constructor({
inputAmount,
outputAmount,
maximumSlippage,
priceImpact,
tradeType,
chainId,
fee,
}: SwaprV3ConstructorParams) {
super({
details: undefined,
type: tradeType,
inputAmount,
outputAmount,
maximumSlippage,
platform: RoutablePlatform.SWAPR_V3,
chainId,
executionPrice: new Price({
baseCurrency: inputAmount.currency,
quoteCurrency: outputAmount.currency,
denominator: inputAmount.raw,
numerator: outputAmount.raw,
}),
priceImpact,
fee,
approveAddress: SWAPR_ALGEBRA_CONTRACTS['router'],
})
}

static async getQuote(
{ amount, quoteCurrency, tradeType, maximumSlippage }: SwaprV3GetQuoteParams,
provider?: BaseProvider
): Promise<SwaprV3Trade | null> {
const chainId = tryGetChainId(amount, quoteCurrency)
invariant(chainId, 'SwaprV3Trade.getQuote: chainId is required')

maximumSlippage = maximumSlippage ?? defaultMaximumSlippage
provider = provider ?? getProvider(chainId)

invariant(amount.currency.address, `SwaprV3Trade.getQuote: amount.currency.address is required`)
const tokenIn = Currency.isNative(amount.currency)
? WXDAI[ChainId.GNOSIS]
: new Token(
ChainId.GNOSIS,
amount.currency.address,
amount.currency.decimals,
amount.currency.symbol,
amount.currency.name
)

invariant(quoteCurrency.address, `SwaprV3Trade.getQuote: quoteCurrency.address is required`)
const tokenOut = Currency.isNative(quoteCurrency)
? WXDAI[ChainId.GNOSIS]
: new Token(
ChainId.GNOSIS,
quoteCurrency.address,
quoteCurrency.decimals,
quoteCurrency.symbol,
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 fee =
routes?.length > 0 && routes[0].pools.length > 0
? new Percent(routes[0].pools[0].fee.toString(), '1000000')
: new Percent('0', '0')

if (tradeType === TradeType.EXACT_INPUT) {
const quotedAmountOut = await getQuoterContract()
.callStatic.quoteExactInputSingle(
tokenIn.address,
tokenOut.address,
parseUnits(amount.toSignificant(), amount.currency.decimals),
0
)
.catch((error) => {
console.error(`Error sending quoteExactInputSingle transaction: ${error}`)
return null
})

if (quotedAmountOut) {
return new SwaprV3Trade({
maximumSlippage,
inputAmount: amount,
outputAmount: new TokenAmount(tokenOut, quotedAmountOut),
tradeType: tradeType,
chainId: chainId,
priceImpact: new Percent('0', '1000'),
fee,
})
}
} else {
const quotedAmountIn = await getQuoterContract()
.callStatic.quoteExactOutputSingle(
tokenOut.address,
amount.currency.address,
parseUnits(amount.toSignificant(), amount.currency.decimals),
0
)
.catch((error) => {
console.error(`Error sending quoteExactOutputSingle transaction: ${error}`)
return null
})

if (quotedAmountIn) {
return new SwaprV3Trade({
maximumSlippage,
inputAmount: new TokenAmount(tokenOut, quotedAmountIn),
outputAmount: amount,
tradeType: tradeType,
chainId: chainId,
priceImpact: new Percent('0', '1000'),
fee: fee,
})
}
}

return null
}

public minimumAmountOut(): CurrencyAmount {
if (this.tradeType === TradeType.EXACT_OUTPUT) {
return this.outputAmount
} else {
const slippageAdjustedAmountOut = new Fraction(ONE)
.add(this.maximumSlippage as Fraction)
.invert()
.multiply(this.outputAmount.raw).quotient
return this.outputAmount instanceof TokenAmount
? new TokenAmount(this.outputAmount.token, slippageAdjustedAmountOut)
: CurrencyAmount.nativeCurrency(slippageAdjustedAmountOut, this.chainId)
}
}

public maximumAmountIn(): CurrencyAmount {
if (this.tradeType === TradeType.EXACT_INPUT) {
return this.inputAmount
} else {
const slippageAdjustedAmountIn = new Fraction(ONE)
.add(this.maximumSlippage as Fraction)
.multiply(this.inputAmount.raw).quotient
return this.inputAmount instanceof TokenAmount
? new TokenAmount(this.inputAmount.token, slippageAdjustedAmountIn)
: CurrencyAmount.nativeCurrency(slippageAdjustedAmountIn, this.chainId)
}
}

public async swapTransaction(options: TradeOptions): Promise<UnsignedTransaction> {
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 isTradeExactInput = this.tradeType === TradeType.EXACT_INPUT
const routerContract = getRouterContract()

const baseParams = {
tokenIn: this.inputAmount.currency.address,
tokenOut: this.outputAmount.currency.address,
recipient: to,
deadline: dayjs().add(30, 'm').unix(),
sqrtPriceLimitX96: 0,
fee: this.fee,
}

const exactInputSingleParams = {
...baseParams,
amountIn: amountIn,
amountOutMinimum: amountOut,
}

const exactOutputSingleParams = {
...baseParams,
amountOut: amountOut,
amountInMaximum: amountIn,
}

const methodName = isTradeExactInput ? 'exactInputSingle' : 'exactOutputSingle'
const params = isTradeExactInput ? exactInputSingleParams : exactOutputSingleParams
const populatedTransaction = await routerContract.populateTransaction[methodName](params)

return populatedTransaction
}
}
3 changes: 3 additions & 0 deletions src/entities/trades/swapr-v3/abi/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './swapr-algebra-quoter'
export * from './swapr-algebra-router'
export * from './swapr-algebra-pool'
Loading

0 comments on commit b3281cf

Please sign in to comment.