Skip to content

Commit 62b0e1d

Browse files
committed
Add arbitrum beta
1 parent 935da9e commit 62b0e1d

6 files changed

+362
-5
lines changed

bin/check-config.ts

+283
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
import { groupBy } from "lodash"
2+
3+
type Hex = `0x${string}`
4+
5+
type BeefyVault = {
6+
id: string
7+
vault_address: Hex
8+
undelying_lp_address: Hex | undefined
9+
strategy_address: Hex
10+
vault_token_symbol: string
11+
chain: string
12+
reward_pools: BeefyRewardPool[]
13+
boosts: BeefyBoost[]
14+
pointStructureIds: string[]
15+
platformId: ApiPlatformId
16+
} & (
17+
| {
18+
protocol_type: "beefy_clm_vault"
19+
beefy_clm_manager: BeefyVault
20+
}
21+
| {
22+
protocol_type: Exclude<BeefyProtocolType, "beefy_clm_vault">
23+
}
24+
)
25+
26+
type BeefyRewardPool = {
27+
id: string
28+
clm_address: Hex
29+
reward_pool_address: Hex
30+
}
31+
32+
type BeefyBoost = {
33+
id: string
34+
boost_address: Hex
35+
underlying_address: Hex
36+
}
37+
38+
type BeefyProtocolType = "aave" | "balancer_aura" | "beefy_clm_vault" | "beefy_clm" | "curve" | "gamma" | "ichi" | "pendle_equilibria" | "solidly"
39+
40+
type ApiPlatformId =
41+
| "aerodrome"
42+
| "aura"
43+
| "beefy"
44+
| "curve"
45+
| "equilibria"
46+
| "gamma"
47+
| "ichi"
48+
| "lendle"
49+
| "lynex"
50+
| "magpie"
51+
| "mendi"
52+
| "nile"
53+
| "velodrome"
54+
55+
type ApiStrategyTypeId = "lp" | "multi-lp" | "multi-lp-locked" | "cowcentrated"
56+
57+
type ApiVault = {
58+
id: string
59+
name: string
60+
status: "active" | "eol"
61+
earnedTokenAddress: string
62+
depositTokenAddresses?: string[]
63+
chain: string
64+
platformId: ApiPlatformId
65+
token: string
66+
tokenAddress?: string
67+
earnedToken: string
68+
isGovVault?: boolean
69+
strategyTypeId?: ApiStrategyTypeId
70+
bridged?: object
71+
assets?: string[]
72+
strategy: Hex
73+
pointStructureIds?: string[]
74+
}
75+
76+
type ApiClmManager = {
77+
id: string
78+
name: string
79+
status: "active" | "eol"
80+
version: number
81+
platformId: ApiPlatformId
82+
strategyTypeId?: ApiStrategyTypeId
83+
earnedToken: string
84+
strategy: string
85+
chain: string
86+
type: "cowcentrated" | "others"
87+
tokenAddress: string // underlying pool address
88+
depositTokenAddresses: string[] // token0 and token1
89+
earnContractAddress: string // reward pool address
90+
earnedTokenAddress: string // clm manager address
91+
pointStructureIds?: string[]
92+
}
93+
94+
type ApiClmRewardPool = {
95+
id: string
96+
status: "active" | "eol"
97+
version: number
98+
platformId: ApiPlatformId
99+
strategyTypeId?: ApiStrategyTypeId
100+
chain: string
101+
tokenAddress: string // clm address (want)
102+
earnContractAddress: string // reward pool address
103+
earnedTokenAddresses: string[] // reward tokens
104+
}
105+
106+
type ApiGovVault = {
107+
id: string
108+
status: "active" | "eol"
109+
version: number
110+
chain: string
111+
tokenAddress: string // clm address
112+
earnContractAddress: string // reward pool address
113+
earnedTokenAddresses: string[]
114+
}
115+
116+
type ApiBoost = {
117+
id: string
118+
poolId: string
119+
120+
version: number
121+
chain: string
122+
status: "active" | "eol"
123+
124+
tokenAddress: string // underlying
125+
earnedTokenAddress: string // reward token address
126+
earnContractAddress: string // reward pool address
127+
}
128+
129+
const protocol_map: Record<ApiPlatformId, BeefyProtocolType> = {
130+
aerodrome: "solidly",
131+
aura: "balancer_aura",
132+
beefy: "beefy_clm",
133+
curve: "curve",
134+
equilibria: "pendle_equilibria",
135+
gamma: "gamma",
136+
ichi: "ichi",
137+
lendle: "aave",
138+
lynex: "solidly",
139+
magpie: "pendle_equilibria",
140+
mendi: "aave",
141+
nile: "solidly",
142+
velodrome: "solidly",
143+
}
144+
145+
type ApiHolderCount = {
146+
chain: string
147+
token_address: Hex
148+
holder_count: number
149+
}
150+
151+
async function main() {
152+
const [holderCountsData, cowVaultsData, mooVaultsData, clmRewardPoolData, [boostData, vaultRewardPoolData]] = await Promise.all([
153+
fetch(`https://balance-api.beefy.finance/api/v1/holders/counts/all`)
154+
.then((res) => res.json())
155+
.then((res) => res as ApiHolderCount[]),
156+
fetch(`https://api.beefy.finance/cow-vaults`)
157+
.then((res) => res.json())
158+
.then((res) => res as ApiClmManager[]),
159+
fetch(`https://api.beefy.finance/vaults`)
160+
.then((res) => res.json())
161+
.then((res) => res as ApiVault[]),
162+
fetch(`https://api.beefy.finance/gov-vaults`)
163+
.then((res) => res.json())
164+
.then((res) => res as ApiClmRewardPool[]),
165+
fetch(`https://api.beefy.finance/boosts`)
166+
.then((res) => res.json())
167+
.then((res) => [(res as ApiBoost[]).filter((g) => g.version !== 2), (res as ApiBoost[]).filter((g) => g.version === 2)] as const),
168+
])
169+
170+
const clmManagerAddresses = new Set(cowVaultsData.map((v) => v.earnedTokenAddress.toLocaleLowerCase()))
171+
const boostPerUnderlyingAddress = groupBy(boostData, (b) => b.tokenAddress?.toLocaleLowerCase())
172+
const vaultRewardPoolDataPerVaultAddress = groupBy(vaultRewardPoolData, (v) => v.tokenAddress.toLocaleLowerCase())
173+
const clmRewardPoolDataPerClmAddress = groupBy(clmRewardPoolData, (c) => c.tokenAddress.toLocaleLowerCase())
174+
175+
const clmVaultConfigs = cowVaultsData.map((vault): BeefyVault => {
176+
const undelying_lp_address = vault.tokenAddress.toLocaleLowerCase() as Hex
177+
const vault_address = vault.earnedTokenAddress.toLocaleLowerCase() as Hex
178+
179+
const protocol_type: BeefyProtocolType | undefined = vault.type === "cowcentrated" ? "beefy_clm" : protocol_map[vault.platformId]
180+
if (protocol_type === "beefy_clm_vault") {
181+
throw new Error("Invalid protocol")
182+
}
183+
const reward_pools = clmRewardPoolDataPerClmAddress[vault_address] ?? []
184+
185+
const boosts = boostPerUnderlyingAddress[vault_address] ?? []
186+
187+
return {
188+
id: vault.id,
189+
vault_address,
190+
chain: vault.chain,
191+
vault_token_symbol: vault.earnedToken,
192+
protocol_type,
193+
platformId: vault.platformId,
194+
strategy_address: vault.strategy.toLocaleLowerCase() as Hex,
195+
undelying_lp_address,
196+
reward_pools: reward_pools.map((pool) => ({
197+
id: pool.id,
198+
clm_address: pool.tokenAddress.toLocaleLowerCase() as Hex,
199+
reward_pool_address: pool.earnContractAddress.toLocaleLowerCase() as Hex,
200+
})),
201+
boosts: boosts.map((boost) => ({
202+
id: boost.id,
203+
boost_address: boost.earnedTokenAddress.toLocaleLowerCase() as Hex,
204+
underlying_address: boost.tokenAddress.toLocaleLowerCase() as Hex,
205+
})),
206+
pointStructureIds: vault.pointStructureIds ?? [],
207+
}
208+
})
209+
210+
const mooVaultCofigs = mooVaultsData.map((vault): BeefyVault => {
211+
let underlying_lp_address = vault.tokenAddress?.toLocaleLowerCase() as Hex | undefined
212+
const vault_address = vault.earnedTokenAddress.toLocaleLowerCase() as Hex
213+
214+
const protocol_type: BeefyProtocolType | undefined =
215+
underlying_lp_address && clmManagerAddresses.has(underlying_lp_address) ? "beefy_clm_vault" : protocol_map[vault.platformId]
216+
217+
const additionalConfig =
218+
protocol_type === "beefy_clm_vault"
219+
? {
220+
protocol_type,
221+
platformId: vault.platformId,
222+
beefy_clm_manager: clmVaultConfigs.find((v) => v.vault_address === underlying_lp_address) as BeefyVault,
223+
}
224+
: { protocol_type, platformId: vault.platformId }
225+
const reward_pools = vaultRewardPoolDataPerVaultAddress[vault_address] ?? []
226+
const boosts = boostPerUnderlyingAddress[vault_address] ?? []
227+
return {
228+
id: vault.id,
229+
vault_address,
230+
chain: vault.chain,
231+
vault_token_symbol: vault.earnedToken,
232+
...additionalConfig,
233+
strategy_address: vault.strategy.toLocaleLowerCase() as Hex,
234+
undelying_lp_address: underlying_lp_address,
235+
reward_pools: reward_pools.map((pool) => ({
236+
id: pool.id,
237+
clm_address: pool.tokenAddress.toLocaleLowerCase() as Hex,
238+
reward_pool_address: pool.earnContractAddress.toLocaleLowerCase() as Hex,
239+
})),
240+
boosts: boosts.map((boost) => ({
241+
id: boost.id,
242+
boost_address: boost.earnedTokenAddress.toLocaleLowerCase() as Hex,
243+
underlying_address: boost.tokenAddress.toLocaleLowerCase() as Hex,
244+
})),
245+
pointStructureIds: vault.pointStructureIds ?? [],
246+
}
247+
})
248+
249+
const allConfigs = clmVaultConfigs.concat(mooVaultCofigs)
250+
251+
const countsPerToken = holderCountsData.reduce(
252+
(acc, { chain, token_address, holder_count }) => {
253+
const key = `${chain}:${token_address}`
254+
acc[key] = holder_count
255+
return acc
256+
},
257+
{} as Record<string, number>,
258+
)
259+
260+
// check for missing holder counts
261+
for (const vault of allConfigs) {
262+
if (!countsPerToken[`${vault.chain}:${vault.vault_address}`]) {
263+
console.error(`ERROR: Missing holder count for ${vault.id} with address ${vault.chain}:${vault.vault_address}`)
264+
}
265+
if (vault.protocol_type === "beefy_clm_vault") {
266+
if (!countsPerToken[`${vault.chain}:${vault.beefy_clm_manager.vault_address}`]) {
267+
console.error(`ERROR: Missing holder count for ${vault.id} with CLM address ${vault.chain}:${vault.beefy_clm_manager.vault_address}`)
268+
}
269+
}
270+
for (const pool of vault.reward_pools) {
271+
if (!countsPerToken[`${vault.chain}:${pool.clm_address}`]) {
272+
console.error(`ERROR: Missing holder count for ${vault.id}'s Reward Pool with address ${vault.chain}:${pool.clm_address}`)
273+
}
274+
}
275+
for (const boost of vault.boosts) {
276+
if (!countsPerToken[`${vault.chain}:${boost.underlying_address}`]) {
277+
console.error(`ERROR: Missing holder count for ${vault.id}'s BOOST with address ${vault.chain}:${boost.underlying_address}`)
278+
}
279+
}
280+
}
281+
}
282+
283+
main()

