Skip to content

Commit

Permalink
feat: use gauges as routing reference
Browse files Browse the repository at this point in the history
  • Loading branch information
chefjackson committed Feb 5, 2024
1 parent 455b5ef commit 83b1d93
Show file tree
Hide file tree
Showing 25 changed files with 325 additions and 85 deletions.
101 changes: 98 additions & 3 deletions packages/smart-router/evm/v3-router/functions/getPairCombinations.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,87 @@
import { ChainId } from '@pancakeswap/chains'
import { Currency, Token } from '@pancakeswap/sdk'
import { getTokensByChain } from '@pancakeswap/tokens'
import type { Address } from 'viem'
import { GAUGES_CONFIG, GaugeConfig, GaugeType } from '@pancakeswap/gauges'
import flatMap from 'lodash/flatMap.js'
import memoize from 'lodash/memoize.js'
import uniqBy from 'lodash/uniqBy.js'

import { ADDITIONAL_BASES, BASES_TO_CHECK_TRADES_AGAINST, CUSTOM_BASES } from '../../constants'
import { wrappedCurrency } from '../../utils/currency'
import { isCurrenciesSameChain } from '../utils'

const allGuages = GAUGES_CONFIG[ChainId.BSC]

const getToken = memoize(
(chainId?: ChainId, address?: Address): Token | undefined => {
if (!chainId || !address) {
return undefined
}
const tokens = getTokensByChain(chainId)
for (const token of tokens) {
if (token.address.toLowerCase() === address.toLowerCase()) {
return token
}
}
return undefined
},
(chainId, address) => `${chainId}_${address}`,
)

// TODO: move to gauges
const getGaugesByChain = memoize(
(chainId?: ChainId): GaugeConfig[] => allGuages.filter((gauge) => gauge.chainId === chainId),
(chainId) => chainId,
)

function isTokenInCommonBases(token?: Token) {
return Boolean(token && BASES_TO_CHECK_TRADES_AGAINST[token.chainId as ChainId].find((t) => t.equals(token)))
}

const getTokenBasesFromGauges = memoize(
(currency?: Currency): Token[] => {
const chainId: ChainId | undefined = currency?.chainId
const address = currency?.wrapped.address
const gauges = getGaugesByChain(currency?.chainId)
const bases = new Set<Token>()
const addTokenToBases = (token?: Token) => token && !isTokenInCommonBases(token) && bases.add(token)
const addTokensToBases = (tokens: Token[]) => tokens.forEach(addTokenToBases)
const isCurrentToken = (addr: Address) => addr.toLowerCase() === address?.toLowerCase()

if (currency && chainId && isTokenInCommonBases(currency.wrapped)) {
return []
}
for (const gauge of gauges) {
const { type } = gauge
if (type === GaugeType.V2 || type === GaugeType.V3) {
const { token0Address, token1Address } = gauge
if (isCurrentToken(token0Address)) {
addTokenToBases(getToken(chainId, token1Address))
}
if (isCurrentToken(token1Address)) {
addTokenToBases(getToken(chainId, token0Address))
}
continue
}
if (type === GaugeType.StableSwap) {
const { tokenAddresses } = gauge
const index = tokenAddresses.findIndex(isCurrentToken)
if (index < 0) {
continue
}
addTokensToBases(
[...tokenAddresses.slice(0, index), ...tokenAddresses.slice(index + 1)]
.map((addr) => getToken(chainId, addr))
.filter((token?: Token): token is Token => Boolean(token)),
)
}
}
return Array.from(bases)
},
(c) => `${c?.chainId}_${c?.wrapped.address}`,
)

