1
+ const lendingPoolABI = require ( './lending-pool.json' ) ;
2
+ const sdk = require ( '@defillama/sdk' ) ;
3
+ const ethers = require ( 'ethers' ) ;
4
+ const utils = require ( '../utils' ) ;
5
+ const axios = require ( 'axios' ) ;
6
+
7
+
8
+ const config = {
9
+ ethereum : [ "0xB7858b66dFA38b9Cb74d00421316116A7851c273" , "0x80E1048eDE66ec4c364b4F22C8768fc657FF6A42" , "0x18a5a3D575F34e5eBa92ac99B0976dBe26f9F869" , "0xEBac5e50003d4B17Be422ff9775043cD61002f7f" , "0xd684AF965b1c17D628ee0d77cae94259c41260F4" , "0x5Fde59415625401278c4d41C6beFCe3790eb357f" ] ,
10
+ avax : [ "0x3408b22d8895753C9A3e14e4222E981d4E9A599E" ] ,
11
+ base : [ "0x4e2D90f0307A93b54ACA31dc606F93FE6b9132d2" ]
12
+ }
13
+ const rewardConfig = {
14
+ "0x3408b22d8895753C9A3e14e4222E981d4E9A599E" : "0xAeAc5f82B140c0f7309f7E9Ec43019062A5e5BE2" ,
15
+ }
16
+
17
+ const chainMapping = {
18
+ ethereum : {
19
+ chain : 'ethereum' ,
20
+ chainId : '1' ,
21
+ nativeToken : ethers . constants . AddressZero ,
22
+ decimals : 18 ,
23
+ symbol : 'ETH' ,
24
+ } ,
25
+ avax : {
26
+ chain : 'avax' ,
27
+ chainId : '43114' ,
28
+ nativeToken : ethers . constants . AddressZero ,
29
+ decimals : 18 ,
30
+ symbol : 'AVAX' ,
31
+ } ,
32
+ base : {
33
+ chain : 'base' ,
34
+ chainId : '8453' ,
35
+ nativeToken : ethers . constants . AddressZero ,
36
+ decimals : 18 ,
37
+ symbol : 'ETH' ,
38
+ }
39
+ }
40
+
41
+ const APR_MULTIPLIER = 31536000 ;
42
+ const projectName = 'upshift' ;
43
+
44
+ const getApy = async ( ) => {
45
+ const poolInfos = [ ] ;
46
+
47
+ const ethereumPools = await Promise . all (
48
+ config . ethereum . map ( async ( pool ) => {
49
+ return await getPoolInfo ( pool , 'ethereum' ) ;
50
+ } ) ,
51
+ ) ;
52
+
53
+ poolInfos . push ( ...ethereumPools ) ;
54
+
55
+ const avaxPools = await Promise . all (
56
+ config . avax . map ( async ( pool ) => {
57
+ return await getPoolInfo ( pool , 'avax' ) ;
58
+ } ) ,
59
+ ) ;
60
+
61
+ poolInfos . push ( ...avaxPools ) ;
62
+
63
+ const basePools = await Promise . all (
64
+ config . base . map ( async ( pool ) => {
65
+ return await getPoolInfo ( pool , 'base' ) ;
66
+ } ) ,
67
+ ) ;
68
+
69
+ poolInfos . push ( ...basePools ) ;
70
+
71
+ return poolInfos ;
72
+ }
73
+
74
+ const getPoolActiveLoans = async ( pool , chain ) => {
75
+ let loans = [ ] ;
76
+
77
+ let loanCount = ( await sdk . api . abi . call ( {
78
+ target : pool ,
79
+ abi : lendingPoolABI . find ( abi => abi . name === 'getTotalLoansDeployed' ) ,
80
+ chain : chain ,
81
+ } ) ) ?. output ;
82
+
83
+ const indexArray = [
84
+ ...Array ( Number ( loanCount ) ) . keys ( ) ,
85
+ ] ;
86
+
87
+ loans = await Promise . all (
88
+ indexArray . map ( async ( i ) => {
89
+ const loansDeployed = ( await sdk . api . abi . call ( {
90
+ target : pool ,
91
+ params : i ,
92
+ abi : lendingPoolABI . find ( abi => abi . name === 'loansDeployed' ) ,
93
+ chain : chain ,
94
+ } ) ) ?. output ;
95
+ return loansDeployed ;
96
+ } ) ,
97
+ ) ;
98
+
99
+
100
+ const states = await Promise . all (
101
+ loans . map ( async ( loan ) => {
102
+ const state = ( await sdk . api . abi . call ( {
103
+ target : loan ,
104
+ abi : 'function loanState() view returns (uint8)' ,
105
+ chain : chain ,
106
+ } ) ) ?. output ;
107
+ return state ;
108
+ } ) ,
109
+ ) ;
110
+
111
+ // filter loan if state is 4 (active)
112
+ const activeLoans = loans . filter ( ( loan , i ) => states [ i ] === '4' ) ;
113
+ return activeLoans ;
114
+ } ;
115
+
116
+ const getPoolInfo = async ( pool , chain ) => {
117
+
118
+ const symbol = ( await sdk . api . abi . call ( {
119
+ target : pool ,
120
+ abi : lendingPoolABI . find ( abi => abi . name === 'symbol' ) ,
121
+ chain : chain ,
122
+ } ) ) ?. output ;
123
+
124
+ const underlying_token = ( await sdk . api . abi . call ( {
125
+ target : pool ,
126
+ abi : lendingPoolABI . find ( abi => abi . name === 'asset' ) ,
127
+ chain : chain ,
128
+ } ) ) ?. output ;
129
+
130
+ const totalSupply = ( await sdk . api . abi . call ( {
131
+ target : pool ,
132
+ abi : lendingPoolABI . find ( abi => abi . name === 'totalSupply' ) ,
133
+ chain : chain ,
134
+ } ) ) ?. output ;
135
+
136
+ const totalAsset = ( await sdk . api . abi . call ( {
137
+ target : pool ,
138
+ abi : lendingPoolABI . find ( abi => abi . name === 'totalAssets' ) ,
139
+ chain : chain ,
140
+ } ) ) ?. output ;
141
+
142
+ const pool_decimals = ( await sdk . api . abi . call ( {
143
+ target : pool ,
144
+ abi : 'erc20:decimals' ,
145
+ chain : chain ,
146
+ } ) ) ?. output ;
147
+
148
+ const underlyingDecimals = ( await sdk . api . abi . call ( {
149
+ target : underlying_token ,
150
+ abi : 'erc20:decimals' ,
151
+ chain : chain ,
152
+ } ) ) ?. output ;
153
+
154
+
155
+ const priceKey = `${ utils . formatChain ( chain ) } :${ underlying_token } ` ;
156
+ const underlyingPrice = ( await axios . get ( `https://coins.llama.fi/prices/current/${ priceKey } ` ) ) . data . coins [ priceKey ] ?. price ;
157
+
158
+ const tvlUsd = Number ( ethers . utils . formatUnits ( totalAsset , underlyingDecimals ) ) * underlyingPrice ;
159
+
160
+ let aggregateApr = BigInt ( 0 ) ;
161
+
162
+ const loans = await getPoolActiveLoans ( pool , chain ) ;
163
+
164
+ const newLoans = (
165
+ await Promise . all (
166
+ loans ?. map ( async ( loanAddress ) => {
167
+ const [ _loanApr , _principalAmt , _collateral , _principalRepaid ] =
168
+ await Promise . all ( [
169
+ sdk . api . abi . call ( {
170
+ target : loanAddress ,
171
+ abi : 'function currentApr() view returns (uint256)' ,
172
+ chain
173
+ } ) ,
174
+ sdk . api . abi . call ( {
175
+ target : loanAddress ,
176
+ abi : 'function principalAmount() view returns (uint256)' ,
177
+ chain
178
+ } ) ,
179
+ sdk . api . abi . call ( {
180
+ target : loanAddress ,
181
+ abi : 'function collateralToken() view returns (address)' ,
182
+ chain
183
+ } ) ,
184
+ sdk . api . abi . call ( {
185
+ target : loanAddress ,
186
+ abi : 'function principalRepaid() view returns (uint256)' ,
187
+ chain
188
+ } ) ,
189
+ sdk . api . abi . call ( {
190
+ target : loanAddress ,
191
+ abi : 'function principalToken() view returns (address)' ,
192
+ chain
193
+ } ) ,
194
+ ] ) ;
195
+
196
+ let _principalDecimals = 18 ;
197
+ if ( _collateral . output !== ethers . constants . AddressZero ) {
198
+ const collateralDecimals = await sdk . api . abi . call ( {
199
+ target : _collateral . output ,
200
+ abi : 'function decimals() view returns (uint8)' ,
201
+ chain
202
+ } ) ;
203
+ _principalDecimals = collateralDecimals . output ;
204
+ }
205
+ // handle aprs
206
+ aggregateApr += _loanApr . output || BigInt ( 0 ) ;
207
+
208
+
209
+ const loanApr = Number ( _loanApr . output || 0 ) / 100 ;
210
+
211
+ const allocation =
212
+ Number ( ethers . utils . formatUnits ( _principalAmt . output , _principalDecimals ) ) /
213
+ Number ( ethers . utils . formatUnits ( totalSupply , _principalDecimals ) ) ;
214
+
215
+ const newLoanObj = {
216
+ address : loanAddress ,
217
+ apr : loanApr ,
218
+ allocation,
219
+ } ;
220
+
221
+ return newLoanObj ;
222
+ } ) ,
223
+ )
224
+ ) . filter ( ( l ) => l !== undefined ) ;
225
+
226
+ const weightedAverage = newLoans . reduce (
227
+ ( acc , { apr, allocation } ) => acc + apr * allocation ,
228
+ 0 ,
229
+ ) ;
230
+
231
+ if ( rewardConfig [ pool ] ) {
232
+ const rewardDistributor = rewardConfig [ pool ] ;
233
+
234
+ const rewardToken = [ chainMapping [ chain ] . nativeToken ] ;
235
+
236
+ const totalStaked = await sdk . api . abi . call ( {
237
+ target : rewardDistributor ,
238
+ abi : 'function totalStaked() view returns (uint256)' ,
239
+ chain
240
+ } ) ;
241
+ const rewardsPerSecond = await sdk . api . abi . call ( {
242
+ target : rewardDistributor ,
243
+ abi : 'function rewardsPerSecond() view returns (uint256)' ,
244
+ chain
245
+ } ) ;
246
+
247
+ const priceKey = `${ utils . formatChain ( chain ) } :${ rewardToken [ 0 ] } ` ;
248
+ const rewardTokenPrice = ( await axios . get ( `https://coins.llama.fi/prices/current/${ priceKey } ` ) ) . data . coins [ priceKey ] ?. price ;
249
+
250
+ const rewardAPR =
251
+ ( ( Number ( ethers . utils . formatUnits ( rewardsPerSecond . output , chainMapping [ chain ] . decimals ) ) *
252
+ APR_MULTIPLIER *
253
+ rewardTokenPrice ) /
254
+ ( ethers . utils . formatUnits ( totalStaked . output , pool_decimals ) * Number ( 1 ) ) ) *
255
+ 100 ;
256
+
257
+ return {
258
+ pool : `${ pool } -${ utils . formatChain ( chain ) } ` ,
259
+ chain : utils . formatChain ( chain ) ,
260
+ project : projectName ,
261
+ symbol : symbol ,
262
+ tvlUsd : tvlUsd ,
263
+ apyBase : weightedAverage ,
264
+ apyReward : rewardAPR ,
265
+ rewardTokens : rewardToken ,
266
+ underlyingTokens : [ underlying_token ] ,
267
+ }
268
+ }
269
+
270
+ return {
271
+ pool : `${ pool } -${ utils . formatChain ( chain ) } ` ,
272
+ chain : utils . formatChain ( chain ) ,
273
+ project : projectName ,
274
+ symbol : symbol ,
275
+ tvlUsd : tvlUsd ,
276
+ apyBase : weightedAverage ,
277
+ underlyingTokens : [ underlying_token ] ,
278
+ }
279
+ } ;
280
+
281
+ module . exports = {
282
+ timetravel : false ,
283
+ apy : getApy ,
284
+ url : 'https://www.upshift.finance/'
285
+ } ;
0 commit comments