@stake-dao/reader 0.4.111 → 0.5.0

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 (193) hide show
  1. package/dist/esm/abis/lockersMulticall.js +30 -2
  2. package/dist/esm/abis/lockersMulticall.js.map +1 -1
  3. package/dist/esm/index.js +2 -1
  4. package/dist/esm/index.js.map +1 -1
  5. package/dist/esm/lockers/fetch/index.js +53 -224
  6. package/dist/esm/lockers/fetch/index.js.map +1 -1
  7. package/dist/esm/lockers/fetch/parse.js +174 -0
  8. package/dist/esm/lockers/fetch/parse.js.map +1 -0
  9. package/dist/esm/lockers/fetch/protocols/angle.js +136 -0
  10. package/dist/esm/lockers/fetch/protocols/angle.js.map +1 -0
  11. package/dist/esm/lockers/fetch/protocols/balancer.js +172 -0
  12. package/dist/esm/lockers/fetch/protocols/balancer.js.map +1 -0
  13. package/dist/esm/lockers/fetch/protocols/blackpool.js +130 -0
  14. package/dist/esm/lockers/fetch/protocols/blackpool.js.map +1 -0
  15. package/dist/esm/lockers/fetch/protocols/curve.js +204 -0
  16. package/dist/esm/lockers/fetch/protocols/curve.js.map +1 -0
  17. package/dist/esm/lockers/fetch/protocols/frax-fpis.js +121 -0
  18. package/dist/esm/lockers/fetch/protocols/frax-fpis.js.map +1 -0
  19. package/dist/esm/lockers/fetch/protocols/frax-fxs.js +169 -0
  20. package/dist/esm/lockers/fetch/protocols/frax-fxs.js.map +1 -0
  21. package/dist/esm/lockers/fetch/protocols/fxn.js +131 -0
  22. package/dist/esm/lockers/fetch/protocols/fxn.js.map +1 -0
  23. package/dist/esm/lockers/fetch/protocols/maverick.js +172 -0
  24. package/dist/esm/lockers/fetch/protocols/maverick.js.map +1 -0
  25. package/dist/esm/lockers/fetch/protocols/pancakeswap.js +128 -0
  26. package/dist/esm/lockers/fetch/protocols/pancakeswap.js.map +1 -0
  27. package/dist/esm/lockers/fetch/protocols/pendle.js +144 -0
  28. package/dist/esm/lockers/fetch/protocols/pendle.js.map +1 -0
  29. package/dist/esm/lockers/fetch/protocols/spectra.js +133 -0
  30. package/dist/esm/lockers/fetch/protocols/spectra.js.map +1 -0
  31. package/dist/esm/lockers/fetch/protocols/yearn.js +138 -0
  32. package/dist/esm/lockers/fetch/protocols/yearn.js.map +1 -0
  33. package/dist/esm/lockers/fetch/protocols/yieldbasis.js +131 -0
  34. package/dist/esm/lockers/fetch/protocols/yieldbasis.js.map +1 -0
  35. package/dist/esm/lockers/fetch/protocols/yieldnest.js +135 -0
  36. package/dist/esm/lockers/fetch/protocols/yieldnest.js.map +1 -0
  37. package/dist/esm/lockers/fetch/protocols/zerolend.js +124 -0
  38. package/dist/esm/lockers/fetch/protocols/zerolend.js.map +1 -0
  39. package/dist/esm/lockers/fetch/static.js +33 -0
  40. package/dist/esm/lockers/fetch/static.js.map +1 -0
  41. package/dist/esm/lockers/fetch/types.js +2 -0
  42. package/dist/esm/lockers/fetch/types.js.map +1 -0
  43. package/dist/esm/lockers/utils/callsForLockers/pegCalls.js.map +1 -1
  44. package/dist/esm/lockers/utils/getBribesRewardsData.js +11 -9
  45. package/dist/esm/lockers/utils/getBribesRewardsData.js.map +1 -1
  46. package/dist/esm/lockers/utils/substractFees.js +1 -2
  47. package/dist/esm/lockers/utils/substractFees.js.map +1 -1
  48. package/dist/esm/strategies/curve/fetch/getOnlyboostData.js +8 -3
  49. package/dist/esm/strategies/curve/fetch/getOnlyboostData.js.map +1 -1
  50. package/dist/esm/strategies/curve/fetch/index.js +1 -1
  51. package/dist/esm/strategies/curve/fetch/index.js.map +1 -1
  52. package/dist/esm/strategies/v2/parse.js +6 -4
  53. package/dist/esm/strategies/v2/parse.js.map +1 -1
  54. package/dist/esm/utils.js +5 -0
  55. package/dist/esm/utils.js.map +1 -1
  56. package/dist/types/abis/lockersMulticall.d.ts +1 -1
  57. package/dist/types/abis/lockersMulticall.d.ts.map +1 -1
  58. package/dist/types/index.d.ts +2 -1
  59. package/dist/types/index.d.ts.map +1 -1
  60. package/dist/types/lockers/fetch/index.d.ts +5 -99
  61. package/dist/types/lockers/fetch/index.d.ts.map +1 -1
  62. package/dist/types/lockers/fetch/parse.d.ts +52 -0
  63. package/dist/types/lockers/fetch/parse.d.ts.map +1 -0
  64. package/dist/types/lockers/fetch/protocols/angle.d.ts +9 -0
  65. package/dist/types/lockers/fetch/protocols/angle.d.ts.map +1 -0
  66. package/dist/types/lockers/fetch/protocols/balancer.d.ts +9 -0
  67. package/dist/types/lockers/fetch/protocols/balancer.d.ts.map +1 -0
  68. package/dist/types/lockers/fetch/protocols/blackpool.d.ts +9 -0
  69. package/dist/types/lockers/fetch/protocols/blackpool.d.ts.map +1 -0
  70. package/dist/types/lockers/fetch/protocols/curve.d.ts +9 -0
  71. package/dist/types/lockers/fetch/protocols/curve.d.ts.map +1 -0
  72. package/dist/types/lockers/fetch/protocols/frax-fpis.d.ts +9 -0
  73. package/dist/types/lockers/fetch/protocols/frax-fpis.d.ts.map +1 -0
  74. package/dist/types/lockers/fetch/protocols/frax-fxs.d.ts +9 -0
  75. package/dist/types/lockers/fetch/protocols/frax-fxs.d.ts.map +1 -0
  76. package/dist/types/lockers/fetch/protocols/fxn.d.ts +9 -0
  77. package/dist/types/lockers/fetch/protocols/fxn.d.ts.map +1 -0
  78. package/dist/types/lockers/fetch/protocols/maverick.d.ts +9 -0
  79. package/dist/types/lockers/fetch/protocols/maverick.d.ts.map +1 -0
  80. package/dist/types/lockers/fetch/protocols/pancakeswap.d.ts +9 -0
  81. package/dist/types/lockers/fetch/protocols/pancakeswap.d.ts.map +1 -0
  82. package/dist/types/lockers/fetch/protocols/pendle.d.ts +9 -0
  83. package/dist/types/lockers/fetch/protocols/pendle.d.ts.map +1 -0
  84. package/dist/types/lockers/fetch/protocols/spectra.d.ts +9 -0
  85. package/dist/types/lockers/fetch/protocols/spectra.d.ts.map +1 -0
  86. package/dist/types/lockers/fetch/protocols/yearn.d.ts +9 -0
  87. package/dist/types/lockers/fetch/protocols/yearn.d.ts.map +1 -0
  88. package/dist/types/lockers/fetch/protocols/yieldbasis.d.ts +9 -0
  89. package/dist/types/lockers/fetch/protocols/yieldbasis.d.ts.map +1 -0
  90. package/dist/types/lockers/fetch/protocols/yieldnest.d.ts +9 -0
  91. package/dist/types/lockers/fetch/protocols/yieldnest.d.ts.map +1 -0
  92. package/dist/types/lockers/fetch/protocols/zerolend.d.ts +9 -0
  93. package/dist/types/lockers/fetch/protocols/zerolend.d.ts.map +1 -0
  94. package/dist/types/lockers/fetch/static.d.ts +3 -0
  95. package/dist/types/lockers/fetch/static.d.ts.map +1 -0
  96. package/dist/types/lockers/fetch/types.d.ts +105 -0
  97. package/dist/types/lockers/fetch/types.d.ts.map +1 -0
  98. package/dist/types/lockers/utils/callsForLockers/pegCalls.d.ts +1 -1
  99. package/dist/types/lockers/utils/callsForLockers/pegCalls.d.ts.map +1 -1
  100. package/dist/types/lockers/utils/getBribesRewardsData.d.ts +1 -0
  101. package/dist/types/lockers/utils/getBribesRewardsData.d.ts.map +1 -1
  102. package/dist/types/lockers/utils/substractFees.d.ts.map +1 -1
  103. package/dist/types/strategies/curve/fetch/getOnlyboostData.d.ts +1 -1
  104. package/dist/types/strategies/curve/fetch/getOnlyboostData.d.ts.map +1 -1
  105. package/dist/types/strategies/curve/fetch/index.d.ts.map +1 -1
  106. package/dist/types/strategies/stakeDao/fetch.d.ts +1 -1
  107. package/dist/types/strategies/v2/parse.d.ts.map +1 -1
  108. package/dist/types/utils.d.ts +1 -0
  109. package/dist/types/utils.d.ts.map +1 -1
  110. package/package.json +2 -2
  111. package/src/abis/lockersMulticall.ts +30 -2
  112. package/src/index.ts +2 -1
  113. package/src/lockers/fetch/index.ts +65 -329
  114. package/src/lockers/fetch/parse.ts +258 -0
  115. package/src/lockers/fetch/protocols/angle.ts +157 -0
  116. package/src/lockers/fetch/protocols/balancer.ts +195 -0
  117. package/src/lockers/fetch/protocols/blackpool.ts +151 -0
  118. package/src/lockers/fetch/protocols/curve.ts +229 -0
  119. package/src/lockers/fetch/protocols/frax-fpis.ts +139 -0
  120. package/src/lockers/fetch/protocols/frax-fxs.ts +193 -0
  121. package/src/lockers/fetch/protocols/fxn.ts +152 -0
  122. package/src/lockers/fetch/protocols/maverick.ts +193 -0
  123. package/src/lockers/fetch/protocols/pancakeswap.ts +149 -0
  124. package/src/lockers/fetch/protocols/pendle.ts +165 -0
  125. package/src/lockers/fetch/protocols/spectra.ts +154 -0
  126. package/src/lockers/fetch/protocols/yearn.ts +159 -0
  127. package/src/lockers/fetch/protocols/yieldbasis.ts +152 -0
  128. package/src/lockers/fetch/protocols/yieldnest.ts +157 -0
  129. package/src/lockers/fetch/protocols/zerolend.ts +144 -0
  130. package/src/lockers/fetch/static.ts +35 -0
  131. package/src/lockers/fetch/types.ts +112 -0
  132. package/src/lockers/utils/callsForLockers/pegCalls.ts +2 -1
  133. package/src/lockers/utils/getBribesRewardsData.ts +12 -11
  134. package/src/lockers/utils/substractFees.ts +1 -2
  135. package/src/strategies/curve/fetch/getOnlyboostData.ts +11 -2
  136. package/src/strategies/curve/fetch/index.ts +2 -0
  137. package/src/strategies/v2/parse.ts +11 -5
  138. package/src/utils.ts +5 -0
  139. package/dist/esm/lockers/fetch/parseBoost.js +0 -36
  140. package/dist/esm/lockers/fetch/parseBoost.js.map +0 -1
  141. package/dist/esm/lockers/fetch/parsePeg.js +0 -18
  142. package/dist/esm/lockers/fetch/parsePeg.js.map +0 -1
  143. package/dist/esm/lockers/fetch/parseVoteBoosterData.js +0 -28
  144. package/dist/esm/lockers/fetch/parseVoteBoosterData.js.map +0 -1
  145. package/dist/esm/lockers/utils/callsForLockers/depositorCalls.js +0 -24
  146. package/dist/esm/lockers/utils/callsForLockers/depositorCalls.js.map +0 -1
  147. package/dist/esm/lockers/utils/callsForLockers/feeCalls.js +0 -97
  148. package/dist/esm/lockers/utils/callsForLockers/feeCalls.js.map +0 -1
  149. package/dist/esm/lockers/utils/callsForLockers/gaugeCalls.js +0 -9
  150. package/dist/esm/lockers/utils/callsForLockers/gaugeCalls.js.map +0 -1
  151. package/dist/esm/lockers/utils/callsForLockers/index.js +0 -34
  152. package/dist/esm/lockers/utils/callsForLockers/index.js.map +0 -1
  153. package/dist/esm/lockers/utils/callsForLockers/veBoosts.js +0 -17
  154. package/dist/esm/lockers/utils/callsForLockers/veBoosts.js.map +0 -1
  155. package/dist/esm/lockers/utils/callsForLockers/veCalls.js +0 -33
  156. package/dist/esm/lockers/utils/callsForLockers/veCalls.js.map +0 -1
  157. package/dist/esm/lockers/utils/callsForLockers/veSdtCalls.js +0 -14
  158. package/dist/esm/lockers/utils/callsForLockers/veSdtCalls.js.map +0 -1
  159. package/dist/esm/lockers/utils/getFees.js +0 -27
  160. package/dist/esm/lockers/utils/getFees.js.map +0 -1
  161. package/dist/types/lockers/fetch/parseBoost.d.ts +0 -4
  162. package/dist/types/lockers/fetch/parseBoost.d.ts.map +0 -1
  163. package/dist/types/lockers/fetch/parsePeg.d.ts +0 -3
  164. package/dist/types/lockers/fetch/parsePeg.d.ts.map +0 -1
  165. package/dist/types/lockers/fetch/parseVoteBoosterData.d.ts +0 -13
  166. package/dist/types/lockers/fetch/parseVoteBoosterData.d.ts.map +0 -1
  167. package/dist/types/lockers/utils/callsForLockers/depositorCalls.d.ts +0 -4
  168. package/dist/types/lockers/utils/callsForLockers/depositorCalls.d.ts.map +0 -1
  169. package/dist/types/lockers/utils/callsForLockers/feeCalls.d.ts +0 -13
  170. package/dist/types/lockers/utils/callsForLockers/feeCalls.d.ts.map +0 -1
  171. package/dist/types/lockers/utils/callsForLockers/gaugeCalls.d.ts +0 -6
  172. package/dist/types/lockers/utils/callsForLockers/gaugeCalls.d.ts.map +0 -1
  173. package/dist/types/lockers/utils/callsForLockers/index.d.ts +0 -8
  174. package/dist/types/lockers/utils/callsForLockers/index.d.ts.map +0 -1
  175. package/dist/types/lockers/utils/callsForLockers/veBoosts.d.ts +0 -7
  176. package/dist/types/lockers/utils/callsForLockers/veBoosts.d.ts.map +0 -1
  177. package/dist/types/lockers/utils/callsForLockers/veCalls.d.ts +0 -4
  178. package/dist/types/lockers/utils/callsForLockers/veCalls.d.ts.map +0 -1
  179. package/dist/types/lockers/utils/callsForLockers/veSdtCalls.d.ts +0 -11
  180. package/dist/types/lockers/utils/callsForLockers/veSdtCalls.d.ts.map +0 -1
  181. package/dist/types/lockers/utils/getFees.d.ts +0 -4
  182. package/dist/types/lockers/utils/getFees.d.ts.map +0 -1
  183. package/src/lockers/fetch/parseBoost.ts +0 -46
  184. package/src/lockers/fetch/parsePeg.ts +0 -22
  185. package/src/lockers/fetch/parseVoteBoosterData.ts +0 -34
  186. package/src/lockers/utils/callsForLockers/depositorCalls.ts +0 -30
  187. package/src/lockers/utils/callsForLockers/feeCalls.ts +0 -124
  188. package/src/lockers/utils/callsForLockers/gaugeCalls.ts +0 -10
  189. package/src/lockers/utils/callsForLockers/index.ts +0 -51
  190. package/src/lockers/utils/callsForLockers/veBoosts.ts +0 -28
  191. package/src/lockers/utils/callsForLockers/veCalls.ts +0 -44
  192. package/src/lockers/utils/callsForLockers/veSdtCalls.ts +0 -15
  193. package/src/lockers/utils/getFees.ts +0 -31
