@stake-dao/reader 0.5.14 → 0.5.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/esm/bytecodes/index.js +1 -0
  2. package/dist/esm/bytecodes/index.js.map +1 -1
  3. package/dist/esm/bytecodes/strategies/batches/batchBalancerStrats.js +1 -1
  4. package/dist/esm/bytecodes/strategies/batches/batchBalancerStrats.js.map +1 -1
  5. package/dist/esm/bytecodes/votemarket/batchDirectIncentives.js +17 -0
  6. package/dist/esm/bytecodes/votemarket/batchDirectIncentives.js.map +1 -0
  7. package/dist/esm/index.js +5 -1
  8. package/dist/esm/index.js.map +1 -1
  9. package/dist/esm/lockers/fetch/protocols/balancer.js +2 -0
  10. package/dist/esm/lockers/fetch/protocols/balancer.js.map +1 -1
  11. package/dist/esm/lockers/fetch/protocols/blackpool.js +2 -0
  12. package/dist/esm/lockers/fetch/protocols/blackpool.js.map +1 -1
  13. package/dist/esm/lockers/fetch/protocols/curve.js +2 -0
  14. package/dist/esm/lockers/fetch/protocols/curve.js.map +1 -1
  15. package/dist/esm/lockers/fetch/protocols/frax-fxs.js +2 -0
  16. package/dist/esm/lockers/fetch/protocols/frax-fxs.js.map +1 -1
  17. package/dist/esm/lockers/fetch/protocols/fxn.js +2 -0
  18. package/dist/esm/lockers/fetch/protocols/fxn.js.map +1 -1
  19. package/dist/esm/lockers/fetch/protocols/maverick.js +2 -0
  20. package/dist/esm/lockers/fetch/protocols/maverick.js.map +1 -1
  21. package/dist/esm/lockers/fetch/protocols/pendle.js +2 -0
  22. package/dist/esm/lockers/fetch/protocols/pendle.js.map +1 -1
  23. package/dist/esm/lockers/fetch/protocols/spectra.js +2 -0
  24. package/dist/esm/lockers/fetch/protocols/spectra.js.map +1 -1
  25. package/dist/esm/lockers/fetch/protocols/yearn.js +2 -0
  26. package/dist/esm/lockers/fetch/protocols/yearn.js.map +1 -1
  27. package/dist/esm/lockers/fetch/protocols/yieldbasis.js +2 -0
  28. package/dist/esm/lockers/fetch/protocols/yieldbasis.js.map +1 -1
  29. package/dist/esm/lockers/fetch/protocols/yieldnest.js +2 -0
  30. package/dist/esm/lockers/fetch/protocols/yieldnest.js.map +1 -1
  31. package/dist/esm/lockers/fetch/protocols/zerolend.js +2 -0
  32. package/dist/esm/lockers/fetch/protocols/zerolend.js.map +1 -1
  33. package/dist/esm/prices.js +178 -85
  34. package/dist/esm/prices.js.map +1 -1
  35. package/dist/esm/strategies/balancer/fetch.js +3 -21
  36. package/dist/esm/strategies/balancer/fetch.js.map +1 -1
  37. package/dist/esm/strategies/v2/parse.js +196 -183
  38. package/dist/esm/strategies/v2/parse.js.map +1 -1
  39. package/dist/esm/votemarket/balancer/fetchUserVlAuraClaimable.js +96 -0
  40. package/dist/esm/votemarket/balancer/fetchUserVlAuraClaimable.js.map +1 -0
  41. package/dist/esm/votemarket/fetchDirectIncentives.js +20 -0
  42. package/dist/esm/votemarket/fetchDirectIncentives.js.map +1 -0
  43. package/dist/types/bytecodes/index.d.ts +1 -0
  44. package/dist/types/bytecodes/index.d.ts.map +1 -1
  45. package/dist/types/bytecodes/votemarket/batchDirectIncentives.d.ts +4 -0
  46. package/dist/types/bytecodes/votemarket/batchDirectIncentives.d.ts.map +1 -0
  47. package/dist/types/index.d.ts +3 -1
  48. package/dist/types/index.d.ts.map +1 -1
  49. package/dist/types/lockers/fetch/protocols/balancer.d.ts.map +1 -1
  50. package/dist/types/lockers/fetch/protocols/blackpool.d.ts.map +1 -1
  51. package/dist/types/lockers/fetch/protocols/curve.d.ts.map +1 -1
  52. package/dist/types/lockers/fetch/protocols/frax-fxs.d.ts.map +1 -1
  53. package/dist/types/lockers/fetch/protocols/fxn.d.ts.map +1 -1
  54. package/dist/types/lockers/fetch/protocols/maverick.d.ts.map +1 -1
  55. package/dist/types/lockers/fetch/protocols/pendle.d.ts.map +1 -1
  56. package/dist/types/lockers/fetch/protocols/spectra.d.ts.map +1 -1
  57. package/dist/types/lockers/fetch/protocols/yearn.d.ts.map +1 -1
  58. package/dist/types/lockers/fetch/protocols/yieldbasis.d.ts.map +1 -1
  59. package/dist/types/lockers/fetch/protocols/yieldnest.d.ts.map +1 -1
  60. package/dist/types/lockers/fetch/protocols/zerolend.d.ts.map +1 -1
  61. package/dist/types/lockers/fetch/types.d.ts +2 -0
  62. package/dist/types/lockers/fetch/types.d.ts.map +1 -1
  63. package/dist/types/prices.d.ts +17 -5
  64. package/dist/types/prices.d.ts.map +1 -1
  65. package/dist/types/strategies/balancer/fetch.d.ts +1 -2
  66. package/dist/types/strategies/balancer/fetch.d.ts.map +1 -1
  67. package/dist/types/strategies/v2/parse.d.ts +1 -51
  68. package/dist/types/strategies/v2/parse.d.ts.map +1 -1
  69. package/dist/types/votemarket/balancer/fetchUserVlAuraClaimable.d.ts +19 -0
  70. package/dist/types/votemarket/balancer/fetchUserVlAuraClaimable.d.ts.map +1 -0
  71. package/dist/types/votemarket/fetchDirectIncentives.d.ts +2 -0
  72. package/dist/types/votemarket/fetchDirectIncentives.d.ts.map +1 -0
  73. package/package.json +2 -2
  74. package/src/bytecodes/index.ts +3 -0
  75. package/src/bytecodes/strategies/batches/batchBalancerStrats.ts +1 -1
  76. package/src/bytecodes/votemarket/batchDirectIncentives.ts +21 -0
  77. package/src/index.ts +8 -1
  78. package/src/lockers/fetch/protocols/balancer.ts +2 -0
  79. package/src/lockers/fetch/protocols/blackpool.ts +2 -0
  80. package/src/lockers/fetch/protocols/curve.ts +2 -0
  81. package/src/lockers/fetch/protocols/frax-fxs.ts +2 -0
  82. package/src/lockers/fetch/protocols/fxn.ts +2 -0
  83. package/src/lockers/fetch/protocols/maverick.ts +2 -0
  84. package/src/lockers/fetch/protocols/pendle.ts +2 -0
  85. package/src/lockers/fetch/protocols/spectra.ts +2 -0
  86. package/src/lockers/fetch/protocols/yearn.ts +2 -0
  87. package/src/lockers/fetch/protocols/yieldbasis.ts +2 -0
  88. package/src/lockers/fetch/protocols/yieldnest.ts +2 -0
  89. package/src/lockers/fetch/protocols/zerolend.ts +2 -0
  90. package/src/lockers/fetch/types.ts +2 -0
  91. package/src/prices.ts +206 -92
  92. package/src/strategies/balancer/fetch.ts +3 -31
  93. package/src/strategies/v2/parse.ts +234 -217
  94. package/src/votemarket/balancer/fetchUserVlAuraClaimable.ts +159 -0
  95. package/src/votemarket/fetchDirectIncentives.ts +23 -0
