@1delta/margin-fetcher 0.0.34 → 0.0.36

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 (77) hide show
  1. package/dist/abis/morpho/lens.d.ts +38 -15
  2. package/dist/abis/morpho/lens.d.ts.map +1 -1
  3. package/dist/abis/morpho/lens.js +30 -20
  4. package/dist/flash-liquidity/assets.d.ts +2 -2
  5. package/dist/flash-liquidity/assets.d.ts.map +1 -1
  6. package/dist/flash-liquidity/assets.js +2 -2
  7. package/dist/flash-liquidity/fetchLiquidity.d.ts.map +1 -1
  8. package/dist/flash-liquidity/fetchLiquidity.js +2 -2
  9. package/dist/lending/fetchLender.d.ts.map +1 -1
  10. package/dist/lending/fetchLender.js +24 -5
  11. package/dist/lending/fetchLenderAll.d.ts.map +1 -1
  12. package/dist/lending/fetchLenderAll.js +15 -3
  13. package/dist/lending/morpho/chainsConfigs.d.ts +21 -0
  14. package/dist/lending/morpho/chainsConfigs.d.ts.map +1 -0
  15. package/dist/lending/morpho/chainsConfigs.js +234 -0
  16. package/dist/lending/morpho/constants/markets.d.ts +4 -0
  17. package/dist/lending/morpho/constants/markets.d.ts.map +1 -0
  18. package/dist/lending/morpho/constants/markets.js +63 -0
  19. package/dist/lending/morpho/convertPublic.d.ts.map +1 -1
  20. package/dist/lending/morpho/convertPublic.js +2 -13
  21. package/dist/lending/morpho/getMarketsFromChain.d.ts +8 -0
  22. package/dist/lending/morpho/getMarketsFromChain.d.ts.map +1 -0
  23. package/dist/lending/morpho/getMarketsFromChain.js +318 -0
  24. package/dist/lending/morpho/publicCallBuild.d.ts +5 -0
  25. package/dist/lending/morpho/publicCallBuild.d.ts.map +1 -1
  26. package/dist/lending/morpho/publicCallBuild.js +16 -0
  27. package/dist/lending/morpho/utils/evmParser.d.ts +22 -0
  28. package/dist/lending/morpho/utils/evmParser.d.ts.map +1 -0
  29. package/dist/lending/morpho/utils/evmParser.js +103 -0
  30. package/dist/lending/morpho/utils/mathLib.d.ts +125 -0
  31. package/dist/lending/morpho/utils/mathLib.d.ts.map +1 -0
  32. package/dist/lending/morpho/utils/mathLib.js +334 -0
  33. package/dist/lending/morpho/utils/parsers.d.ts +10 -0
  34. package/dist/lending/morpho/utils/parsers.d.ts.map +1 -0
  35. package/dist/lending/morpho/utils/parsers.js +37 -0
  36. package/dist/lending/user-data/aave-v2-type/userCallParse.js +2 -2
  37. package/dist/lending/user-data/aave-v3-type/userCallParse.js +2 -2
  38. package/dist/lending/user-data/aave-v3-type/userCallParseYldr.js +2 -2
  39. package/dist/lending/user-data/abis.d.ts +37 -14
  40. package/dist/lending/user-data/abis.d.ts.map +1 -1
  41. package/dist/lending/user-data/morpho/userCallBuild.d.ts +3 -0
  42. package/dist/lending/user-data/morpho/userCallBuild.d.ts.map +1 -1
  43. package/dist/lending/user-data/morpho/userCallBuild.js +9 -8
  44. package/dist/lending-pairs/computeLendingPairs.d.ts.map +1 -1
  45. package/dist/lending-pairs/computeLendingPairs.js +11 -7
  46. package/dist/prices/main-prices/fetchOracleData.d.ts +0 -2
  47. package/dist/prices/main-prices/fetchOracleData.d.ts.map +1 -1
  48. package/dist/prices/main-prices/fetchOracleData.js +2 -22
  49. package/dist/utils/index.d.ts.map +1 -1
  50. package/dist/utils/index.js +2 -5
  51. package/dist/utils/parsing.d.ts +2 -0
  52. package/dist/utils/parsing.d.ts.map +1 -1
  53. package/dist/utils/parsing.js +20 -0
  54. package/package.json +1 -1
  55. package/src/abis/morpho/lens.ts +40 -30
  56. package/src/flash-liquidity/assets.ts +3 -2
  57. package/src/flash-liquidity/fetchLiquidity.ts +3 -2
  58. package/src/lending/fetchLender.ts +29 -4
  59. package/src/lending/fetchLenderAll.ts +32 -12
  60. package/src/lending/morpho/chainsConfigs.ts +268 -0
  61. package/src/lending/morpho/constants/markets.ts +64 -0
  62. package/src/lending/morpho/convertPublic.ts +2 -14
  63. package/src/lending/morpho/getMarketsFromChain.ts +402 -0
  64. package/src/lending/morpho/publicCallBuild.ts +17 -0
  65. package/src/lending/morpho/utils/evmParser.ts +122 -0
  66. package/src/lending/morpho/utils/mathLib.ts +434 -0
  67. package/src/lending/morpho/utils/parsers.ts +53 -0
  68. package/src/lending/user-data/aave-v2-type/userCallParse.ts +2 -2
  69. package/src/lending/user-data/aave-v3-type/userCallParse.ts +2 -2
  70. package/src/lending/user-data/aave-v3-type/userCallParseYldr.ts +2 -2
  71. package/src/lending/user-data/morpho/userCallBuild.ts +9 -8
  72. package/src/lending-pairs/computeLendingPairs.ts +15 -10
  73. package/src/prices/main-prices/fetchOracleData.ts +2 -34
  74. package/src/utils/index.ts +3 -4
  75. package/src/utils/parsing.ts +32 -0
  76. package/test/lenderData.test.ts +1 -1
  77. package/test/mbChain.test.ts +44 -0