const resolver = (currencyA?: Currency, currencyB?: Currency) => {
if (!currencyA || !currencyB || currencyA.wrapped.equals(currencyB.wrapped)) {
return `${currencyA?.chainId}_${currencyA?.wrapped?.address}_${currencyB?.wrapped?.address}`
Expand All @@ -17,6 +92,28 @@ const resolver = (currencyA?: Currency, currencyB?: Currency) => {
return `${token0.chainId}_${token0.address}_${token1.address}`
}

type TokenBases = {
[tokenAddress: Address]: Token[]
}

function getAdditionalCheckAgainstBaseTokens(currencyA?: Currency, currencyB?: Currency) {
const chainId: ChainId | undefined = currencyA?.chainId
const additionalBases: TokenBases = {
...(chainId ? ADDITIONAL_BASES[chainId] ?? {} : {}),
}
const uniq = (tokens: Token[]) => uniqBy(tokens, (t) => t.address)
const additionalA =
currencyA && chainId
? uniq([...(additionalBases[currencyA.wrapped.address] || []), ...getTokenBasesFromGauges(currencyA)]) ?? []
: []
const additionalB =
currencyB && chainId
? uniq([...(additionalBases[currencyB.wrapped.address] || []), ...getTokenBasesFromGauges(currencyB)]) ?? []
: []

return [...additionalA, ...additionalB]
}

export const getCheckAgainstBaseTokens = memoize((currencyA?: Currency, currencyB?: Currency): Token[] => {
// eslint-disable-next-line prefer-destructuring
const chainId: ChainId | undefined = currencyA?.chainId
Expand All @@ -33,10 +130,8 @@ export const getCheckAgainstBaseTokens = memoize((currencyA?: Currency, currency
}

const common = BASES_TO_CHECK_TRADES_AGAINST[chainId] ?? []
const additionalA = tokenA ? ADDITIONAL_BASES[chainId]?.[tokenA.address] ?? [] : []
const additionalB = tokenB ? ADDITIONAL_BASES[chainId]?.[tokenB.address] ?? [] : []

return [...common, ...additionalA, ...additionalB]
return [...common, ...getAdditionalCheckAgainstBaseTokens(currencyA, currencyB)]
}, resolver)

export const getPairCombinations = memoize((currencyA?: Currency, currencyB?: Currency): [Currency, Currency][] => {
Expand Down
1 change: 1 addition & 0 deletions packages/smart-router/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
],
"dependencies": {
"@pancakeswap/chains": "workspace:*",
"@pancakeswap/gauges": "workspace:*",
"@pancakeswap/multicall": "workspace:*",
"@pancakeswap/sdk": "workspace:*",
"@pancakeswap/swap-sdk-core": "workspace:*",
Expand Down
39 changes: 39 additions & 0 deletions packages/tokens/src/allTokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ChainId } from '@pancakeswap/chains'

import { bscTokens } from './constants/bsc'
import { goerliTestnetTokens } from './constants/goerli'
import { bscTestnetTokens } from './constants/bscTestnet'
import { ethereumTokens } from './constants/eth'
import { arbitrumTokens } from './constants/arb'
import { polygonZkEvmTokens } from './constants/polygonZkEVM'
import { polygonZkEvmTestnetTokens } from './constants/polygonZkEVMTestnet'
import { zksyncTokens } from './constants/zkSync'
import { zkSyncTestnetTokens } from './constants/zkSyncTestnet'
import { lineaTestnetTokens } from './constants/lineaTestnet'
import { lineaTokens } from './constants/linea'
import { arbitrumGoerliTokens } from './constants/arbGoerli'
import { opBnbTokens } from './constants/opBNB'
import { opBnbTestnetTokens } from './constants/opBnbTestnet'
import { baseTokens } from './constants/base'
import { baseTestnetTokens } from './constants/baseTestnet'
import { scrollSepoliaTokens } from './constants/scrollSepolia'

export const allTokens = {
[ChainId.GOERLI]: goerliTestnetTokens,
[ChainId.BSC]: bscTokens,
[ChainId.BSC_TESTNET]: bscTestnetTokens,
[ChainId.ETHEREUM]: ethereumTokens,
[ChainId.ARBITRUM_ONE]: arbitrumTokens,
[ChainId.POLYGON_ZKEVM]: polygonZkEvmTokens,
[ChainId.POLYGON_ZKEVM_TESTNET]: polygonZkEvmTestnetTokens,
[ChainId.ZKSYNC]: zksyncTokens,
[ChainId.ZKSYNC_TESTNET]: zkSyncTestnetTokens,
[ChainId.LINEA_TESTNET]: lineaTestnetTokens,
[ChainId.LINEA]: lineaTokens,
[ChainId.ARBITRUM_GOERLI]: arbitrumGoerliTokens,
[ChainId.OPBNB]: opBnbTokens,
[ChainId.OPBNB_TESTNET]: opBnbTestnetTokens,
[ChainId.BASE]: baseTokens,
[ChainId.BASE_TESTNET]: baseTestnetTokens,
[ChainId.SCROLL_SEPOLIA]: scrollSepoliaTokens,
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions packages/tokens/src/helpers/getTokensByChain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ChainId } from '@pancakeswap/chains'
import { Token } from '@pancakeswap/sdk'

import { allTokens } from '../allTokens'

export function getTokensByChain(chainId?: ChainId): Token[] {
if (!chainId) {
return []
}

const tokenMap = allTokens[chainId]
return Object.values(tokenMap)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { ChainId } from '@pancakeswap/chains'
import { enumValues } from '@pancakeswap/utils/enumValues'
import { TokenAddressMap } from '@pancakeswap/token-lists'

export * from './getTokensByChain'

const createEmptyList = () => {
const list = {} as Record<ChainId, TokenAddressMap<ChainId>[ChainId]>
for (const chainId of enumValues(ChainId)) {
Expand Down
36 changes: 18 additions & 18 deletions packages/tokens/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
export * from './common'
export * from './constants/common'
export * from './helpers'
export * from './goerli'
export * from './bsc'
export * from './bscTestnet'
export * from './eth'
export * from './arb'
export * from './polygonZkEVM'
export * from './polygonZkEVMTestnet'
export * from './zkSync'
export * from './zkSyncTestnet'
export * from './lineaTestnet'
export * from './linea'
export * from './arbGoerli'
export * from './opBnbTestnet'
export * from './opBNB'
export * from './base'
export * from './baseTestnet'
export * from './scrollSepolia'
export * from './constants/goerli'
export * from './constants/bsc'
export * from './constants/bscTestnet'
export * from './constants/eth'
export * from './constants/arb'
export * from './constants/polygonZkEVM'
export * from './constants/polygonZkEVMTestnet'
export * from './constants/zkSync'
export * from './constants/zkSyncTestnet'
export * from './constants/lineaTestnet'
export * from './constants/linea'
export * from './constants/arbGoerli'
export * from './constants/opBnbTestnet'
export * from './constants/opBNB'
export * from './constants/base'
export * from './constants/baseTestnet'
export * from './constants/scrollSepolia'
Loading

0 comments on commit 83b1d93

Please sign in to comment.