@@ -0,0 +1,258 @@
1
+ import { ONE_WEEK, ONE_YEAR, Zero } from '@stake-dao/constants'
2
+ import { formatUnits, parseUnits } from 'viem'
3
+ import { equalTlc } from '../../utils.js'
4
+ import getBribesRewardsData, { type TBribesRewards } from '../utils/getBribesRewardsData.js'
5
+ import substractFees from '../utils/substractFees.js'
6
+ import type { Locker } from './types.js'
7
+
8
+ export const parseVoteBoosterData = (locker: Locker, voteBooster: any) => {
9
+ const voteBoosterBoost =
10
+ voteBooster && Number(voteBooster.working) > 0 && Number(voteBooster.staked) > 0
11
+ ? Number(voteBooster.working) / (Number(voteBooster.staked) * 0.4)
12
+ : 1
13
+
14
+ return {
15
+ booster: locker.voteBooster!.booster,
16
+ vSdToken: locker.voteBooster!.vSdToken,
17
+ balance: voteBooster,
18
+ boost: voteBoosterBoost,
19
+ }
20
+ }
21
+
22
+ export const parsePeg = (locker: Locker, rawPeg: any) => {
23
+ if (rawPeg && rawPeg !== '-') {
24
+ const pegBase = parseUnits(locker.secondaryMarket?.pegBase?.toString() || '1', 0)
25
+ return formatUnits(rawPeg / pegBase, 18)
26
+ }
27
+
28
+ return '-'
29
+ }
30
+
31
+ export const parseAltYields = (locker: Locker, common: any) => {
32
+ const alternativeYields = JSON.parse(JSON.stringify(locker.alternativeYields || {})) // parse and stringify to avoid extensible issue
33
+
34
+ try {
35
+ if (common.cvgAprs?.[locker.modules.gauge]) {
36
+ alternativeYields.convergenceSdToken = {
37
+ label: locker.sdToken.symbol,
38
+ platform: 'Convergence',
39
+ href: 'https://app.cvg.finance/',
40
+ apr: common.cvgAprs[locker.modules.gauge].totalApr,
41
+ }
42
+ }
43
+
44
+ const spectraAltYield = common.spectraAprs?.find((s) => equalTlc(s.underlying.address, locker.sdToken.address))
45
+
46
+ alternativeYields.spectraAsdToken = spectraAltYield
47
+ ? {
48
+ label: spectraAltYield.ibt.symbol,
49
+ platform: 'Spectra',
50
+ href: 'https://app.spectra.finance/pools',
51
+ apr: Math.max(spectraAltYield.pools.map((p) => p.lpApy?.total || 0) || [0]),
52
+ }
53
+ : undefined
54
+ } catch (e) {
55
+ console.error(e)
56
+ }
57
+
58
+ return alternativeYields
59
+ }
60
+
61
+ export const parseVeBoostApr = (weeklyRewards: any, tokenPriceInUsd: number, totalDelegatedVeBoost: number) => {
62
+ let amountPerYear = 0
63
+
64
+ try {
65
+ const weeklyRewardsWithoutNull = weeklyRewards
66
+ .filter((r) => r > Zero)
67
+ .map((r) => Number(formatUnits(r as bigint, 18)))
68
+
69
+ if (weeklyRewardsWithoutNull.length > 0) {
70
+ amountPerYear =
71
+ (weeklyRewardsWithoutNull.reduce((total, x) => (total += x), 0) /
72
+ (weeklyRewardsWithoutNull.length * ONE_WEEK)) *
73
+ ONE_YEAR
74
+ }
75
+ } catch (e) {
76
+ console.error(e)
77
+ amountPerYear = 0
78
+ }
79
+
80
+ const tvl = Number(totalDelegatedVeBoost) * tokenPriceInUsd
81
+ const apr = tvl > 0 ? ((amountPerYear * tokenPriceInUsd) / tvl) * 100 : 0
82
+
83
+ return apr
84
+ }
85
+
86
+ export const parseSidechains = (locker, raw, prices) => {
87
+ if (locker.extensions.sideChains && raw.sidechains) {
88
+ return locker.extensions.sideChains.map((s, index) => {
89
+ const rewards =
90
+ s.rewards?.map((reward) => {
91
+ const price = prices.find((p) => equalTlc(p.address, reward.address))?.usdPrice || 0
92
+ return { token: reward, price }
93
+ }) || []
94
+
95
+ return {
96
+ ...s,
97
+ ...raw.sidechains[index],
98
+ rewards,
99
+ }
100
+ })
101
+ }
102
+
103
+ return undefined
104
+ }
105
+
106
+ export interface RawLockersData {
107
+ tokenLocked: string
108
+ veBalanceOfLocker: string
109
+ totalTokenLocked: string
110
+ veTotalSupply: string
111
+ totalSupplyStaked: string
112
+ gaugeWorkingSupply: string
113
+ amountTokenNotLock: string
114
+ sdTokenInPool: string
115
+ lockIncentive?: string
116
+ peg: string
117
+ rewards: any[]
118
+ veBoost?: {
119
+ delegated: string
120
+ weeklyRewards: string[]
121
+ }
122
+ voteBooster?: {
123
+ token: string
124
+ sdToken: string
125
+ staked: string
126
+ working: string
127
+ }
128
+ veTokenRate: string
129
+ _workingSupply: string
130
+ _veBalanceOfLocker: string
131
+ replaceApr?: number[]
132
+ sidechains?: any[]
133
+ }
134
+
135
+ export interface ParseLockers {
136
+ locker: any
137
+ raw: RawLockersData
138
+ common: {
139
+ bribesData: { [locker: string]: number }
140
+ veSdtTotalSupply: bigint
141
+ }
142
+ prices: any[]
143
+ }
144
+
145
+ export const parse = async ({ locker, raw, common, prices }: ParseLockers) => {
146
+ const lockerFee = { total: 15 }
147
+
148
+ const tokenPrice = prices.find((p) => p.address === locker.token.address)
149
+ const tokenPriceInUsd = tokenPrice ? tokenPrice.usdPrice : 0
150
+ const sdTokenPriceInUsd = raw.peg !== '-' ? tokenPriceInUsd * Number(raw.peg) : tokenPriceInUsd
151
+
152
+ const tvl = raw.totalSupplyStaked ? Number(raw.totalSupplyStaked) * sdTokenPriceInUsd : 0
153
+
154
+ const veBoostApr =
155
+ locker.veBoost && raw.veBoost
156
+ ? parseVeBoostApr(raw.veBoost.weeklyRewards, tokenPriceInUsd, Number(raw.veBoost.delegated))
157
+ : 0
158
+
159
+ // Rewards APR
160
+ const rewardsData = raw.rewards.map((rawData, index) => {
161
+ const r = locker.rewards[index]
162
+ const rewardPrice = equalTlc(r.address, locker.sdToken.address)
163
+ ? sdTokenPriceInUsd
164
+ : prices.find((p) => p.address === r.address)?.usdPrice || 0
165
+
166
+ const periodFinish = Number(formatUnits(rawData ? rawData[2] : Zero, 0))
167
+ let streaming = r.distribution === 'streamed' && periodFinish > Math.floor(Date.now() / 1000)
168
+
169
+ const rate = rawData ? rawData[3] : Zero
170
+ const oneYearRate = rate * BigInt(ONE_YEAR)
171
+
172
+ let apr = streaming
173
+ ? rewardPrice && tvl > 0
174
+ ? ((Number(formatUnits(oneYearRate, r.decimals)) * rewardPrice) / tvl) * 100
175
+ : 0
176
+ : 0
177
+
178
+ if (raw.replaceApr?.[index]) {
179
+ apr = raw.replaceApr[index]
180
+ streaming = apr > 0
181
+ }
182
+
183
+ // Remove fees from APR
184
+ apr = substractFees(locker.id, apr, lockerFee)
185
+
186
+ return {
187
+ token: r,
188
+ price: rewardPrice,
189
+ apr,
190
+ streaming,
191
+ periodFinish,
192
+ rate: formatUnits(rate, 0),
193
+ lastUpdate: rawData ? formatUnits(rawData[4], 0) : '0',
194
+ isAirdrop: r.isAirdrop,
195
+ }
196
+ })
197
+
198
+ const data = getBribesRewardsData(
199
+ locker,
200
+ common.bribesData,
201
+ common.veSdtTotalSupply,
202
+ raw.totalSupplyStaked,
203
+ raw._veBalanceOfLocker,
204
+ raw._workingSupply,
205
+ raw.sdTokenInPool,
206
+ raw.tokenLocked,
207
+ )
208
+
209
+ const bribeMinApr: number = data.bribeMinApr
210
+ const bribeMaxApr: number = data.bribeMaxApr
211
+ const bribeRewards: TBribesRewards | undefined = data.bribeRewards
212
+
213
+ // Total APR
214
+ const minRewardsAprs = rewardsData.reduce((x, y) => x + y.apr, 0) + bribeMinApr
215
+ const maxRewardsAprs = rewardsData.reduce((x, y) => x + y.apr, 0) + bribeMaxApr
216
+
217
+ // Streaming status
218
+ const streaming = rewardsData.some((r) => r.streaming)
219
+ const alternativeYields = parseAltYields(locker, common)
220
+
221
+ // Sidechains
222
+ const sideChains = parseSidechains(locker, raw, prices)
223
+
224
+ return {
225
+ ...locker,
226
+ rewards: rewardsData,
227
+ tokenLocked: raw.tokenLocked,
228
+ veBalanceOfLocker: raw.veBalanceOfLocker,
229
+ totalTokenLocked: raw.totalTokenLocked,
230
+ veTotalSupply: raw.veTotalSupply,
231
+ lockIncentive: raw.lockIncentive || '0',
232
+ gaugeWorkingSupply: raw.gaugeWorkingSupply,
233
+ totalSupplyStaked: raw.totalSupplyStaked,
234
+ amountTokenNotLock: raw.amountTokenNotLock,
235
+ bribeRewards,
236
+ apr: [minRewardsAprs, maxRewardsAprs],
237
+ streaming,
238
+ veTokenRate: raw.veTokenRate,
239
+ tvl,
240
+ peg: raw.peg,
241
+ tokenPriceInUsd,
242
+ sdTokenPriceInUsd,
243
+ alternativeYields,
244
+ extensions: {
245
+ ...locker.extensions,
246
+ sideChains,
247
+ },
248
+ veBoost:
249
+ locker.veBoost && raw.veBoost
250
+ ? {
251
+ ...locker.veBoost,
252
+ delegated: raw.veBoost.delegated,
253
+ apr: veBoostApr,
254
+ }
255
+ : undefined,
256
+ voteBooster: raw.voteBooster,
257
+ }
258
+ }
@@ -0,0 +1,157 @@
1
+ import { One, STAKE_DAO_ASSETS_BASE_URL, Zero, tokenWithId } from '@stake-dao/constants'
2
+ import { formatUnits, parseUnits } from 'viem'
3
+ import lockersMulticallAbi from '../../../abis/lockersMulticall.js'
4
+ import { type Call, getRes, multicall } from '../../../utils.js'
5
+ import { parse, parsePeg } from '../parse.js'
6
+ import type { Locker } from '../types.js'
7
+
8
+ export const locker: Locker = {
9
+ id: 'angle',
10
+ symbol: 'ANGLE',
11
+ protocol: 'Angle',
12
+ protocolDescription:
13
+ 'Angle is a decentralized, capital efficient and over-collateralized stablecoin protocol composed of smart contracts running on open blockchains.',
14
+ website: 'https://angle.money/',
15
+ logoUrl: `${STAKE_DAO_ASSETS_BASE_URL}/assets/archive/angle.svg`,
16
+ chainId: 1,
17
+ rgb: '249, 145, 144',
18
+ token: tokenWithId('angle')!,
19
+ sdToken: tokenWithId('sdangle')!,
20
+ rewards: [
21
+ { ...tokenWithId('sdt')!, distribution: 'streamed', origin: 'sdtEmission' },
22
+ { ...tokenWithId('angle')!, distribution: 'streamed', origin: 'stratPerf' },
23
+ { ...tokenWithId('eura')!, distribution: 'streamed', origin: 'native.common' },
24
+ { ...tokenWithId('sdangle')!, distribution: 'distributed', origin: 'bounties' },
25
+ ],
26
+ delegation: ['sdangle.eth'],
27
+ modules: {
28
+ depositor: '0x0000000000000000000000000000000000000000',
29
+ locker: '0xD13F8C25CceD32cdfA79EB5eD654Ce3e484dCAF5',
30
+ veToken: '0x0C462Dbb9EC8cD1630f1728B2CFD2769d09f0dd5',
31
+ gauge: '0xE55843a90672f7d8218285e51EE8fF8E233F35d5',
32
+ accumulator: '0x8cc02F4f383A11b989708437DbA6BB0628d7eE78',
33
+ redeem: '0x1D8A9c30E4e25033498347c1A054717bd0c4D356',
34
+ },
35
+ secondaryMarket: {
36
+ label: 'Curve',
37
+ poolKey: 'factory-v2-101',
38
+ vaultKey: '',
39
+ pool: '0x48fF31bBbD8Ab553Ebe7cBD84e1eA3dBa8f54957',
40
+ pools: ['0x48fF31bBbD8Ab553Ebe7cBD84e1eA3dBa8f54957'],
41
+ pegBase: 300000,
42
+ },
43
+ fees: [
44
+ {
45
+ label: { key: 'liquidity', variable: 'sdANGLE/ANGLE' },
46
+ value: 10,
47
+ key: 'liquidityFee',
48
+ static: true,
49
+ },
50
+ {
51
+ label: { key: 'treasury' },
52
+ value: 5,
53
+ key: 'daoFee',
54
+ static: true,
55
+ },
56
+ {
57
+ label: { key: 'harvester' },
58
+ value: 0.1,
59
+ key: 'claimerFee',
60
+ static: true,
61
+ },
62
+ ],
63
+ extensions: {
64
+ coingeckoBaseSlug: 'angle',
65
+ },
66
+ }
67
+
68
+ const angleLocker = async ({ provider, common, prices }: { provider; common; prices }) => {
69
+ const token = locker.token.address
70
+ const sdToken = locker.sdToken.address
71
+
72
+ const gauge = locker.modules.gauge
73
+ const depositor = locker.modules.depositor
74
+ const votingEscrow = locker.modules.veToken
75
+ const lockerAddress = locker.modules.locker
76
+
77
+ const secondaryMarket = locker.secondaryMarket!
78
+ const rewards = locker.rewards
79
+
80
+ const pegBase = parseUnits(secondaryMarket?.pegBase?.toString() || '1', 18)
81
+
82
+ const format = (value: bigint) => formatUnits(value, locker.token.decimals)
83
+ const formatRes = (value: any) => format(getRes(value))
84
+
85
+ const calls: Call[] = [
86
+ /*********************************************************************************
87
+ *** Voting Escrow
88
+ *********************************************************************************/
89
+
90
+ // Token locked by the Locker
91
+ { address: votingEscrow, name: 'locked', params: [lockerAddress] },
92
+ // veToken Balance of the Locker
93
+ { address: votingEscrow, name: 'balanceOf', params: [lockerAddress] },
94
+ // Total token locked
95
+ { address: votingEscrow, name: 'supply' },
96
+ // Total veToken supply
97
+ { address: votingEscrow, name: 'totalSupply' },
98
+
99
+ /*********************************************************************************
100
+ *** Gauge
101
+ *********************************************************************************/
102
+
103
+ // Total sdToken staked
104
+ { address: gauge, name: 'totalSupply' },
105
+ // Gauge working supply
106
+ { address: gauge, name: 'working_supply' },
107
+
108
+ /*********************************************************************************
109
+ *** Token & sdToken
110
+ *********************************************************************************/
111
+
112
+ // Token balance not locked
113
+ { address: token, name: 'balanceOf', params: [depositor] },
114
+ // sdToken in secondary market pool
115
+ { address: sdToken, name: 'balanceOf', params: [secondaryMarket.pool] },
116
+
117
+ /*********************************************************************************
118
+ *** Peg
119
+ *********************************************************************************/
120
+
121
+ // Return amount when swapping {pegBase} sdToken to token -> get_dy(int128,int128,uint256)
122
+ { address: secondaryMarket.pool, name: '0x5e0d443f', params: [One, Zero, pegBase] },
123
+
124
+ /*********************************************************************************
125
+ *** Rewards
126
+ *********************************************************************************/
127
+
128
+ // Streaming status for each reward token
129
+ ...rewards.map((r) => ({ address: gauge, name: 'reward_data', params: [r.address] })),
130
+ ]
131
+
132
+ const res = await multicall(provider, calls, lockersMulticallAbi(locker.id, locker.chainId))
133
+ const raw = {
134
+ tokenLocked: getRes(res.shift()),
135
+ veBalanceOfLocker: formatRes(res.shift()),
136
+ totalTokenLocked: formatRes(res.shift()),
137
+ veTotalSupply: formatRes(res.shift()),
138
+ totalSupplyStaked: formatRes(res.shift()),
139
+ gaugeWorkingSupply: formatRes(res.shift()),
140
+ amountTokenNotLock: formatRes(res.shift()),
141
+ sdTokenInPool: formatRes(res.shift()),
142
+ peg: getRes(res.shift()),
143
+ rewards: rewards.map(() => getRes(res.shift())),
144
+ veTokenRate: '4',
145
+ _workingSupply: '0',
146
+ _veBalanceOfLocker: '0',
147
+ }
148
+
149
+ raw.tokenLocked = format(raw.tokenLocked[0])
150
+ raw.peg = parsePeg(locker, raw.peg)
151
+ raw._workingSupply = raw.gaugeWorkingSupply
152
+ raw._veBalanceOfLocker = raw.veBalanceOfLocker
153
+
154
+ return parse({ locker, common, prices, raw })
155
+ }
156
+
157
+ export default angleLocker
@@ -0,0 +1,195 @@
1
+ import { ONE_WEEK, One, STAKE_DAO_ASSETS_BASE_URL, Zero, contracts, tokenWithId } from '@stake-dao/constants'
2
+ import { range } from 'lodash-es'
3
+ import { type Address, formatUnits, parseUnits, zeroAddress } from 'viem'
4
+ import lockersMulticallAbi from '../../../abis/lockersMulticall.js'
5
+ import { type Call, getRes, multicall } from '../../../utils.js'
6
+ import { parse, parsePeg } from '../parse.js'
7
+ import type { Locker } from '../types.js'
8
+
9
+ export const locker: Locker = {
10
+ id: 'bal',
11
+ symbol: 'BAL',
12
+ protocol: 'Balancer',
13
+ protocolDescription:
14
+ 'Balancer is a decentralized automated market maker (AMM) protocol built on Ethereum that represents a flexible building block for programmable liquidity.',
15
+ website: 'https://balancer.fi/',
16
+ logoUrl: `${STAKE_DAO_ASSETS_BASE_URL}/assets/archive/bal.svg`,
17
+ chainId: 1,
18
+ rgb: '9, 31, 59',
19
+ token: tokenWithId('80-bal-20-weth')!,
20
+ sdToken: tokenWithId('sdbal')!,
21
+ rewards: [
22
+ { ...tokenWithId('sdt')!, distribution: 'streamed', origin: 'sdtEmission' },
23
+ { ...tokenWithId('bal')!, distribution: 'streamed', origin: 'stratPerf' },
24
+ { ...tokenWithId('usdc')!, distribution: 'streamed', origin: 'native.common' },
25
+ { ...tokenWithId('sdbal')!, distribution: 'distributed', origin: 'bounties' },
26
+ ],
27
+ delegation: ['sdbal.eth'],
28
+ modules: {
29
+ depositor: '0x3e0d44542972859de3CAdaF856B1a4FD351B4D2E',
30
+ locker: '0xea79d1a83da6db43a85942767c389fe0acf336a5',
31
+ veToken: '0xC128a9954e6c874eA3d62ce62B468bA073093F25',
32
+ gauge: '0x3e8c72655e48591d93e6dfda16823db0ff23d859',
33
+ accumulator: '0x2903DBEC58d193c34708dE22f89fd7A42b6d0Eb0',
34
+ },
35
+ secondaryMarket: {
36
+ label: 'Balancer',
37
+ poolKey: '0x2d011adf89f0576c9b722c28269fcb5d50c2d17900020000000000000000024d',
38
+ vaultKey: '0x2d011adf89f0576c9b722c28269fcb5d50c2d17900020000000000000000024d',
39
+ pool: '0x2d011adf89f0576c9b722c28269fcb5d50c2d17900020000000000000000024d',
40
+ pools: [contracts.balancerVault![1] as Address],
41
+ router: contracts.balancerVault![1] as Address,
42
+ pegBase: 1000,
43
+ },
44
+ veBoost: {
45
+ address: '0x2cf8e145Bdfe7c52b49AD9bB3c294a31B2736c59',
46
+ delegator: '0xda9846665Bdb44b0d0CAFFd0d1D4A539932BeBdf',
47
+ },
48
+ alternativeYields: {
49
+ sdBalBalStakeDao: {
50
+ label: 'sdBAL/B-80BAL-20WETH',
51
+ platform: 'Stake DAO',
52
+ href: '/yield',
53
+ },
54
+ },
55
+ fees: [
56
+ {
57
+ label: { key: 'liquidity', variable: 'sdBAL/B-80BAL-20WETH' },
58
+ value: 10,
59
+ key: 'liquidityFee',
60
+ },
61
+ {
62
+ label: { key: 'treasury' },
63
+ value: 5,
64
+ key: 'daoFee',
65
+ },
66
+ {
67
+ label: { key: 'harvesterOn', variable: 'BAL, USDC' },
68
+ value: 0,
69
+ key: 'claimerFee',
70
+ },
71
+ ],
72
+ extensions: {
73
+ coingeckoBaseSlug: 'balancer',
74
+ },
75
+ }
76
+
77
+ const balancerLocker = async ({ provider, common, prices }: { provider; common; prices }) => {
78
+ const token = locker.token.address
79
+ const sdToken = locker.sdToken.address
80
+
81
+ const gauge = locker.modules.gauge
82
+ const depositor = locker.modules.depositor
83
+ const votingEscrow = locker.modules.veToken
84
+ const lockerAddress = locker.modules.locker
85
+
86
+ const veBoost = locker.veBoost!
87
+ const secondaryMarket = locker.secondaryMarket!
88
+ const rewards = locker.rewards
89
+
90
+ const now = Math.floor(Date.now() / 1000)
91
+ const lastWeek = Math.floor(now / ONE_WEEK) * ONE_WEEK
92
+ const pegBase = parseUnits(secondaryMarket?.pegBase?.toString() || '1', 18)
93
+
94
+ const format = (value: bigint) => formatUnits(value, locker.token.decimals)
95
+ const formatRes = (value: any) => format(getRes(value))
96
+
97
+ const calls: Call[] = [
98
+ /*********************************************************************************
99
+ *** Voting Escrow
100
+ *********************************************************************************/
101
+
102
+ // Token locked by the Locker
103
+ { address: votingEscrow, name: 'locked', params: [lockerAddress] },
104
+ // veToken Balance of the Locker
105
+ { address: votingEscrow, name: 'balanceOf', params: [lockerAddress] },
106
+ // Total token locked
107
+ { address: votingEscrow, name: 'supply' },
108
+ // Total veToken supply
109
+ { address: votingEscrow, name: 'totalSupply' },
110
+
111
+ /*********************************************************************************
112
+ *** Gauge
113
+ *********************************************************************************/
114
+
115
+ // Total sdToken staked
116
+ { address: gauge, name: 'totalSupply' },
117
+ // Gauge working supply
118
+ { address: gauge, name: 'working_supply' },
119
+
120
+ /*********************************************************************************
121
+ *** Token & sdToken
122
+ *********************************************************************************/
123
+
124
+ // Token balance not locked
125
+ { address: token, name: 'balanceOf', params: [depositor] },
126
+ // sdToken in secondary market pool
127
+ { address: sdToken, name: 'balanceOf', params: [secondaryMarket.router] },
128
+
129
+ /*********************************************************************************
130
+ *** Peg
131
+ *********************************************************************************/
132
+
133
+ // Return amount when swapping {pegBase} sdToken to token -> get_dy(int128,int128,uint256)
134
+ {
135
+ address: contracts.balancerVault![1]!,
136
+ name: 'queryBatchSwap',
137
+ params: [
138
+ Zero,
139
+ [[secondaryMarket.pool, Zero, One, pegBase, '0x']],
140
+ [sdToken, token],
141
+ [zeroAddress, false, zeroAddress, false],
142
+ ],
143
+ },
144
+
145
+ /*********************************************************************************
146
+ *** Rewards
147
+ *********************************************************************************/
148
+
149
+ // Streaming status for each reward token
150
+ ...rewards.map((r) => ({ address: gauge, name: 'reward_data', params: [r.address] })),
151
+
152
+ /*********************************************************************************
153
+ *** veBoost
154
+ *********************************************************************************/
155
+
156
+ // Total veBoost delegated through delegator
157
+ { address: veBoost.delegator, name: 'totalSupply' },
158
+ // veBoost 5 last weeks rewards
159
+ ...range(0, 5).map((i) => ({
160
+ address: veBoost.delegator,
161
+ name: 'weeklyRewards',
162
+ params: [token, lastWeek - i * ONE_WEEK],
163
+ })),
164
+ ]
165
+
166
+ const res = await multicall(provider, calls, lockersMulticallAbi(locker.id, locker.chainId))
167
+ const raw = {
168
+ tokenLocked: getRes(res.shift()),
169
+ veBalanceOfLocker: formatRes(res.shift()),
170
+ totalTokenLocked: formatRes(res.shift()),
171
+ veTotalSupply: formatRes(res.shift()),
172
+ totalSupplyStaked: formatRes(res.shift()),
173
+ gaugeWorkingSupply: formatRes(res.shift()),
174
+ amountTokenNotLock: formatRes(res.shift()),
175
+ sdTokenInPool: formatRes(res.shift()),
176
+ peg: getRes(res.shift()),
177
+ rewards: rewards.map(() => getRes(res.shift())),
178
+ veBoost: {
179
+ delegated: formatRes(res.shift()),
180
+ weeklyRewards: range(0, 5).map(() => getRes(res.shift())),
181
+ },
182
+ veTokenRate: '4',
183
+ _workingSupply: '0',
184
+ _veBalanceOfLocker: '0',
185
+ }
186
+
187
+ raw.tokenLocked = format(raw.tokenLocked[0])
188
+ raw.peg = parsePeg(locker, raw.peg[1] * BigInt(-1))
189
+ raw._workingSupply = raw.gaugeWorkingSupply
190
+ raw._veBalanceOfLocker = raw.veBalanceOfLocker
191
+
192
+ return parse({ locker, common, prices, raw })
193
+ }
194
+
195
+ export default balancerLocker