Skip to content

Commit

Permalink
feat: v4 non-complex hooks routing (#916)
Browse files Browse the repository at this point in the history
we can support non-complex hooks routing, that we know have no effect during swaps.
  • Loading branch information
jsy1218 authored Nov 16, 2024
1 parent 75503d1 commit 106bd58
Show file tree
Hide file tree
Showing 5 changed files with 695 additions and 25 deletions.
12 changes: 2 additions & 10 deletions lib/cron/cache-pools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { AWSMetricsLogger } from '../handlers/router-entities/aws-metrics-logger
import { metricScope } from 'aws-embedded-metrics'
import * as zlib from 'zlib'
import dotenv from 'dotenv'
import { HOOKS_ADDRESSES_ALLOWLIST } from '../util/hooksAddressesAllowlist'
import { v4HooksPoolsFiltering } from '../util/v4HooksPoolsFiltering'

// Needed for local stack dev, not needed for staging or prod
// But it still doesn't work on the local cdk stack update,
Expand Down Expand Up @@ -224,15 +224,7 @@ const handler: ScheduledHandler = metricScope((metrics) => async (event: EventBr
}

if (protocol === Protocol.V4) {
pools = (pools as Array<V4SubgraphPool>).filter((pool: V4SubgraphPool) => {
const shouldFilterOut = !HOOKS_ADDRESSES_ALLOWLIST[chainId].includes(pool.hooks.toLowerCase())

if (shouldFilterOut) {
log.info(`Filtering out pool ${pool.id} from ${protocol} on ${chainId}`)
}

return !shouldFilterOut
})
pools = v4HooksPoolsFiltering(chainId, pools as Array<V4SubgraphPool>)
}

metric.putMetric(`${metricPrefix}.getPools.latency`, Date.now() - beforeGetPool)
Expand Down
63 changes: 63 additions & 0 deletions lib/util/v4HooksPoolsFiltering.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { V4SubgraphPool } from '@uniswap/smart-order-router'
import { Hook } from '@uniswap/v4-sdk'
import { HOOKS_ADDRESSES_ALLOWLIST } from './hooksAddressesAllowlist'
import { ChainId } from '@uniswap/sdk-core'
import { PriorityQueue } from '@datastructures-js/priority-queue'

type V4PoolGroupingKey = string
const TOP_GROUPED_V4_POOLS = 10

function convertV4PoolToGroupingKey(pool: V4SubgraphPool): V4PoolGroupingKey {
return pool.token0.id.concat(pool.token1.id).concat(pool.feeTier)
}

function isHooksPoolRoutable(pool: V4SubgraphPool): boolean {
return (
!Hook.hasSwapPermissions(pool.hooks) &&
// If the fee tier is smaller than or equal to 100%, it means the pool is not dynamic fee pool.
// Swap fee in total can be 100% (https://github.com/Uniswap/v4-core/blob/b619b6718e31aa5b4fa0286520c455ceb950276d/src/libraries/SwapMath.sol#L12)
// Dynamic fee is at 0x800000 or 838.8608% fee tier.
// Since pool manager doesn;t check the fee at 100% max during pool initialization (https://github.com/Uniswap/v4-core/blob/main/src/PoolManager.sol#L128)
// it's more defensive programming to ensure the fee tier is less than or equal to 100%
Number(pool.feeTier) <= 1000000
)
}

// it has to be a min heap in order to preserve the top eth tvl v4 pools
const V4SubgraphPoolComparator = (a: V4SubgraphPool, b: V4SubgraphPool) => {
return a.tvlETH > b.tvlETH ? 1 : -1
}

export function v4HooksPoolsFiltering(chainId: ChainId, pools: Array<V4SubgraphPool>): Array<V4SubgraphPool> {
const v4PoolsByTokenPairsAndFees: Record<V4PoolGroupingKey, PriorityQueue<V4SubgraphPool>> = {}

pools.forEach((pool: V4SubgraphPool) => {
if (isHooksPoolRoutable(pool)) {
const v4Pools =
v4PoolsByTokenPairsAndFees[convertV4PoolToGroupingKey(pool)] ??
new PriorityQueue<V4SubgraphPool>(V4SubgraphPoolComparator)

v4Pools.push(pool)

if (v4Pools.size() > TOP_GROUPED_V4_POOLS) {
v4Pools.dequeue()
}

v4PoolsByTokenPairsAndFees[pool.token0.id.concat(pool.token1.id).concat(pool.feeTier)] = v4Pools
}
})

const topTvlPools: Array<V4SubgraphPool> = []
Object.values(v4PoolsByTokenPairsAndFees).forEach((pq: PriorityQueue<V4SubgraphPool>) => {
topTvlPools.push(...pq.toArray())
})

const allowlistedHooksPools = pools.filter((pool: V4SubgraphPool) => {
return (
HOOKS_ADDRESSES_ALLOWLIST[chainId].includes(pool.hooks.toLowerCase()) &&
!topTvlPools.find((topPool: V4SubgraphPool) => topPool.id.toLowerCase() === pool.id.toLowerCase())
)
})

return topTvlPools.concat(allowlistedHooksPools)
}
43 changes: 30 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"typescript": "^4.2.3"
},
"dependencies": {
"@datastructures-js/priority-queue": "^6.3.1",
"@hapi/joi": "^17.1.1",
"@middy/core": "^2.4.1",
"@middy/http-error-handler": "^2.4.1",
Expand All @@ -80,20 +81,20 @@
"@types/async-retry": "^1.4.2",
"@types/chai-subset": "^1.3.3",
"@types/qs": "^6.9.7",
"@types/semver": "^7.5.8",
"@types/sinon": "^10.0.6",
"@types/stats-lite": "^2.2.0",
"@uniswap/default-token-list": "^11.13.0",
"@uniswap/permit2-sdk": "^1.3.0",
"@uniswap/router-sdk": "^1.14.0",
"@uniswap/sdk-core": "^5.9.0",
"@types/semver": "^7.5.8",
"@uniswap/smart-order-router": "4.8.0",
"@uniswap/token-lists": "^1.0.0-beta.33",
"@uniswap/universal-router-sdk": "^4.6.1",
"@uniswap/v2-sdk": "^4.6.1",
"@uniswap/v3-periphery": "^1.4.4",
"@uniswap/v3-sdk": "^3.17.1",
"@uniswap/v4-sdk": "^1.10.0",
"@uniswap/v4-sdk": "^1.11.2",
"async-retry": "^1.3.1",
"aws-cdk-lib": "^2.137.0",
"aws-embedded-metrics": "^2.0.6",
Expand Down
Loading

0 comments on commit 106bd58

Please sign in to comment.