1
+ const sdk = require ( '@defillama/sdk' ) ;
2
+ const superagent = require ( 'superagent' ) ;
3
+
4
+ const BOLD_TOKEN = '0x6440f144b7e50d6a8439336510312d2f54beb01d' ;
5
+
6
+ const WETH_BRANCH = {
7
+ activePool : '0xeb5a8c825582965f1d84606e078620a84ab16afe' ,
8
+ defaultPool : '0xd4558240d50c2e219a21c9d25afd513bb6e5b1a0' ,
9
+ stabilityPool : '0x5721cbbd64fc7ae3ef44a0a3f9a790a9264cf9bf' ,
10
+ borrowerOperations : '0x0b995602b5a797823f92027e8b40c0f2d97aff1c' ,
11
+ collToken : '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' . toLowerCase ( ) ,
12
+ symbol : 'ETH'
13
+ }
14
+
15
+ const WSTETH_BRANCH = {
16
+ activePool : '0x531a8f99c70d6a56a7cee02d6b4281650d7919a0' ,
17
+ defaultPool : '0xd796e1648526400386cc4d12fa05e5f11e6a22a1' ,
18
+ stabilityPool : '0x9502b7c397e9aa22fe9db7ef7daf21cd2aebe56b' ,
19
+ borrowerOperations : '0x94c1610a7373919bd9cfb09ded19894601f4a1be' ,
20
+ collToken : '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0' . toLowerCase ( ) ,
21
+ symbol : 'WSTETH'
22
+ }
23
+
24
+ const RETH_BRANCH = {
25
+ activePool : '0x9074d72cc82dad1e13e454755aa8f144c479532f' ,
26
+ defaultPool : '0x5cc5cefd034fdc4728d487a72ca58a410cddcd6b' ,
27
+ stabilityPool : '0xd442e41019b7f5c4dd78f50dc03726c446148695' ,
28
+ borrowerOperations : '0xa351d5b9cda9eb518727c3ceff02208915fda60d' ,
29
+ collToken : '0xae78736cd615f374d3085123a210448e74fc6393' . toLowerCase ( ) ,
30
+ symbol : 'RETH'
31
+ }
32
+
33
+ const branches = [ WETH_BRANCH , WSTETH_BRANCH , RETH_BRANCH ] ;
34
+
35
+ const SP_YIELD_SPLIT = 0.75 ;
36
+
37
+ const ABIS = {
38
+ getTotalBoldDeposits : {
39
+ inputs : [ ] ,
40
+ name : 'getTotalBoldDeposits' ,
41
+ outputs : [
42
+ {
43
+ internalType : 'uint256' ,
44
+ name : 'totalBoldDeposits' ,
45
+ type : 'uint256' ,
46
+ } ,
47
+ ] ,
48
+ stateMutability : 'view' ,
49
+ type : 'function' ,
50
+ } ,
51
+ getCollBalance : {
52
+ inputs : [ ] ,
53
+ name : 'getCollBalance' ,
54
+ outputs : [
55
+ {
56
+ internalType : 'uint256' ,
57
+ name : 'collBalance' ,
58
+ type : 'uint256' ,
59
+ } ,
60
+ ] ,
61
+ stateMutability : 'view' ,
62
+ type : 'function' ,
63
+ } ,
64
+ getBoldDebt : {
65
+ inputs : [ ] ,
66
+ name : 'getBoldDebt' ,
67
+ outputs : [
68
+ {
69
+ internalType : 'uint256' ,
70
+ name : 'boldDebt' ,
71
+ type : 'uint256' ,
72
+ } ,
73
+ ] ,
74
+ stateMutability : 'view' ,
75
+ type : 'function' ,
76
+ } ,
77
+ getMCR : {
78
+ inputs : [ ] ,
79
+ name : 'MCR' ,
80
+ outputs : [ { internalType : 'uint256' , name : '' , type : 'uint256' } ] ,
81
+ stateMutability : 'view' ,
82
+ type : 'function' ,
83
+ } ,
84
+ getNewApproxAvgInterestRateFromTroveChange : {
85
+ inputs : [
86
+ {
87
+ components : [
88
+ {
89
+ internalType : 'uint256' ,
90
+ name : 'appliedRedistBoldDebtGain' ,
91
+ type : 'uint256' ,
92
+ } ,
93
+ {
94
+ internalType : 'uint256' ,
95
+ name : 'appliedRedistCollGain' ,
96
+ type : 'uint256' ,
97
+ } ,
98
+ {
99
+ internalType : 'uint256' ,
100
+ name : 'collIncrease' ,
101
+ type : 'uint256' ,
102
+ } ,
103
+ {
104
+ internalType : 'uint256' ,
105
+ name : 'collDecrease' ,
106
+ type : 'uint256' ,
107
+ } ,
108
+ {
109
+ internalType : 'uint256' ,
110
+ name : 'debtIncrease' ,
111
+ type : 'uint256' ,
112
+ } ,
113
+ {
114
+ internalType : 'uint256' ,
115
+ name : 'debtDecrease' ,
116
+ type : 'uint256' ,
117
+ } ,
118
+ {
119
+ internalType : 'uint256' ,
120
+ name : 'newWeightedRecordedDebt' ,
121
+ type : 'uint256' ,
122
+ } ,
123
+ {
124
+ internalType : 'uint256' ,
125
+ name : 'oldWeightedRecordedDebt' ,
126
+ type : 'uint256' ,
127
+ } ,
128
+ {
129
+ internalType : 'uint256' ,
130
+ name : 'upfrontFee' ,
131
+ type : 'uint256' ,
132
+ } ,
133
+ {
134
+ internalType : 'uint256' ,
135
+ name : 'batchAccruedManagementFee' ,
136
+ type : 'uint256' ,
137
+ } ,
138
+ {
139
+ internalType : 'uint256' ,
140
+ name : 'newWeightedRecordedBatchManagementFee' ,
141
+ type : 'uint256' ,
142
+ } ,
143
+ {
144
+ internalType : 'uint256' ,
145
+ name : 'oldWeightedRecordedBatchManagementFee' ,
146
+ type : 'uint256' ,
147
+ } ,
148
+ ] ,
149
+ internalType : 'struct TroveChange' ,
150
+ name : '_troveChange' ,
151
+ type : 'tuple' ,
152
+ } ,
153
+ ] ,
154
+ name : 'getNewApproxAvgInterestRateFromTroveChange' ,
155
+ outputs : [
156
+ {
157
+ internalType : 'uint256' ,
158
+ name : '' ,
159
+ type : 'uint256' ,
160
+ } ,
161
+ ] ,
162
+ stateMutability : 'view' ,
163
+ type : 'function' ,
164
+ }
165
+ } ;
166
+
167
+ const getSPSupplyAndApy = async ( spAddr , avgBranchInterestRate , branchBoldSupply ) => {
168
+ const spSupply = ( await sdk . api . abi . call ( {
169
+ target : spAddr ,
170
+ abi : ABIS . getTotalBoldDeposits ,
171
+ chain : 'ethereum' ,
172
+ } ) ) . output / 1e18 ;
173
+
174
+ // Yield is the branch interest rate amplifyed by ratio of branch supply to the BOLD in the SP
175
+ const spApy = avgBranchInterestRate * SP_YIELD_SPLIT * branchBoldSupply / spSupply ;
176
+
177
+ return [ spSupply , spApy ] ;
178
+ }
179
+
180
+ const getPrices = async ( addresses ) => {
181
+ const req = addresses . map ( ( address ) => `ethereum:${ address } ` ) . join ( ',' ) . toLowerCase ( ) ;
182
+ const prices = ( await superagent . get ( `https://coins.llama.fi/prices/current/${ req } ` ) ) . body . coins ;
183
+
184
+ const pricesObj = Object . fromEntries (
185
+ Object . entries ( prices ) . map ( ( [ address , priceData ] ) => [ address . split ( ':' ) [ 1 ] . toLowerCase ( ) , priceData . price ] )
186
+ ) ;
187
+
188
+ return pricesObj ;
189
+ }
190
+
191
+ const getBranchColl = async ( collPools ) => {
192
+ const results = await sdk . api . abi . multiCall ( {
193
+ calls : collPools . map ( ( poolAddr ) => ( {
194
+ target : poolAddr ,
195
+ params : [ ] ,
196
+ } ) ) ,
197
+ abi : ABIS . getCollBalance ,
198
+ chain : 'ethereum' ,
199
+ } ) ;
200
+
201
+ const totalColl = results . output . map ( x => Number ( x . output ) ) . reduce ( ( a , b ) => a + b ) ;
202
+ return totalColl / 1e18 ;
203
+ }
204
+
205
+ const getBranchDebt = async ( debtPools ) => {
206
+ const results = await sdk . api . abi . multiCall ( {
207
+ calls : debtPools . map ( ( poolAddr ) => ( {
208
+ target : poolAddr ,
209
+ params : [ ] ,
210
+ } ) ) ,
211
+ abi : ABIS . getBoldDebt ,
212
+ chain : 'ethereum' ,
213
+ } ) ;
214
+
215
+ const totalDebt = results . output . map ( x => Number ( x . output ) ) . reduce ( ( a , b ) => a + b ) ;
216
+ return totalDebt / 1e18 ;
217
+ }
218
+
219
+ const getLTV = async ( borrowerOpsAddr ) => {
220
+ const res = ( await sdk . api . abi . call ( {
221
+ target : borrowerOpsAddr ,
222
+ abi : ABIS . getMCR ,
223
+ chain : 'ethereum' ,
224
+ } )
225
+ ) ;
226
+
227
+ return 1 / ( res . output / 1e18 ) ;
228
+ }
229
+
230
+ const getNewApproxAvgInterestRateFromTroveChange = async ( activePoolAddr ) => {
231
+ const res = await sdk . api . abi . call ( {
232
+ target : activePoolAddr ,
233
+ abi : ABIS . getNewApproxAvgInterestRateFromTroveChange ,
234
+ params : [
235
+ [ 0 , // appliedRedistBoldDebtGain
236
+ 0 , // appliedRedistCollGain
237
+ 0 , // collIncrease
238
+ 0 , // collDecrease
239
+ 0 , // debtIncrease
240
+ 0 , // debtDecrease
241
+ 0 , // newWeightedRecordedDebt
242
+ 0 , // oldWeightedRecordedDebt
243
+ 0 , // upfrontFee
244
+ 0 , // batchAccruedManagementFee
245
+ 0 , // newWeightedRecordedBatchManagementFee
246
+ 0 ] // oldWeightedRecordedBatchManagementFee
247
+ ] ,
248
+ chain : 'ethereum' ,
249
+ } ) ;
250
+
251
+ // convert from 18 decimals and make percentage
252
+ return res . output / 1e16 ;
253
+ }
254
+
255
+ const main = async ( ) => {
256
+ const prices = await getPrices (
257
+ [ WETH_BRANCH . collToken ,
258
+ WSTETH_BRANCH . collToken ,
259
+ RETH_BRANCH . collToken ,
260
+ BOLD_TOKEN
261
+ ]
262
+ ) ;
263
+
264
+ WETH_BRANCH . price = prices [ WETH_BRANCH . collToken ] ;
265
+ WSTETH_BRANCH . price = prices [ WSTETH_BRANCH . collToken ] ;
266
+ RETH_BRANCH . price = prices [ RETH_BRANCH . collToken ] ;
267
+
268
+ const pools = [ ] ;
269
+
270
+ for ( const branch of branches ) {
271
+ const collPools = [ branch . activePool , branch . defaultPool ] ;
272
+
273
+ const totalColl = await getBranchColl ( collPools ) ;
274
+ const totalCollUsd = totalColl * branch . price
275
+
276
+ const ltv = await getLTV ( branch . borrowerOperations ) ;
277
+ const borrowApy = await getNewApproxAvgInterestRateFromTroveChange ( branch . activePool ) ;
278
+
279
+ const totalDebt = await getBranchDebt ( collPools ) ;
280
+ const totalDebtUsd = totalDebt * prices [ BOLD_TOKEN ] ;
281
+
282
+ const [ spSupply , spApy ] = await getSPSupplyAndApy ( branch . stabilityPool , borrowApy , totalDebt ) ;
283
+ const spSupplyUsd = spSupply * prices [ BOLD_TOKEN ] ;
284
+
285
+ const spPool =
286
+ {
287
+ pool : branch . stabilityPool ,
288
+ project : 'liquity-v2' ,
289
+ symbol : 'BOLD' ,
290
+ chain : 'ethereum' ,
291
+ apy : spApy ,
292
+ tvlUsd : spSupplyUsd ,
293
+ underlyingTokens : [ BOLD_TOKEN ] ,
294
+ rewardTokens : [ BOLD_TOKEN , branch . collToken ] ,
295
+ poolMeta : `BOLD deposited in the ${ branch . symbol } Stability Pool earns continuous BOLD yield and periodic ${ branch . symbol } rewards from Trove liquidations`
296
+ }
297
+
298
+ const borrowPool =
299
+ {
300
+ pool : branch . activePool ,
301
+ project : 'liquity-v2' ,
302
+ symbol : branch . symbol ,
303
+ chain : 'ethereum' ,
304
+ apy : 0 ,
305
+ tvlUsd : totalCollUsd ,
306
+ apyBaseBorrow : borrowApy ,
307
+ totalSupplyUsd : totalCollUsd ,
308
+ totalBorrowUsd : totalDebtUsd ,
309
+ ltv : ltv ,
310
+ mintedCoin : 'BOLD' ,
311
+ underlyingTokens : [ branch . collToken ] ,
312
+ }
313
+
314
+ pools . push ( spPool , borrowPool ) ;
315
+ } ;
316
+
317
+ return pools ;
318
+ }
319
+
320
+ module . exports = {
321
+ timetravel : false ,
322
+ apy : main ,
323
+ url : 'https://www.liquity.org/' ,
324
+ } ;
0 commit comments