@@ -38,237 +38,254 @@ const baseTokens = {
38
38
  },
39
39
  }
40
40
 
41
+ const protocols = {
42
+ '0xc715e373': 'curve',
43
+ }
44
+
45
+ const SUPPORTED_PROTOCOLS = Object.keys(protocols)
46
+
41
47
  export const parseV2Strats = (global: any, rawStrats: any[], extra: any) => {
42
48
  try {
43
- return rawStrats.map((s) => {
44
- const isLending = s.asset.name.startsWith('Llamalend')
45
-
46
- const lpToken = parseAsset(s.asset)
47
- const coins = s.asset.components.map((c) => parseAsset(c.childAsset))
48
-
49
- let name = coins.map((c) => c.symbol).join('/')
50
- if (name.length > 26 || lpToken?.name?.startsWith('CrossCurve')) name = lpToken.symbol
51
- if (isLending) name = s.asset.name
52
-
53
- const lpPriceInUsd =
54
- Number(s.gauge.totalSupply) > 0
55
- ? Number(s.gauge.totalSupplyUSD) / Number(formatUnits(BigInt(s.gauge.totalSupply || '0'), 18))
56
- : 0
57
-
58
- const compoundedYieldKey = isLending ? 'LENDING_INTEREST' : 'TRADING_FEES'
59
- const tradingApy = (s.gauge.aprDetails.find((el) => el.yieldType === compoundedYieldKey)?.aprUSD || 0) * 100
60
- const otherRewards = s.gauge.aprDetails.filter((el) => el.yieldType !== compoundedYieldKey && el.asset)
61
- const merklRewards = (extra?.merklApi || [])
62
- .filter((r) => equalTlc(r.explorerAddress, lpToken?.address))
63
- .map((r) => ({
64
- token: parseAsset(r.rewardsRecord.breakdowns[0]?.token),
65
- aprInToken: r.apr / r.rewardsRecord.breakdowns[0]?.token.price || 1,
66
- apr: r.apr,
67
- streaming: true,
68
- periodFinish: 2000000000,
69
- yieldType: 'OFFCHAIN',
70
- }))
71
-
72
- // Compute rewards from the hook incentive (Votemarket)
73
- const hookIncentivesPrices = extra?.hookIncentivesPrices || []
74
- const gaugeUsd = Number(s.gauge.totalSupplyUSD)
75
-
76
- const incentivesByToken = (extra?.hookIncentives || [])
77
- .filter((r) => equalTlc(r.vault, s.address))
78
- .reduce((acc, r) => {
79
- const rewardAddress = r.reward
80
- const price = hookIncentivesPrices.find((p) => equalTlc(rewardAddress, p.address))?.usdPrice || 0
81
-
82
- const amountToken = Number.parseFloat(formatUnits(r.amount, r.rewardDecimals))
83
- const duration = Number.parseInt(r.end) - Number.parseInt(r.start)
84
-
85
- if (duration <= 0) return acc
86
-
87
- const tokensPerSecond = amountToken / duration
88
- const yearlyTokens = tokensPerSecond * ONE_YEAR
89
- const yearlyRewardsUsd = yearlyTokens * price
90
-
91
- if (!acc[rewardAddress]) {
92
- acc[rewardAddress] = {
93
- meta: r,
94
- price: price,
95
- totalYearlyUsd: 0,
96
- maxPeriodFinish: Number.parseInt(r.end),
49
+ const res: any[] = []
50
+
51
+ for (const s of rawStrats) {
52
+ if (SUPPORTED_PROTOCOLS.includes(s.protocolId)) {
53
+ const protocol = protocols[s.protocolId]
54
+ const isLending = s.asset.name.startsWith('Llamalend')
55
+
56
+ const lpToken = parseAsset(s.asset)
57
+ const coins = s.asset.components.map((c) => parseAsset(c.childAsset))
58
+
59
+ let name = coins.map((c) => c.symbol).join('/')
60
+ if (name.length > 26 || lpToken?.name?.startsWith('CrossCurve')) name = lpToken.symbol
61
+ if (isLending) name = s.asset.name
62
+
63
+ const lpPriceInUsd =
64
+ Number(s.gauge.totalSupply) > 0
65
+ ? Number(s.gauge.totalSupplyUSD) / Number(formatUnits(BigInt(s.gauge.totalSupply || '0'), 18))
66
+ : 0
67
+
68
+ const compoundedYieldKey = isLending ? 'LENDING_INTEREST' : 'TRADING_FEES'
69
+ const tradingApy = (s.gauge.aprDetails.find((el) => el.yieldType === compoundedYieldKey)?.aprUSD || 0) * 100
70
+ const otherRewards = s.gauge.aprDetails.filter((el) => el.yieldType !== compoundedYieldKey && el.asset)
71
+ const merklRewards = (extra?.merklApi || [])
72
+ .filter((r) => equalTlc(r.explorerAddress, lpToken?.address))
73
+ .map((r) => ({
74
+ token: parseAsset(r.rewardsRecord.breakdowns[0]?.token),
75
+ aprInToken: r.apr / r.rewardsRecord.breakdowns[0]?.token.price || 1,
76
+ apr: r.apr,
77
+ streaming: true,
78
+ periodFinish: 2000000000,
79
+ yieldType: 'OFFCHAIN',
80
+ }))
81
+
82
+ // Compute rewards from the hook incentive (Votemarket)
83
+ const hookIncentivesPrices = extra?.baseRewardsPrices || []
84
+ const gaugeUsd = Number(s.gauge.totalSupplyUSD)
85
+
86
+ const incentivesByToken = (extra?.hookIncentives || [])
87
+ .filter((r) => equalTlc(r.vault, s.address))
88
+ .reduce((acc, r) => {
89
+ const rewardAddress = r.reward
90
+ const price = hookIncentivesPrices.find((p) => equalTlc(rewardAddress, p.address))?.usdPrice || 0
91
+
92
+ const amountToken = Number.parseFloat(formatUnits(r.amount, r.rewardDecimals))
93
+ const duration = Number.parseInt(r.end) - Number.parseInt(r.start)
94
+
95
+ if (duration <= 0) return acc
96
+
97
+ const tokensPerSecond = amountToken / duration
98
+ const yearlyTokens = tokensPerSecond * ONE_YEAR
99
+ const yearlyRewardsUsd = yearlyTokens * price
100
+
101
+ if (!acc[rewardAddress]) {
102
+ acc[rewardAddress] = {
103
+ meta: r,
104
+ price: price,
105
+ totalYearlyUsd: 0,
106
+ maxPeriodFinish: Number.parseInt(r.end),
107
+ }
97
108
  }
98
- }
99
109
 
100
- acc[rewardAddress].totalYearlyUsd += yearlyRewardsUsd
101
- acc[rewardAddress].maxPeriodFinish = Math.max(acc[rewardAddress].maxPeriodFinish, Number.parseInt(r.end))
110
+ acc[rewardAddress].totalYearlyUsd += yearlyRewardsUsd
111
+ acc[rewardAddress].maxPeriodFinish = Math.max(acc[rewardAddress].maxPeriodFinish, Number.parseInt(r.end))
102
112
 
103
- return acc
104
- }, {})
113
+ return acc
114
+ }, {})
105
115
 
106
- const hookIncentives = Object.values(incentivesByToken).map((group: any) => {
107
- const { meta, price, totalYearlyUsd, maxPeriodFinish } = group
116
+ const hookIncentives = Object.values(incentivesByToken).map((group: any) => {
117
+ const { meta, price, totalYearlyUsd, maxPeriodFinish } = group
108
118
 
109
- const apr = gaugeUsd > 0 ? (totalYearlyUsd / gaugeUsd) * 100 : 0
110
-
111
- return {
112
- token: parseAsset({
113
- id: meta.id.toString(),
114
- name: meta.rewardSymbol,
115
- symbol: meta.rewardSymbol,
116
- address: meta.reward,
117
- decimals: meta.rewardDecimals,
118
- }),
119
- aprInToken: price > 0 ? apr / price : 0,
120
- apr,
121
- streaming: true,
122
- periodFinish: maxPeriodFinish,
123
- yieldType: 'VOTEMARKET',
124
- }
125
- })
126
-
127
- const rewards = otherRewards
128
- .map((r) => ({
129
- token: parseAsset(r.asset),
130
- aprInToken: r.apr,
131
- apr: Number(r.aprUSD) * 100,
132
- streaming: true,
133
- periodFinish: 2000000000,
134
- yieldType: r.yieldType,
135
- }))
136
- .concat(merklRewards)
137
- .concat(hookIncentives)
138
- .sort((a, b) => {
139
- if (a.token.address === baseTokens.curve[s.chainId]) return -1
140
- if (b.token.address === baseTokens.curve[s.chainId]) return 1
141
- return 0
119
+ let _gaugeUsd = gaugeUsd
120
+ if (_gaugeUsd === 0) {
121
+ _gaugeUsd = 10_000
122
+ }
123
+ const apr = _gaugeUsd > 0 ? (totalYearlyUsd / _gaugeUsd) * 100 : 0
124
+
125
+ return {
126
+ token: parseAsset({
127
+ id: meta.id.toString(),
128
+ name: meta.rewardSymbol,
129
+ symbol: meta.rewardSymbol,
130
+ address: meta.reward,
131
+ decimals: meta.rewardDecimals,
132
+ }),
133
+ aprInToken: price > 0 ? apr / price : 0,
134
+ apr,
135
+ streaming: true,
136
+ periodFinish: maxPeriodFinish,
137
+ yieldType: 'VOTEMARKET',
138
+ }
142
139
  })
143
140
 
144
- const metadata: any = {}
145
- for (const m of s.gauge.metadata) metadata[m.key] = m.value
146
-
147
- // Current
148
- const totalSupply = BigInt(s.totalSupply)
149
- const convexSupply = BigInt(s.sidecarBalance)
150
- const stakeDaoSupply = totalSupply - convexSupply
151
-
152
- // Optimal
153
- const stakeDaoOptSupply =
154
- totalSupply > BigInt(metadata.optimalDepositBalance || '0')
155
- ? BigInt(metadata.optimalDepositBalance || '0')
156
- : totalSupply
157
- const convexOptSupply = totalSupply - stakeDaoOptSupply
158
-
159
- const useVeBoost = s.chainId === mainnet.id && s.gauge?.address !== '0xd8b712d29381748dB89c36BCa0138d7c75866ddF' // MIM/3crv
160
-
161
- const baseReward = rewards.find(
162
- (r) => r.yieldType === 'STAKING_REWARDS' && equalTlc(r.token.address, baseTokens.curve[s.chainId]),
163
- )
164
- const baseRewardPrice =
165
- extra.baseRewardsPrices.find((r) => equalTlc(r.address, baseTokens.curve[s.chainId]))?.usdPrice || 0
166
- const maxApr = baseReward?.apr || 0
167
-
168
- const onlyboost = getOnlyboostData(
169
- {
170
- active: s.sidecar !== zeroAddress,
171
- convexImpl: s.sidecar,
172
- totalSupply,
173
- convexSupply,
174
- stakeDaoSupply,
175
- convexStrategyHoldings: BigInt(metadata.convexTotalSupply || '0'),
176
- convexWorkingBalance: BigInt(metadata.workingBalanceConvex || '0'),
177
- convexRewardRate: BigInt(metadata.convexRewardRate || '0'),
178
- convexOptSupply,
179
- stakeDaoOptSupply,
180
- claimableData: [],
181
- },
182
- s.chainId,
183
- global[useVeBoost ? 'stakeDaoVeBoost' : 'stakeDaoVeBalance'],
184
- global[useVeBoost ? 'convexVeBoost' : 'convexVeBalance'],
185
- global.veCrvTotalSupply,
186
- BigInt(s.gauge.totalSupply),
187
- stakeDaoSupply,
188
- BigInt(metadata.workingBalance || '0'),
189
- totalSupply,
190
- lpPriceInUsd,
191
- maxApr,
192
- baseRewardPrice,
193
- )
194
-
195
- const boost = onlyboost.boost
196
- const baseRewardApr = (maxApr / 2.5) * boost * ((100 - V2_FEES) / 100)
197
-
198
- let baseRewardAdded = false
199
- const aprDetails = [{ label: isLending ? 'Lending' : 'Trading Fees (APY)', value: [tradingApy] }]
200
-
201
- for (const r of rewards) {
202
- if (
203
- baseReward &&
204
- r.yieldType === 'STAKING_REWARDS' &&
205
- r.token.symbol === baseReward.token.symbol &&
206
- !baseRewardAdded
207
- ) {
208
- aprDetails.push({
209
- label: `${r.token.symbol} APR (incl. ${withTwoDec(boost)}x boost)`,
210
- value: [baseRewardApr || 0],
141
+ const rewards = otherRewards
142
+ .map((r) => ({
143
+ token: parseAsset(r.asset),
144
+ aprInToken: r.apr,
145
+ apr: Number(r.aprUSD) * 100,
146
+ streaming: true,
147
+ periodFinish: 2000000000,
148
+ yieldType: r.yieldType,
149
+ }))
150
+ .concat(merklRewards)
151
+ .concat(hookIncentives)
152
+ .sort((a, b) => {
153
+ if (a.token.address === baseTokens[protocol][s.chainId]) return -1
154
+ if (b.token.address === baseTokens[protocol][s.chainId]) return 1
155
+ return 0
211
156
  })
212
157
 
213
- baseRewardAdded = true
214
- } else {
215
- const label =
216
- r.yieldType === 'VOTEMARKET'
217
- ? `${r.token.symbol} APR (Extra Rewards from Votemarket)`
218
- : `${r.token.symbol} APR`
219
- aprDetails.push({ label, value: [r.apr || 0] })
158
+ const metadata: any = {}
159
+ for (const m of s.gauge.metadata) metadata[m.key] = m.value
160
+
161
+ // Current
162
+ const totalSupply = BigInt(s.totalSupply)
163
+ const convexSupply = BigInt(s.sidecarBalance)
164
+ const stakeDaoSupply = totalSupply - convexSupply
165
+
166
+ // Optimal
167
+ const stakeDaoOptSupply =
168
+ totalSupply > BigInt(metadata.optimalDepositBalance || '0')
169
+ ? BigInt(metadata.optimalDepositBalance || '0')
170
+ : totalSupply
171
+ const convexOptSupply = totalSupply - stakeDaoOptSupply
172
+
173
+ const useVeBoost = s.chainId === mainnet.id && s.gauge?.address !== '0xd8b712d29381748dB89c36BCa0138d7c75866ddF' // MIM/3crv
174
+
175
+ const baseReward = rewards.find(
176
+ (r) => r.yieldType === 'STAKING_REWARDS' && equalTlc(r.token.address, baseTokens[protocol][s.chainId]),
177
+ )
178
+ const baseRewardPrice =
179
+ extra.baseRewardsPrices.find((r) => equalTlc(r.address, baseTokens[protocol][s.chainId]))?.usdPrice || 0
180
+ const maxApr = baseReward?.apr || 0
181
+
182
+ const onlyboost = getOnlyboostData(
183
+ {
184
+ active: s.sidecar !== zeroAddress,
185
+ convexImpl: s.sidecar,
186
+ totalSupply,
187
+ convexSupply,
188
+ stakeDaoSupply,
189
+ convexStrategyHoldings: BigInt(metadata.convexTotalSupply || '0'),
190
+ convexWorkingBalance: BigInt(metadata.workingBalanceConvex || '0'),
191
+ convexRewardRate: BigInt(metadata.convexRewardRate || '0'),
192
+ convexOptSupply,
193
+ stakeDaoOptSupply,
194
+ claimableData: [],
195
+ },
196
+ s.chainId,
197
+ global[useVeBoost ? 'stakeDaoVeBoost' : 'stakeDaoVeBalance'],
198
+ global[useVeBoost ? 'convexVeBoost' : 'convexVeBalance'],
199
+ global.veCrvTotalSupply,
200
+ BigInt(s.gauge.totalSupply),
201
+ stakeDaoSupply,
202
+ BigInt(metadata.workingBalance || '0'),
203
+ totalSupply,
204
+ lpPriceInUsd,
205
+ maxApr,
206
+ baseRewardPrice,
207
+ )
208
+
209
+ const boost = onlyboost.boost
210
+ const baseRewardApr = (maxApr / 2.5) * boost * ((100 - V2_FEES) / 100)
211
+
212
+ let baseRewardAdded = false
213
+ const aprDetails = [{ label: isLending ? 'Lending' : 'Trading Fees (APY)', value: [tradingApy] }]
214
+
215
+ for (const r of rewards) {
216
+ if (
217
+ baseReward &&
218
+ r.yieldType === 'STAKING_REWARDS' &&
219
+ r.token.symbol === baseReward.token.symbol &&
220
+ !baseRewardAdded
221
+ ) {
222
+ aprDetails.push({
223
+ label: `${r.token.symbol} APR (incl. ${withTwoDec(boost)}x boost)`,
224
+ value: [baseRewardApr || 0],
225
+ })
226
+
227
+ baseRewardAdded = true
228
+ } else {
229
+ const label =
230
+ r.yieldType === 'VOTEMARKET'
231
+ ? `${r.token.symbol} APR (Extra Rewards from Votemarket)`
232
+ : `${r.token.symbol} APR`
233
+ aprDetails.push({ label, value: [r.apr || 0] })
234
+ }
220
235
  }
221
- }
222
236
 
223
- let aprTotal = aprDetails.reduce((total, x) => {
224
- for (const v of x.value) total += v
225
- return total
226
- }, 0)
227
- if (aprTotal > 1e18) aprTotal = 2727
228
-
229
- return {
230
- key: s.id,
231
- tokensFilter: getTokenTypes({ isLending, coins }),
232
- isLending,
233
- name,
234
- type: 'factory-stable-ng',
235
- version: 2,
236
- protocol: 'curve',
237
- chainId: s.chainId,
238
- vault: s.address,
239
- lpToken,
240
- gaugeAddress: s.gauge.address,
241
- gauge: {
242
- address: s.gauge.address,
243
- totalSupply: s.gauge.totalSupply,
244
- totalSupplyUsd: s.gauge.totalSupplyUSD,
245
- extraRewards: [],
246
- },
247
- coins,
248
- underlyingCoins: [],
249
- lpPriceInUsd,
250
- streaming: true,
251
- tvl: Number(s.totalSupplyUSD) > 10000000000 ? 0 : Number(s.totalSupplyUSD),
252
- apr: {
253
- boost,
254
- current: { total: aprTotal, details: aprDetails },
255
- },
256
- rewards,
257
- tradingApy,
258
- minApr: maxApr / 2.5,
259
- maxApr,
260
- totalSupply: s.totalSupply,
261
- workingBalance: metadata?.workingBalance || '0',
262
- onlyboost,
263
- convexPool:
264
- metadata.pid && metadata.convexBaseRewardPool
265
- ? {
266
- id: Number(metadata.pid),
267
- crvRewards: metadata.convexBaseRewardPool,
268
- }
269
- : undefined,
237
+ let aprTotal = aprDetails.reduce((total, x) => {
238
+ for (const v of x.value) total += v
239
+ return total
240
+ }, 0)
241
+ if (aprTotal > 1e18) aprTotal = 2727
242
+
243
+ res.push({
244
+ key: s.id,
245
+ tokensFilter: getTokenTypes({ isLending, coins }),
246
+ isLending,
247
+ name,
248
+ type: 'factory-stable-ng',
249
+ version: 2,
250
+ protocol,
251
+ chainId: s.chainId,
252
+ vault: s.address,
253
+ lpToken,
254
+ gaugeAddress: s.gauge.address,
255
+ gauge: {
256
+ address: s.gauge.address,
257
+ totalSupply: s.gauge.totalSupply,
258
+ totalSupplyUsd: s.gauge.totalSupplyUSD,
259
+ extraRewards: [],
260
+ },
261
+ coins,
262
+ underlyingCoins: [],
263
+ lpPriceInUsd,
264
+ streaming: true,
265
+ tvl: Number(s.totalSupplyUSD) > 10000000000 ? 0 : Number(s.totalSupplyUSD),
266
+ apr: {
267
+ boost,
268
+ current: { total: aprTotal, details: aprDetails },
269
+ },
270
+ rewards,
271
+ tradingApy,
272
+ minApr: maxApr / 2.5,
273
+ maxApr,
274
+ totalSupply: s.totalSupply,
275
+ workingBalance: metadata?.workingBalance || '0',
276
+ onlyboost,
277
+ convexPool:
278
+ metadata.pid && metadata.convexBaseRewardPool
279
+ ? {
280
+ id: Number(metadata.pid),
281
+ crvRewards: metadata.convexBaseRewardPool,
282
+ }
283
+ : undefined,
284
+ })
270
285
  }
271
- })
286
+ }
287
+
288
+ return res
272
289
  } catch (e) {
273
290
  console.error(e)
274
291
  return []
@@ -0,0 +1,159 @@
1
+ import { Zero, contract, tokenWithAddress } from '@stake-dao/constants'
2
+ import { type Address, formatUnits, parseAbi } from 'viem'
3
+ import { mainnet } from 'viem/chains'
4
+ import { GH_STAKE_DAO_BOUNTIES_REPORT } from '../../endpoints.js'
5
+ import { type Price, getPrices } from '../../prices.js'
6
+ import { rpcFetchTokensData } from '../../tokens.js'
7
+ import { equalTlc, multicall } from '../../utils.js'
8
+
9
+ type Rpcs = {
10
+ [chainId: number]: string
11
+ }
12
+
13
+ type UnknownToken = {
14
+ name: string
15
+ symbol: string
16
+ address: string
17
+ decimals: number
18
+ chainId: number
19
+ }
20
+
21
+ const getParsedData = (
22
+ user: string,
23
+ recipient: string,
24
+ merkleAddress: string,
25
+ userData: any,
26
+ unknownTokensData: any[],
27
+ claimedData: any[],
28
+ prices: Price[],
29
+ chainId: number,
30
+ ) => {
31
+ return userData
32
+ ? Object.keys(userData.tokens).map((token) => {
33
+ const rewardToken = tokenWithAddress(token) || unknownTokensData.find((t) => equalTlc(t.address, token))
34
+ const tokenPrice = prices.find((p) => equalTlc(token, p.address))?.usdPrice || 0
35
+
36
+ const claimed = claimedData.find((c) => equalTlc(c.token, token))?.claimed
37
+ const claimable = BigInt(userData.tokens[token].amount) - claimed
38
+
39
+ return {
40
+ user,
41
+ recipient,
42
+ token: rewardToken,
43
+ claimable: formatUnits(claimable, 0),
44
+ claimableUsd: Number(formatUnits(claimable, rewardToken?.decimals || 18)) * tokenPrice,
45
+ amount: userData.tokens[token].amount,
46
+ amountUsd:
47
+ Number(formatUnits(BigInt(userData.tokens[token].amount), rewardToken?.decimals || 18)) * tokenPrice,
48
+ proof: userData.tokens[token].proof,
49
+ merkleAddress: merkleAddress as Address,
50
+ isClaimed: claimable === Zero,
51
+ chainId,
52
+ }
53
+ })
54
+ : undefined
55
+ }
56
+
57
+ const getMerkleData = async (chainId: number) => {
58
+ const merkleData = await fetch(
59
+ `${GH_STAKE_DAO_BOUNTIES_REPORT}/refs/heads/main/bounties-reports/latest/vlAURA/vlaura_merkle${
60
+ chainId === mainnet.id ? '' : `_${chainId}`
61
+ }.json`,
62
+ ).then((res) => res.json())
63
+
64
+ return { merkleData }
65
+ }
66
+
67
+ const validateMerkleRoots = (fetchedRoot: string, merkleData: any) => {
68
+ return equalTlc(fetchedRoot, merkleData.merkleRoot)
69
+ }
70
+
71
+ const getMerkleRoots = async (provider: any, user: string) => {
72
+ const contracts = [contract('vlAuraMerkle', mainnet.id)]
73
+
74
+ const result = await multicall(
75
+ provider,
76
+ contracts.flatMap((address) => [
77
+ { address, name: 'root', params: [] },
78
+ { address, name: 'recipients', params: [user] },
79
+ ]),
80
+ parseAbi([
81
+ 'function root() external view returns (bytes32)',
82
+ 'function recipients(address) external view returns (address)',
83
+ ]),
84
+ )
85
+
86
+ return {
87
+ merkleRoot: result[0].result,
88
+ merkleRecipient: result[1].result,
89
+ }
90
+ }
91
+
92
+ const getClaimedData = async (provider: any, tokens: string[], user: string, contract: string) => {
93
+ const rawClaimed =
94
+ tokens.length > 0
95
+ ? await multicall(
96
+ provider,
97
+ tokens.flatMap((t) => [{ address: contract, name: 'claimed', params: [user, t] }]),
98
+ parseAbi(['function claimed(address,address) external view returns (uint256)']),
99
+ )
100
+ : []
101
+
102
+ return tokens.map((t, index) => ({
103
+ token: t,
104
+ claimed: rawClaimed[index].result,
105
+ }))
106
+ }
107
+
108
+ export const fetchUserVlAuraClaimable = async (provider: any, rpc: Rpcs, user: string, chainId: number) => {
109
+ const { merkleRoot, merkleRecipient } = await getMerkleRoots(provider, user)
110
+
111
+ let vlAuraClaimable: any
112
+
113
+ try {
114
+ const { merkleData } = await getMerkleData(chainId)
115
+ if (validateMerkleRoots(merkleRoot, merkleData)) {
116
+ vlAuraClaimable = merkleData
117
+ }
118
+ } catch {}
119
+
120
+ if (!vlAuraClaimable) {
121
+ console.error('Could not find valid merkle data')
122
+ return []
123
+ }
124
+
125
+ const vlAuraUser = vlAuraClaimable.claims?.[user]
126
+
127
+ const tokens = Object.keys(vlAuraUser?.tokens || {})
128
+
129
+ if (!tokens.length) return []
130
+
131
+ const claimed = await getClaimedData(provider, tokens, user, contract('vlAuraMerkle'))
132
+
133
+ const unknownTokens = tokens.filter((t) => !tokenWithAddress(t))
134
+ const rawUnknownTokensData = await rpcFetchTokensData(chainId, rpc[chainId]!, unknownTokens)
135
+ const unknownTokensData: UnknownToken[] = rawUnknownTokensData.map((t) => ({
136
+ name: t.name,
137
+ symbol: t.symbol,
138
+ address: t.tokenAddress,
139
+ decimals: Number(t.decimals),
140
+ chainId,
141
+ }))
142
+
143
+ const prices = await getPrices(tokens.map((t) => ({ address: t })) as any[], chainId)
144
+
145
+ return [
146
+ getParsedData(
147
+ user,
148
+ merkleRecipient,
149
+ contract('vlAuraMerkle'),
150
+ vlAuraUser,
151
+ unknownTokensData,
152
+ claimed,
153
+ prices,
154
+ chainId,
155
+ ),
156
+ ]
157
+ .filter(Boolean)
158
+ .flat()
159
+ }
@@ -0,0 +1,23 @@
1
+ import { encodeAbiParameters, parseAbiParameters } from 'viem'
2
+ import { mainnet } from 'viem/chains'
3
+ import batchDirectIncentives from '../bytecodes/votemarket/batchDirectIncentives.js'
4
+ import { concatBytecode } from '../index.js'
5
+ import { batchJsonRpc } from '../utils.js'
6
+
7
+ export const fetchDirectIncentives = async (rpc: string, campaignRewardDistributor: string, start: number) => {
8
+ const inputData = encodeAbiParameters(parseAbiParameters(batchDirectIncentives.inputType[mainnet.id]!) as any, [
9
+ campaignRewardDistributor,
10
+ start,
11
+ ])
12
+
13
+ const call = concatBytecode(batchDirectIncentives.bytecode[mainnet.id]!, inputData)
14
+
15
+ const directIncentives = await batchJsonRpc({
16
+ rpc,
17
+ calls: [call],
18
+ outputTypeAbi: batchDirectIncentives.outputTypeHr[mainnet.id],
19
+ callsKey: `fetch direct incentives - rpc ${rpc}`,
20
+ })
21
+
22
+ return directIncentives
23
+ }