Skip to content

Commit ffa90c2

Browse files
committed
Add VIRTUS Protocol DEX adapters for basic AMM and CL pools on Base
- dexs/virtus-protocol: basic AMM pools via PoolFactory - dexs/virtus-protocol-cl: concentrated liquidity pools via CLFactory
1 parent bbc1b02 commit ffa90c2

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed

dexs/virtus-protocol-cl/index.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types";
2+
import { CHAIN } from "../../helpers/chains";
3+
import { addOneToken } from '../../helpers/prices';
4+
5+
const CONFIG = {
6+
CLFactory: '0x0e5Ab24beBdA7e5Bb3961f7E9b3532a83aE86B48',
7+
fromBlock: 42960000,
8+
}
9+
10+
const swapEvent = 'event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick)'
11+
const poolCreatedEvent = 'event PoolCreated(address indexed token0, address indexed token1, int24 indexed tickSpacing, address pool)'
12+
13+
const fetch = async (fetchOptions: FetchOptions): Promise<FetchResult> => {
14+
const { api, createBalances, chain, getLogs } = fetchOptions
15+
const dailyVolume = createBalances()
16+
const dailyFees = createBalances()
17+
18+
const rawPools = await getLogs({
19+
target: CONFIG.CLFactory,
20+
fromBlock: CONFIG.fromBlock,
21+
eventAbi: poolCreatedEvent,
22+
cacheInCloud: true,
23+
skipIndexer: true,
24+
})
25+
26+
if (!rawPools?.length) return { dailyVolume, dailyFees }
27+
28+
const pools = rawPools.map((i: any) => i.pool.toLowerCase())
29+
const fees = await api.multiCall({ abi: 'uint256:fee', calls: pools, permitFailure: true })
30+
31+
const poolTokens: Record<string, [string, string]> = {}
32+
const poolFees: Record<string, number> = {}
33+
const validPools: string[] = []
34+
35+
rawPools.forEach(({ token0, token1, pool }: any, index: number) => {
36+
const p = pool.toLowerCase()
37+
const rawFee = fees[index]
38+
if (rawFee === null || rawFee === undefined) return;
39+
poolTokens[p] = [token0, token1]
40+
poolFees[p] = rawFee / 1e6
41+
validPools.push(p)
42+
})
43+
44+
if (!validPools.length) return { dailyVolume, dailyFees }
45+
46+
const allLogs = await getLogs({ targets: validPools, eventAbi: swapEvent, flatten: false })
47+
48+
allLogs.forEach((logs: any, index: number) => {
49+
if (!logs?.length) return;
50+
const pool = validPools[index]
51+
const [token0, token1] = poolTokens[pool]
52+
const fee = poolFees[pool]
53+
logs.forEach((log: any) => {
54+
const amount0 = Number(log.amount0)
55+
const amount1 = Number(log.amount1)
56+
addOneToken({ chain, balances: dailyVolume, token0, token1, amount0, amount1 })
57+
addOneToken({ chain, balances: dailyFees, token0, token1, amount0: amount0 * fee, amount1: amount1 * fee })
58+
})
59+
})
60+
61+
return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyHoldersRevenue: dailyFees }
62+
}
63+
64+
const adapters: SimpleAdapter = {
65+
version: 2,
66+
adapter: {
67+
[CHAIN.BASE]: {
68+
fetch: fetch as any,
69+
start: '2026-03-05',
70+
}
71+
}
72+
}
73+
74+
export default adapters

dexs/virtus-protocol/index.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { FetchOptions, FetchResult, SimpleAdapter } from "../../adapters/types";
2+
import { CHAIN } from "../../helpers/chains";
3+
import { addOneToken } from '../../helpers/prices';
4+
5+
const CONFIG = {
6+
PoolFactory: '0x7F03ae4452192b0E280fB0d4f9c225DDa88C7623',
7+
}
8+
9+
const swapEvent = 'event Swap(address indexed sender, address indexed to, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out)'
10+
11+
const factoryAbis = {
12+
allPoolsLength: 'uint256:allPoolsLength',
13+
allPools: 'function allPools(uint256) external view returns (address)',
14+
getFee: 'function getFee(address pool, bool _stable) external view returns (uint256)',
15+
}
16+
17+
const fetch = async (fetchOptions: FetchOptions): Promise<FetchResult> => {
18+
const { createBalances, api, chain, getLogs } = fetchOptions
19+
const dailyVolume = createBalances()
20+
const dailyFees = createBalances()
21+
22+
const poolCount = await api.call({ target: CONFIG.PoolFactory, abi: factoryAbis.allPoolsLength })
23+
if (!poolCount || Number(poolCount) === 0) return { dailyVolume, dailyFees }
24+
25+
const calls = []
26+
for (let i = 0; i < Number(poolCount); i++) {
27+
calls.push({ target: CONFIG.PoolFactory, params: [i] })
28+
}
29+
const pools: string[] = await api.multiCall({ abi: factoryAbis.allPools, calls })
30+
const token0s: string[] = await api.multiCall({ abi: 'address:token0', calls: pools })
31+
const token1s: string[] = await api.multiCall({ abi: 'address:token1', calls: pools })
32+
const stables: boolean[] = await api.multiCall({ abi: 'bool:stable', calls: pools, permitFailure: true })
33+
34+
const fees = await api.multiCall({
35+
abi: factoryAbis.getFee,
36+
target: CONFIG.PoolFactory,
37+
calls: pools.map((pool, i) => ({ params: [pool, stables[i] ?? false] })),
38+
permitFailure: true,
39+
})
40+
41+
const poolTokens: Record<string, [string, string]> = {}
42+
const poolFees: Record<string, number> = {}
43+
pools.forEach((pool, index) => {
44+
const p = pool.toLowerCase()
45+
poolTokens[p] = [token0s[index], token1s[index]]
46+
poolFees[p] = (fees[index] ?? 30) / 1e4
47+
})
48+
49+
const targets = pools.map(p => p.toLowerCase())
50+
const allLogs = await getLogs({ targets, eventAbi: swapEvent, flatten: false })
51+
52+
allLogs.forEach((logs: any, index: number) => {
53+
if (!logs?.length) return;
54+
const pool = targets[index]
55+
const [token0, token1] = poolTokens[pool]
56+
const fee = poolFees[pool]
57+
logs.forEach((log: any) => {
58+
const amount0 = Number(log.amount0In) + Number(log.amount0Out)
59+
const amount1 = Number(log.amount1In) + Number(log.amount1Out)
60+
addOneToken({ chain, balances: dailyVolume, token0, token1, amount0, amount1 })
61+
addOneToken({ chain, balances: dailyFees, token0, token1, amount0: amount0 * fee, amount1: amount1 * fee })
62+
})
63+
})
64+
65+
return { dailyVolume, dailyFees, dailyRevenue: dailyFees, dailyHoldersRevenue: dailyFees }
66+
}
67+
68+
const adapters: SimpleAdapter = {
69+
version: 2,
70+
adapter: {
71+
[CHAIN.BASE]: {
72+
fetch: fetch as any,
73+
start: '2026-03-05',
74+
}
75+
}
76+
}
77+
78+
export default adapters

0 commit comments

Comments
 (0)