@@ -0,0 +1,434 @@
1
+ import { rateToApy, SECONDS_PER_YEAR } from './parsers'
2
+
3
+ export type RoundingDirection = 'Up' | 'Down'
4
+
5
+ /**
6
+ * Library to manage fixed-point arithmetic.
7
+ * https://github.com/morpho-org/morpho-blue/blob/main/src/libraries/MathLib.sol
8
+ */
9
+ export namespace MathLib {
10
+ export const WAD = 1_000000000000000000n
11
+ export const RAY = 1_000000000000000000000000000n
12
+
13
+ export const MAX_UINT_256 = maxUint(256)
14
+ export const MAX_UINT_160 = maxUint(160)
15
+ export const MAX_UINT_128 = maxUint(128)
16
+ export const MAX_UINT_48 = maxUint(48)
17
+
18
+ export function maxUint(nBits: number) {
19
+ if (nBits % 4 !== 0) throw new Error(`Invalid number of bits: ${nBits}`)
20
+
21
+ return BigInt(`0x${'f'.repeat(nBits / 4)}`)
22
+ }
23
+
24
+ /**
25
+ * Returns the absolute value of a number
26
+ * @param a The number
27
+ */
28
+ export function abs(a: bigint) {
29
+ a = BigInt(a)
30
+
31
+ return a >= 0 ? a : -a
32
+ }
33
+
34
+ /**
35
+ * Returns the smallest number given as param
36
+ * @param x The first number
37
+ * @param y The second number
38
+ */
39
+ export function min(...xs: bigint[]) {
40
+ return xs.map(BigInt).reduce((x, y) => (x <= y ? x : y))
41
+ }
42
+
43
+ /**
44
+ * Returns the greatest number given as param
45
+ * @param x The first number
46
+ * @param y The second number
47
+ */
48
+ export function max(...xs: bigint[]) {
49
+ return xs.map(BigInt).reduce((x, y) => (x <= y ? y : x))
50
+ }
51
+
52
+ /**
53
+ * Returns the subtraction of b from a, floored to zero if negative
54
+ * @param x The first number
55
+ * @param y The second number
56
+ */
57
+ export function zeroFloorSub(x: bigint, y: bigint) {
58
+ x = BigInt(x)
59
+ y = BigInt(y)
60
+
61
+ return x <= y ? 0n : x - y
62
+ }
63
+
64
+ /**
65
+ * Perform the WAD-based multiplication of 2 numbers, rounded down
66
+ * @param x The first number
67
+ * @param y The second number
68
+ */
69
+ export function wMulDown(x: bigint, y: bigint) {
70
+ return MathLib.wMul(x, y, 'Down')
71
+ }
72
+
73
+ /**
74
+ * Perform the WAD-based multiplication of 2 numbers, rounded up
75
+ * @param x The first number
76
+ * @param y The second number
77
+ */
78
+ export function wMulUp(x: bigint, y: bigint) {
79
+ return MathLib.wMul(x, y, 'Up')
80
+ }
81
+
82
+ /**
83
+ * Perform the WAD-based multiplication of 2 numbers with a provided rounding direction
84
+ * @param x The first number
85
+ * @param y The second number
86
+ */
87
+ export function wMul(x: bigint, y: bigint, rounding: RoundingDirection) {
88
+ return MathLib.mulDiv(x, y, MathLib.WAD, rounding)
89
+ }
90
+
91
+ /**
92
+ * Perform the WAD-based division of 2 numbers, rounded down
93
+ * @param x The first number
94
+ * @param y The second number
95
+ */
96
+ export function wDivDown(x: bigint, y: bigint) {
97
+ return MathLib.wDiv(x, y, 'Down')
98
+ }
99
+
100
+ /**
101
+ * Perform the WAD-based multiplication of 2 numbers, rounded up
102
+ * @param x The first number
103
+ * @param y The second number
104
+ */
105
+ export function wDivUp(x: bigint, y: bigint) {
106
+ return MathLib.wDiv(x, y, 'Up')
107
+ }
108
+
109
+ /**
110
+ * Perform the WAD-based multiplication of 2 numbers with a provided rounding direction
111
+ * @param x The first number
112
+ * @param y The second number
113
+ */
114
+ export function wDiv(x: bigint, y: bigint, rounding: RoundingDirection) {
115
+ return MathLib.mulDiv(x, MathLib.WAD, y, rounding)
116
+ }
117
+
118
+ /**
119
+ * Multiply two numbers and divide by a denominator, rounding down the result
120
+ * @param x The first number
121
+ * @param y The second number
122
+ * @param denominator The denominator
123
+ */
124
+ export function mulDivDown(x: bigint, y: bigint, denominator: bigint) {
125
+ x = BigInt(x)
126
+ y = BigInt(y)
127
+ denominator = BigInt(denominator)
128
+ if (denominator === 0n) throw Error('MathLib: DIVISION_BY_ZERO')
129
+
130
+ return (x * y) / denominator
131
+ }
132
+
133
+ /**
134
+ * Multiply two numbers and divide by a denominator, rounding up the result
135
+ * @param x The first number
136
+ * @param y The second number
137
+ * @param denominator The denominator
138
+ */
139
+ export function mulDivUp(x: bigint, y: bigint, denominator: bigint) {
140
+ x = BigInt(x)
141
+ y = BigInt(y)
142
+ denominator = BigInt(denominator)
143
+ if (denominator === 0n) throw Error('MathLib: DIVISION_BY_ZERO')
144
+
145
+ const roundup = (x * y) % denominator > 0 ? 1n : 0n
146
+
147
+ return (x * y) / denominator + roundup
148
+ }
149
+
150
+ export function mulDiv(
151
+ x: bigint,
152
+ y: bigint,
153
+ denominator: bigint,
154
+ rounding: RoundingDirection,
155
+ ) {
156
+ return MathLib[`mulDiv${rounding}`](x, y, denominator)
157
+ }
158
+
159
+ /**
160
+ * The sum of the first three non-zero terms of a Taylor expansion of e^(nx) - 1,
161
+ * to approximate a continuously compounded interest rate.
162
+ *
163
+ * @param x The base of the exponent
164
+ * @param n The exponent
165
+ */
166
+ export function wTaylorCompounded(x: bigint, n: bigint) {
167
+ const firstTerm = BigInt(x) * BigInt(n)
168
+ const secondTerm = MathLib.mulDivDown(
169
+ firstTerm,
170
+ firstTerm,
171
+ 2n * MathLib.WAD,
172
+ )
173
+ const thirdTerm = MathLib.mulDivDown(
174
+ secondTerm,
175
+ firstTerm,
176
+ 3n * MathLib.WAD,
177
+ )
178
+
179
+ return firstTerm + secondTerm + thirdTerm
180
+ }
181
+
182
+ /**
183
+ * Converts a WAD-based quantity to a RAY-based quantity.
184
+ * @param x The WAD-based quantity.
185
+ */
186
+ export function wToRay(x: bigint) {
187
+ return BigInt(x) * 1_000000000n
188
+ }
189
+
190
+ /**
191
+ * Returns the market's utilization rate (scaled by WAD).
192
+ * @param market The market state.
193
+ */
194
+ export function getUtilization({
195
+ totalSupplyAssets,
196
+ totalBorrowAssets,
197
+ }: {
198
+ totalSupplyAssets: bigint
199
+ totalBorrowAssets: bigint
200
+ }) {
201
+ if (totalSupplyAssets === 0n) {
202
+ if (totalBorrowAssets > 0n) return MathLib.MAX_UINT_256
203
+
204
+ return 0n
205
+ }
206
+
207
+ return MathLib.wDivDown(totalBorrowAssets, totalSupplyAssets)
208
+ }
209
+
210
+ /**
211
+ * The market's instantaneous supply-side Annual Percentage Yield (APY) at the given timestamp,
212
+ * if the state remains unchanged (not accrued) (scaled by WAD).
213
+ * @param timestamp The timestamp at which to calculate the supply APY.
214
+ * Must be greater than or equal to `lastUpdate`.
215
+ * Defaults to `Time.timestamp()` (returns the current supply APY).
216
+ */
217
+ export function getSupplyApy(
218
+ borrowApy: bigint,
219
+ utilization: bigint,
220
+ fee: bigint,
221
+ ) {
222
+ if (!utilization) return 0n
223
+ return MathLib.wMulUp(
224
+ MathLib.wMulDown(borrowApy, utilization),
225
+ MathLib.WAD - fee,
226
+ )
227
+ }
228
+
229
+ /**
230
+ * Returns the rates that _would_ apply to interest accrual for borrowers of this market,
231
+ * if `accrueInterest` was called at the given timestamp (scaled by WAD).
232
+ * @param timestamp The timestamp at which to calculate the accrual borrow rate.
233
+ * Must be greater than or equal to `lastUpdate`.
234
+ * Defaults to `Time.timestamp()` (returns the current accrual borrow rate).
235
+ */
236
+ function getAccrualBorrowRates(
237
+ rateAtTarget: bigint | null,
238
+ utilization: bigint,
239
+ _timestamp: number = Math.floor(Date.now() / 1000),
240
+ _lastUpdate: number,
241
+ ):
242
+ | {
243
+ elapsed: bigint
244
+ avgBorrowRate: bigint
245
+ endBorrowRate: bigint
246
+ endRateAtTarget?: bigint
247
+ }
248
+ | undefined {
249
+ const timestamp = BigInt(_timestamp)
250
+
251
+ const elapsed = timestamp - BigInt(_lastUpdate)
252
+ if (elapsed < 0n) return undefined
253
+
254
+ if (rateAtTarget == null)
255
+ return {
256
+ elapsed,
257
+ avgBorrowRate: 0n,
258
+ endBorrowRate: 0n,
259
+ }
260
+
261
+ return {
262
+ elapsed,
263
+ ..._getBorrowRate(utilization, rateAtTarget, elapsed),
264
+ }
265
+ }
266
+
267
+ /**
268
+ */
269
+ function getEndBorrowRate(
270
+ rateAtTarget: bigint | null,
271
+ utilization: bigint,
272
+ _timestamp: number = Math.floor(Date.now() / 1000),
273
+ _lastUpdate: number,
274
+ ) {
275
+ return getAccrualBorrowRates(
276
+ rateAtTarget,
277
+ utilization,
278
+ _timestamp,
279
+ _lastUpdate,
280
+ )?.endBorrowRate
281
+ }
282
+
283
+ export function getBorrowApy(
284
+ rateAtTarget: bigint | null,
285
+ utilization: bigint,
286
+ _timestamp: number = Math.floor(Date.now() / 1000),
287
+ _lastUpdate: number,
288
+ ) {
289
+ const borrowRate = getEndBorrowRate(
290
+ rateAtTarget,
291
+ utilization,
292
+ _timestamp,
293
+ _lastUpdate,
294
+ )
295
+
296
+ return borrowRate ? rateToApy(borrowRate) : 0n
297
+ }
298
+
299
+ const CURVE_STEEPNESS = 4_000000000000000000n
300
+ const TARGET_UTILIZATION = 90_0000000000000000n
301
+ const INITIAL_RATE_AT_TARGET = 4_0000000000000000n / SECONDS_PER_YEAR
302
+ const ADJUSTMENT_SPEED = 50_000000000000000000n / SECONDS_PER_YEAR
303
+ const MIN_RATE_AT_TARGET = 10_00000000000000n / SECONDS_PER_YEAR
304
+ const MAX_RATE_AT_TARGET = 2_000000000000000000n / SECONDS_PER_YEAR
305
+
306
+ /**
307
+ * ln(2), scaled by WAD.
308
+ */
309
+ const LN_2_INT = 693147180559945309n
310
+
311
+ /**
312
+ * ln(1e-18), scaled by WAD.
313
+ */
314
+ const LN_WEI_INT = -41_446531673892822312n
315
+
316
+ /**
317
+ * Above this bound, `wExp` is clipped to avoid overflowing when multiplied with 1 ether.
318
+ * This upper bound corresponds to: ln(type(int256).max / 1e36) (scaled by WAD, floored).
319
+ */
320
+ const WEXP_UPPER_BOUND = 93_859467695000404319n
321
+
322
+ /**
323
+ * The value of wExp(`WEXP_UPPER_BOUND`).
324
+ */
325
+ const WEXP_UPPER_VALUE =
326
+ 57716089161558943949701069502944508345128_422502756744429568n
327
+
328
+ export function wExp(x: bigint) {
329
+ x = BigInt(x)
330
+
331
+ // If x < ln(1e-18) then exp(x) < 1e-18 so it is rounded to zero.
332
+ if (x < LN_WEI_INT) return 0n
333
+ // `wExp` is clipped to avoid overflowing when multiplied with 1 ether.
334
+ if (x >= WEXP_UPPER_BOUND) return WEXP_UPPER_VALUE
335
+
336
+ // Decompose x as x = q * ln(2) + r with q an integer and -ln(2)/2 <= r <= ln(2)/2.
337
+ // q = x / ln(2) rounded half toward zero.
338
+ const roundingAdjustment = x < 0n ? -(LN_2_INT / 2n) : LN_2_INT / 2n
339
+ const q = (x + roundingAdjustment) / LN_2_INT
340
+ const r = x - q * LN_2_INT
341
+
342
+ // Compute e^r with a 2nd-order Taylor polynomial.
343
+ const expR = MathLib.WAD + r + (r * r) / MathLib.WAD / 2n
344
+
345
+ // Return e^x = 2^q * e^r.
346
+ if (q >= 0n) return expR << q
347
+ return expR >> -q
348
+ }
349
+
350
+ export function _getBorrowRate(
351
+ startUtilization: bigint,
352
+ startRateAtTarget: bigint,
353
+ elapsed: bigint,
354
+ ) {
355
+ startUtilization = BigInt(startUtilization)
356
+ startRateAtTarget = BigInt(startRateAtTarget)
357
+ elapsed = BigInt(elapsed)
358
+
359
+ const errNormFactor =
360
+ startUtilization > TARGET_UTILIZATION
361
+ ? MathLib.WAD - TARGET_UTILIZATION
362
+ : TARGET_UTILIZATION
363
+ const err = MathLib.wDivDown(
364
+ startUtilization - TARGET_UTILIZATION,
365
+ errNormFactor,
366
+ )
367
+
368
+ let avgRateAtTarget: bigint
369
+ let endRateAtTarget: bigint
370
+
371
+ if (startRateAtTarget === 0n) {
372
+ // First interaction.
373
+ avgRateAtTarget = INITIAL_RATE_AT_TARGET
374
+ endRateAtTarget = INITIAL_RATE_AT_TARGET
375
+ } else {
376
+ // The speed is assumed constant between two updates, but it is in fact not constant because of interest.
377
+ // So the rate is always underestimated.
378
+ const speed = MathLib.wMulDown(ADJUSTMENT_SPEED, err)
379
+ const linearAdaptation = speed * elapsed
380
+
381
+ if (linearAdaptation === 0n) {
382
+ // If linearAdaptation == 0, avgRateAtTarget = endRateAtTarget = startRateAtTarget;
383
+ avgRateAtTarget = startRateAtTarget
384
+ endRateAtTarget = startRateAtTarget
385
+ } else {
386
+ // Non negative because MIN_RATE_AT_TARGET > 0.
387
+ const _newRateAtTarget = (linearAdaptation: bigint) =>
388
+ MathLib.min(
389
+ MathLib.max(
390
+ MathLib.wMulDown(startRateAtTarget, wExp(linearAdaptation)),
391
+ MIN_RATE_AT_TARGET,
392
+ ),
393
+ MAX_RATE_AT_TARGET,
394
+ )
395
+
396
+ // Formula of the average rate that should be returned to Morpho Blue:
397
+ // avg = 1/T * ∫_0^T curve(startRateAtTarget*exp(speed*x), err) dx
398
+ // The integral is approximated with the trapezoidal rule:
399
+ // avg ~= 1/T * Σ_i=1^N [curve(f((i-1) * T/N), err) + curve(f(i * T/N), err)] / 2 * T/N
400
+ // Where f(x) = startRateAtTarget*exp(speed*x)
401
+ // avg ~= Σ_i=1^N [curve(f((i-1) * T/N), err) + curve(f(i * T/N), err)] / (2 * N)
402
+ // As curve is linear in its first argument:
403
+ // avg ~= curve([Σ_i=1^N [f((i-1) * T/N) + f(i * T/N)] / (2 * N), err)
404
+ // avg ~= curve([(f(0) + f(T))/2 + Σ_i=1^(N-1) f(i * T/N)] / N, err)
405
+ // avg ~= curve([(startRateAtTarget + endRateAtTarget)/2 + Σ_i=1^(N-1) f(i * T/N)] / N, err)
406
+ // With N = 2:
407
+ // avg ~= curve([(startRateAtTarget + endRateAtTarget)/2 + startRateAtTarget*exp(speed*T/2)] / 2, err)
408
+ // avg ~= curve([startRateAtTarget + endRateAtTarget + 2*startRateAtTarget*exp(speed*T/2)] / 4, err)
409
+ endRateAtTarget = _newRateAtTarget(linearAdaptation)
410
+ avgRateAtTarget =
411
+ (startRateAtTarget +
412
+ endRateAtTarget +
413
+ 2n * _newRateAtTarget(linearAdaptation / 2n)) /
414
+ 4n
415
+ }
416
+ }
417
+
418
+ // Non negative because 1 - 1/C >= 0, C - 1 >= 0.
419
+ const coeff =
420
+ err < 0
421
+ ? MathLib.WAD - MathLib.wDivDown(MathLib.WAD, CURVE_STEEPNESS)
422
+ : CURVE_STEEPNESS - MathLib.WAD
423
+
424
+ const _curve = (rateAtTarget: bigint) =>
425
+ MathLib.wMulDown(MathLib.wMulDown(coeff, err) + MathLib.WAD, rateAtTarget)
426
+
427
+ // Non negative if avgRateAtTarget >= 0 because if err < 0, coeff <= 1.
428
+ return {
429
+ avgBorrowRate: _curve(avgRateAtTarget),
430
+ endBorrowRate: _curve(endRateAtTarget),
431
+ endRateAtTarget,
432
+ }
433
+ }
434
+ }
@@ -0,0 +1,53 @@
1
+ import { formatEther, formatUnits, parseUnits } from 'viem'
2
+
3
+ export const SECONDS_PER_YEAR = 31_556_952n
4
+
5
+ // Alternative to Number.toFixed that doesn't use scientific notation for excessively small or large numbers.
6
+ const toFixed = (x: number, decimals: number) =>
7
+ new Intl.NumberFormat('en-US', {
8
+ style: 'decimal',
9
+ useGrouping: false,
10
+ maximumFractionDigits: decimals,
11
+ minimumFractionDigits: decimals,
12
+ }).format(x)
13
+
14
+ const safeParseNumber = (value: number, decimals = 18) =>
15
+ safeParseUnits(toFixed(value, decimals), decimals)
16
+
17
+ const safeParseUnits = (strValue: string, decimals = 18) => {
18
+ if (!/[-+]?[0-9]*\.?[0-9]+/.test(strValue))
19
+ throw Error(`invalid number: ${strValue}`)
20
+
21
+ let [whole, dec = ''] = strValue.split('.')
22
+
23
+ dec = dec.slice(0, decimals)
24
+
25
+ return parseUnits(
26
+ [whole || '0', dec].filter((v) => v.length > 0).join('.'),
27
+ decimals,
28
+ )
29
+ }
30
+
31
+ /**
32
+ * Returns the per-second rate continuously compounded over a year (scaled by WAD),
33
+ * as calculated in Morpho Blue assuming the market is frequently accrued onchain.
34
+ * @param rate The per-second rate to compound annually (scaled by WAD).
35
+ */
36
+ // TODO: return a Number for APYs.
37
+ export function rateToApy(rate: bigint) {
38
+ return safeParseNumber(
39
+ Math.expm1(+formatEther(BigInt(rate) * SECONDS_PER_YEAR)),
40
+ )
41
+ }
42
+
43
+ export function parseLtv(ltv: bigint | number | string) {
44
+ let str = 0
45
+ try {
46
+ str = Number(formatUnits(BigInt(ltv), 18))
47
+ } catch (e) {}
48
+ return str
49
+ }
50
+
51
+ export function formatNr(n: string | bigint, d: number) {
52
+ return Number(formatUnits(BigInt(n ?? 0), d))
53
+ }
@@ -375,8 +375,8 @@ function createAaveV2Entry(
375
375
  const priceHist = pricesHist?.[key] ?? price
376
376
 
377
377
  const dataForAsset = {
378
- poolId: asset,
379
- underlying: asset,
378
+ poolId: asset.address,
379
+ underlying: asset.address,
380
380
  deposits: currentATokenBalance,
381
381
  depositsRaw: currentATokenBalanceRaw,
382
382
  debtStable: currentStableDebt,
@@ -114,8 +114,8 @@ function createAaveV3Entry(
114
114
  const priceHist = pricesHist?.[key] ?? price
115
115
 
116
116
  const dataForAsset = {
117
- poolId: asset,
118
- underlying: asset,
117
+ poolId: asset.address,
118
+ underlying: asset.address,
119
119
  deposits: currentATokenBalance,
120
120
  depositsRaw: currentATokenBalanceRaw,
121
121
  debtStable: currentStableDebt,
@@ -103,8 +103,8 @@ function createAaveV3Entry(
103
103
  const priceHist = pricesHist?.[key] ?? price
104
104
 
105
105
  const dataForAsset = {
106
- poolId: asset,
107
- underlying: asset,
106
+ poolId: asset.address,
107
+ underlying: asset.address,
108
108
  deposits: currentATokenBalance,
109
109
  depositsRaw: currentATokenBalanceRaw,
110
110
  debtStable: '0',
@@ -4,14 +4,15 @@ import { Call } from '../../../utils/multicall'
4
4
  import { chunk } from 'lodash'
5
5
  import { morphoPools } from '@1delta/data-sdk'
6
6
 
7
- const MORPHO_LENS: { [c: string]: string } = {
8
- [Chain.BASE]: '0x98542B95B44a4732EffB1F4F01A696F1546236d3',
9
- [Chain.POLYGON_MAINNET]: '0x105eb87D2b3127f43B1b4C0F125dbEb0EDF3d6C6',
10
- [Chain.OP_MAINNET]: '0xd184c5315B728c1C990f59dDD275c8155f8e255c',
11
- [Chain.ARBITRUM_ONE]: '0xF64F862Fb7D687411585e06C08711B612e156530',
12
- [Chain.KATANA]: '0xcB6Eb8df68153cebF60E1872273Ef52075a5C297',
13
- [Chain.HYPEREVM]: '0xCe434378adacC51d54312c872113D687Ac19B516',
14
- [Chain.ETHEREUM_MAINNET]: '0x0bd7473CbBf81d9dD936c61117eD230d95006CA2',
7
+ export const MORPHO_LENS: { [c: string]: string } = {
8
+ [Chain.BASE]: '0x05f3f58716a88A52493Be45aA0871c55b3748f18',
9
+ [Chain.POLYGON_MAINNET]: '0x04102873b1A80647879Aa8B8a119F07aE08f457a',
10
+ [Chain.OP_MAINNET]: '0x61895aEB0a42679E2Df8EE64334C405a8d47D244',
11
+ [Chain.ARBITRUM_ONE]: '0xeaC918F73Ba5b11D21D31a72BD00ca4A22865C3f',
12
+ [Chain.KATANA]: '0xCe434378adacC51d54312c872113D687Ac19B516',
13
+ [Chain.HYPEREVM]: '0x6Bc6aCB905c1216B0119C87Bf9E178ce298310FA',
14
+ [Chain.SONEIUM]: '0x4b5458BB47dCBC1a41B31b41e1a8773dE312BE9d',
15
+ [Chain.ETHEREUM_MAINNET]: '0x4b5458BB47dCBC1a41B31b41e1a8773dE312BE9d'
15
16
  }
16
17
 
17
18
  const getBaseMorphoCalls = (
@@ -6,7 +6,7 @@ import {
6
6
  } from '../assets/liquidityThresholds'
7
7
  import { GenericCurrency } from '../lending/types'
8
8
  import { ConfigEntry, LenderData, PoolData } from '../types'
9
- import { isAaveV3Type, isInit } from '../utils'
9
+ import { isAaveV3Type, isInit, isMorphoType } from '../utils'
10
10
 
11
11
  interface SimpleAssetInfo {
12
12
  asset: GenericCurrency
@@ -252,7 +252,8 @@ function getPriceKey(asset: GenericCurrency): [string, string] {
252
252
  const assetGroup = asset?.assetGroup
253
253
  return [
254
254
  assetGroup,
255
- toOracleKey(assetGroup) ?? toGenericPriceKey(asset.address, asset.chainId),
255
+ toOracleKey(assetGroup) ??
256
+ toGenericPriceKey(asset?.address, asset?.chainId),
256
257
  ]
257
258
  }
258
259
 
@@ -301,14 +302,18 @@ function filterPairsByCategory(
301
302
  p.assetGroupShort,
302
303
  )
303
304
 
304
- const longMeetsThresholds = meetsLiquidityThresholdsLong(
305
- {
306
- totalDepositsUSD: p.longTotalDepositsUSD,
307
- totalDebtUSD: p.longTotalDebtUSD,
308
- totalLiquidityUSD: p.longTotalLiquidityUSD,
309
- },
310
- longThresholds,
311
- )
305
+ // note: morpho does not allow to borrow collateral
306
+ // therefore, the collateral is always withdrawable if debt is repaid
307
+ const longMeetsThresholds =
308
+ isMorphoType(p.lender) ||
309
+ meetsLiquidityThresholdsLong(
310
+ {
311
+ totalDepositsUSD: p.longTotalDepositsUSD,
312
+ totalDebtUSD: p.longTotalDebtUSD,
313
+ totalLiquidityUSD: p.longTotalLiquidityUSD,
314
+ },
315
+ longThresholds,
316
+ )
312
317
 
313
318
  const shortMeetsThresholds = meetsLiquidityThresholdsShort(
314
319
  {
@@ -7,7 +7,7 @@ import { RWADynamicOracleAbi } from '../../abis/oracle/RWADynamicOracle'
7
7
  import { api3OracleAddresses } from './addresses/api3'
8
8
  import { AAVE_V2_LENDERS } from '@1delta/lender-registry'
9
9
  import { Chain } from '@1delta/chain-registry'
10
- import { formatEther, formatUnits } from 'viem'
10
+ import { formatUnits } from 'viem'
11
11
  import { getAaveAssets } from '../../assets'
12
12
  import {
13
13
  chainlinkOracles,
@@ -17,45 +17,13 @@ import {
17
17
  import { fetchDefillamaData } from '../defillama'
18
18
  import { fetchPendlePrices } from '../pendle'
19
19
  import { getAavesForChain } from '../../utils'
20
- import { parseRawAmount } from '../../utils/parsing'
20
+ import { formatAavePrice, formatMorphoPrice, parseRawAmount } from '../../utils/parsing'
21
21
  import { ProxyOracleAbi } from '../../abis/oracle/ProxyOracle'
22
22
  import { multicallRetry } from '@1delta/providers'
23
23
  import { TokenList } from '../../types'
24
24
  import { UniswapV3Abi } from '../../abis/oracle/UniV3'
25
25
  import { aaveOracles, morphoOracles } from '@1delta/data-sdk'
26
26
 
27
- export const formatAavePrice = (price: string, isV2 = false): number => {
28
- try {
29
- return Number(
30
- formatEther(
31
- BigInt(price ?? '0') *
32
- // 10^(18 - decimals)
33
- 10n ** (isV2 ? 0n : 10n),
34
- ),
35
- )
36
- } catch {
37
- return NaN
38
- }
39
- }
40
-
41
- export const formatMorphoPrice = (
42
- price: string,
43
- collateralDec: number,
44
- debtDec: number,
45
- ): number => {
46
- try {
47
- return Number(
48
- formatUnits(
49
- BigInt(price ?? '0'),
50
- // 10^(18 - decimals)
51
- 36 + collateralDec - debtDec,
52
- ),
53
- )
54
- } catch {
55
- return NaN
56
- }
57
- }
58
-
59
27
  const LENDLE_PAIR_MANTLE = '0x4c57BE599d0e0414785943569E9B6A66dA79Aa6b'
60
28
  const AU_PAIR_MANTLE = '0x709503fbb50b10f921e812c48fbd5c5522a0b20c'
61
29
  const WMNT_USDT_PAIR = '0x3e5922cd0cec71dc2d60ec8b36aa4c05b7c1672f'
@@ -63,10 +63,9 @@ export const getLendersForChain = (c: string) => {
63
63
  })
64
64
 
65
65
  // compound V3s
66
- Object.entries(compoundV3Pools() ?? {}).forEach(([l, data]) => {
67
- const chains = Object.keys(data)
68
- if (chains.includes(c)) lenders.push(l)
69
- })
66
+
67
+ if (compoundV3Pools()?.[c])
68
+ lenders = [...lenders, ...Object.keys(compoundV3Pools()?.[c])]
70
69
 
71
70
  // init
72
71
  Object.entries(initConfig() ?? {}).forEach(([l, data]) => {
@@ -80,3 +80,35 @@ export const convertRateToApr = (ratePerSecond: number | string) => {
80
80
  if (isNaN(rps)) return 0
81
81
  return rps * 3600 * 24 * 365 * 100
82
82
  }
83
+
84
+ export const formatAavePrice = (price: string, isV2 = false): number => {
85
+ try {
86
+ return Number(
87
+ formatEther(
88
+ BigInt(price ?? '0') *
89
+ // 10^(18 - decimals)
90
+ 10n ** (isV2 ? 0n : 10n),
91
+ ),
92
+ )
93
+ } catch {
94
+ return NaN
95
+ }
96
+ }
97
+
98
+ export const formatMorphoPrice = (
99
+ price: string,
100
+ collateralDec: number,
101
+ debtDec: number,
102
+ ): number => {
103
+ try {
104
+ return Number(
105
+ formatUnits(
106
+ BigInt(price ?? '0'),
107
+ // 10^(18 - decimals)
108
+ 36 + collateralDec - debtDec,
109
+ ),
110
+ )
111
+ } catch {
112
+ return NaN
113
+ }
114
+ }