config/arbitrum.json

+11
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,16 @@
1414
"beefyClassicBoostFactoryAddress": "0x2951c806a75b19954ce0bed477676a54f3c1c200",
1515
"beefyClassicBoostFactoryStartBlock": 131261823,
1616

17+
"clmManagerFactoryAddress_2": "0xB45B92C318277d57328fE09DD5cF6Bd53F4F269B",
18+
"clmManagerFactoryStartBlock_2": 198239651,
19+
"clmStrategyFactoryAddress_2": "0xB37c7C935CcE547Eb858Fc8F2d8C3B48597f4aE9",
20+
"clmStrategyFactoryStartBlock_2": 197959279,
21+
"rewardPoolFactoryAddress_2": "0x26eb26e0aadd5fa70331219c5cec0166114ce71e",
22+
"rewardPoolFactoryStartBlock_2": 206875840,
23+
"beefyClassicVaultFactoryAddress_2": "0x8396f3d25d07531a80770ce3dea025932c4953f7",
24+
"beefyClassicVaultFactoryStartBlock_2": 197959279,
25+
"beefyClassicBoostFactoryAddress_2": "0x2951c806a75b19954ce0bed477676a54f3c1c200",
26+
"beefyClassicBoostFactoryStartBlock_2": 197959279,
27+
1728
"vaultInitializedEvent": "Initialized(uint8)"
1829
}

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"test": "yarn run --silent test:lint && yarn run --silent test:unit",
1010
"test:unit": "echo 'No unit tests defined'",
1111
"test:lint": "prettier . --check",
12+
"test:config": "ts-node --project tsconfig.scripts.json ./bin/check-config.ts",
1213
"infra:start": "docker compose up -d",
1314
"infra:stop": "docker compose down",
1415
"create-local": "graph create beefyfinance/local --node http://127.0.0.1:8020",
@@ -37,9 +38,11 @@
3738
"devDependencies": {
3839
"@graphprotocol/graph-cli": "^0.69.2",
3940
"@graphprotocol/graph-ts": "^0.34.0",
41+
"@types/lodash": "^4.17.7",
4042
"assemblyscript-prettier": "^3.0.1",
4143
"husky": ">=7",
4244
"lint-staged": ">=10",
45+
"lodash": "^4.17.21",
4346
"matchstick-as": "^0.6.0",
4447
"mustache": "^4.2.0",
4548
"prettier": "^3.2.5",

0 commit comments

Comments
 (0)