@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,64 @@
1
+ import { Chain } from '@1delta/chain-registry'
2
+
3
+ export const MORPHO_MARKETS: { [chain: string]: string[] } = {
4
+ [Chain.HYPEREVM]: [
5
+ '0xf9f0473b23ebeb82c83078f0f0f77f27ac534c9fb227cb4366e6057b6163ffbf',
6
+ '0xb5b215bd2771f5ed73125bf6a02e7b743fadc423dfbb095ad59df047c50d3e81',
7
+ '0x64e7db7f042812d4335947a7cdf6af1093d29478aff5f1ccd93cc67f8aadfddc',
8
+ '0xc0a3063a0a7755b7d58642e9a6d3be1c05bc974665ef7d3b158784348d4e17c5',
9
+ '0x78f6b57d825ef01a5dc496ad1f426a6375c685047d07a30cd07ac5107ffc7976',
10
+ '0xd2e8f6fd195556222d7a0314d4fb93fdf84ae920faaebba6dbcf584ac865e1f5',
11
+ '0xd5c5b5db889eb5d4f4026b9704cddffbc1356732a37c2b543330c10756ae7a18',
12
+ '0xfdece686f16877984325c7a1c192e0f18862bae3829d000a1a62b5bc2b31d4ef',
13
+ '0x076689a210adf3fdaa54e8ed452615ed641ba0d985f95e1376c3df3017d62878',
14
+ '0x0bb2900086fe38fa9633c664e1f955eb8dcf66a81174967e83dee867e083a105',
15
+ '0x0ecf5be1fadf4bec3f79ce196f02a327b507b34d230c0f033f4970b1b510119c',
16
+ '0x15f505f8dda26a523f7490ad0322f3ed4f325a54fd50832bc65e4bd75e3dca54',
17
+ '0x19bbcc95b876740c0765ed1e4bac1979c4aea1b4bfbfee0e61dc1fe76a6887dc',
18
+ '0x19e47d37453628ebf0fd18766ce6fee1b08ea46752a5da83ca0bfecb270d07e8',
19
+ '0x1c6b87ae1b97071ef444eedcba9f5a92cfe974edbbcaa1946644fc7ab0e283af',
20
+ '0x1da89208e6cb5173e97a83461853b8400de4f7c37542cf010a10579a5f7ca451',
21
+ '0x216bd19960f140177a4a3fb9cf258edcbadb1f5d54740fc944503bff4a00e65e',
22
+ '0x2acd218c67daa94dd2f92e81f477ffc9f8507319f0f2d698eae5ed631ae14039',
23
+ '0x2b62c4153d81d5b5a233d1d2b7ef899d3fca4076d458e215ff3a00176b415b0d',
24
+ '0x31aaa663d718e83ea15326ec110c4bcf5e123585d0b6c4d0ad61a50c4aa65b1e',
25
+ '0x33c935bb0699b737d9cbd4274b5936a9004eee03ccfa70e266ff7c1513fd4808',
26
+ '0x5031ac4543f8232df889e5eb24389f8cf9520366f21dc62240017cb3bc6ecc59',
27
+ '0x53bf81793c2cc384c19a3bc9b032467e179a390a9225cd9542742ac10f539cc2',
28
+ '0x5ecb7a25d51c870ec57f810c880e3e20743e56d0524575b7b8934a778aaec1af',
29
+ '0x5ef35fe4418a6bcfcc70fe32efce30074f22e9a782f81d432c1e537ddbda11e2',
30
+ '0x65f2a559764859a559d8c39604cf665942bab7d10dfaa1b82e914c9d351038d4',
31
+ '0x7268244d330f1462f77ded7a14e2f868893e86e76e8b8eaa869405d588aff6ce',
32
+ '0x83bab0d612f592d0f145b2ec82fd730144dfb3d72c8fc838b27555558e49c496',
33
+ '0x8eb8cfe3b1ac8f653608ae09fb099263fa2fe25d4a59305c309937292c2aeee9',
34
+ '0x964e7d1db11bdf32262c71274c297dcdb4710d73acb814f04fdca8b0c7cdf028',
35
+ '0x9e28003bb5c29c1df3552e99b04d656fadf1aedaf81256637dcc51d91cf6c639',
36
+ '0xa24d04c3aff60d49b3475f0084334546cbf66182e788b6bf173e6f9990b2c816',
37
+ '0xa62327642e110efd38ba2d153867a8625c8dc40832e1d211ba4f4151c3de9050',
38
+ '0xa7fe39c692f0192fb2f281a6cc16c8b2e1c8f9b9f2bc418e0c0c1e9374bf4b04',
39
+ '0xb142d65d7c624def0a9f4b49115b83f400a86bd2904d4f3339ec4441e28483ea',
40
+ '0xb5b575e402c7c19def8661069c39464c8bf3297b638e64d841b09a4eb2807de5',
41
+ '0xbc15a1782163f4be46c23ac61f5da50fed96ad40293f86a5ce0501ce4a246b32',
42
+ '0xc5526286d537c890fdd879d17d80c4a22dc7196c1e1fff0dd6c853692a759c62',
43
+ '0xc59a3f8a3918d89ebef44ee1dcda435719f543cfd3f37ead7e74852ea5931581',
44
+ '0xd173e9d80aeacac486b46a9a849ecb386cec260cc7dd5be0db3505a0f9f93fb5',
45
+ '0xdb2cf3ad3ef91c9bb673bf35744e7141bc2950b27a75c8d11b0ead9f6742d927',
46
+ '0xe0ede98b4425285a9c93d51f8ba27d9a09bc0033874e4a883d3f29d41f9f2e4a',
47
+ '0xe41ace68f2de7be8e47185b51ddc23d4a58aac4ce9f8cc5f9384fe26f2104ec8',
48
+ '0xebeabb17bd69d4b8ed6929a821d69478b564f4cc604d0995944c9da8b5cb3f04',
49
+ '0xed00791e29eb08c9bc0d8b389fe1f00084699baf2a785ba2a42e915706b17b82',
50
+ '0xf25db2433ae650155eae04ebd8b3795d19bfcb318d22926a8a5e746e8028e0a8',
51
+ ],
52
+ [Chain.OP_MAINNET]: [
53
+ '0x173b66359f0741b1c7f1963075cd271c739b6dc73b658e108a54ce6febeb279b',
54
+ '0x67840b3ace736fe47ab919ad003e0330da50536f61f9fcb96af80d0f37a57070',
55
+ '0xc7ae57c1998c67a4c21804df606db1309b68a518ba5acc8b1dc3ffcb1b26b071',
56
+ ],
57
+ [Chain.SONEIUM]: [
58
+ '0xc35eda4e57363a5679949be05c65b81c2c274bfcd21173344d99726147236614',
59
+ '0x80a26251892573c16d88f2aabd447bc46d918daa035e1bbaedc9ca315bfb3275',
60
+ '0x87f0a5e65f1cfb879d2d5e7300691332ba227f3babe8fbd4bd2cbca862d8ae5e',
61
+ '0xebaf3dc6fa2fb3f78d18c87adcc37c06fe64874c5b2d69619ef7696088780df9',
62
+ '0x5869019d7ec9f92db2e90c0156b542cda7c0a679c626eac842aa5117a0483d4a',
63
+ ],
64
+ }
@@ -1,4 +1,3 @@
1
- import { formatUnits } from 'viem'
2
1
  import {
3
2
  MorphoGeneralPublicResponse,
4
3
  RewardsMap,
@@ -7,18 +6,7 @@ import {
7
6
  import { apyToApr } from '../user-data/utils'
8
7
  import { AdditionalYields } from '../../types'
9
8
  import { GenericTokenList } from '../types'
10
-
11
- function parseLtv(ltv: number | string) {
12
- let str = 0
13
- try {
14
- str = Number(formatUnits(BigInt(ltv), 18))
15
- } catch (e) {}
16
- return str
17
- }
18
-
19
- function formatNr(n: string, d: number) {
20
- return Number(formatUnits(BigInt(n ?? 0), d))
21
- }
9
+ import { formatNr, parseLtv } from './utils/parsers'
22
10
 
23
11
  export function convertMarketsToMorphoResponse(
24
12
  response: GetMarketsResponse,
@@ -112,7 +100,7 @@ export function convertMarketsToMorphoResponse(
112
100
  ),
113
101
  totalDebtStable: 0,
114
102
  totalDebt: 0,
115
- totalLiquidity: 0,
103
+ totalLiquidity: formatNr(state.collateralAssets, collateralAsset.decimals),
116
104
  totalLiquidityUSD: Number(state.collateralAssetsUsd),
117
105
  totalDepositsUSD: Number(state.collateralAssetsUsd),
118
106
  totalDebtStableUSD: 0,
@@ -0,0 +1,402 @@
1
+ import { morphoPools } from '@1delta/data-sdk'
2
+ import { getEvmClient } from '@1delta/providers'
3
+ import { formatEther, parseAbi } from 'viem'
4
+ import { MORPHO_LENS } from '../user-data/morpho/userCallBuild'
5
+ import { decodeMarkets } from './utils/evmParser'
6
+ import { AdditionalYields } from '../../types'
7
+ import { GenericTokenList } from '../types'
8
+ import { formatNr, parseLtv } from './utils/parsers'
9
+ import { MorphoGeneralPublicResponse } from './types'
10
+ import { toGenericPriceKey, toOracleKey } from '../../assets'
11
+ import { MathLib } from './utils/mathLib'
12
+ import { apyToApr } from '../user-data/utils'
13
+ import { formatMorphoPrice } from '../../utils/parsing'
14
+ import { MORPHO_MARKETS } from './constants/markets'
15
+
16
+ export async function getMarkets(
17
+ chainId: string,
18
+ markets: string[],
19
+ additionalYields: AdditionalYields = {
20
+ intrinsicYields: {},
21
+ lenderRewards: {},
22
+ loaded: true,
23
+ },
24
+ tokens: GenericTokenList = {},
25
+ prices: any,
26
+ ) {
27
+ const abi = parseAbi([
28
+ 'function getMarketDataCompact(address morpho, bytes32[] calldata marketsIds) external view returns (bytes memory data)',
29
+ ])
30
+ const provider = getEvmClient(chainId)
31
+
32
+ const mb = morphoPools()?.MORPHO_BLUE?.[chainId]
33
+ if (!mb) return []
34
+
35
+ const returnData = await provider.simulateContract({
36
+ abi,
37
+ functionName: 'getMarketDataCompact',
38
+ address: MORPHO_LENS[chainId] as any,
39
+ args: [mb, markets] as any,
40
+ })
41
+
42
+ const decoded = decodeMarkets(returnData.result ?? '0x')
43
+
44
+ const data: { [m: string]: MorphoGeneralPublicResponse } = {}
45
+ decoded.forEach((market, i) => {
46
+ const uniqueKey = markets[i]
47
+ const { lltv, irm, oracle, loanToken, collateralToken, ...state } = market
48
+ if (collateralToken && loanToken && oracle) {
49
+ const m = 'MORPHO_BLUE_' + uniqueKey.slice(2).toUpperCase()
50
+ // @ts-ignore
51
+ if (!data[m]) data[m] = { data: {} }
52
+ // 1. LOAN asset entry
53
+ const loanRewards: any = {}
54
+
55
+ // state.rewards?.forEach((reward) => {
56
+ // loanRewards[reward.asset.address] = {
57
+ // depositRate: formatNr(reward.amountPerSuppliedToken, reward.asset.decimals),
58
+ // variableBorrowRate: formatNr(reward.amountPerBorrowedToken, reward.asset.decimals),
59
+ // stableBorrowRate: 0,
60
+ // }
61
+ // })
62
+
63
+ // get assets from list
64
+ const loanAsset = tokens[loanToken.toLowerCase()]
65
+ const collateralAsset = tokens[collateralToken.toLowerCase()]
66
+
67
+ const loanKey =
68
+ toOracleKey(loanAsset?.assetGroup!) ??
69
+ toGenericPriceKey(loanAsset.address, chainId)
70
+
71
+ let loanPrice = prices[loanKey]
72
+
73
+ // try to infer loan price from collateral price if any
74
+ if (!loanPrice) {
75
+ const collateralKey =
76
+ toOracleKey(collateralAsset?.assetGroup!) ??
77
+ toGenericPriceKey(collateralAsset.address, chainId)
78
+ const collateralPrice = prices[collateralKey]
79
+ // get debt price by collateral price
80
+ if (collateralPrice) {
81
+ const priceDebtToCollateral = formatMorphoPrice(
82
+ state.price.toString(),
83
+ loanAsset.decimals,
84
+ collateralAsset.decimals,
85
+ )
86
+ loanPrice = collateralPrice / priceDebtToCollateral
87
+ }
88
+ }
89
+
90
+ const loanTokenAddress = loanAsset.address.toLowerCase()
91
+
92
+ const meta = tokens[loanTokenAddress] ?? loanAsset
93
+ const totalDeposits = formatNr(
94
+ state.totalSupplyAssets,
95
+ loanAsset.decimals,
96
+ )
97
+ const totalDebt = formatNr(state.totalBorrowAssets, loanAsset.decimals)
98
+
99
+ const utilization = MathLib.getUtilization({
100
+ totalBorrowAssets: state.totalBorrowAssets,
101
+ totalSupplyAssets: state.totalSupplyAssets,
102
+ })
103
+
104
+ let borrowApy = 0n
105
+ let supplyApy = 0n
106
+
107
+ try {
108
+ borrowApy = MathLib.getBorrowApy(
109
+ state.rateAtTarget,
110
+ utilization,
111
+ undefined,
112
+ Number(state.lastUpdate),
113
+ )
114
+ supplyApy = MathLib.getSupplyApy(borrowApy, utilization, state.fee)
115
+ } catch {}
116
+ const borrowApr = apyToApr(Number(formatEther(borrowApy))) * 100
117
+ const depositApr = apyToApr(Number(formatEther(supplyApy))) * 100
118
+
119
+ data[m].data[loanTokenAddress] = {
120
+ poolId: loanTokenAddress,
121
+ underlying: loanTokenAddress,
122
+ asset: meta,
123
+ totalDeposits,
124
+ totalDebtStable: 0,
125
+ totalDebt,
126
+ totalDepositsUSD: totalDeposits * loanPrice,
127
+ totalDebtStableUSD: 0,
128
+ totalLiquidity: totalDeposits - totalDebt,
129
+ totalLiquidityUSD: (totalDeposits - totalDebt) * loanPrice,
130
+ totalDebtUSD: totalDebt * loanPrice,
131
+ depositRate: depositApr,
132
+ variableBorrowRate: borrowApr,
133
+ stableBorrowRate: 0,
134
+ stakingYield: additionalYields.intrinsicYields[meta?.assetGroup] ?? 0,
135
+ rewards: Object.keys(loanRewards).length > 0 ? loanRewards : undefined,
136
+ decimals: loanAsset.decimals,
137
+ config: {
138
+ 0: {
139
+ category: 0,
140
+ borrowCollateralFactor: 0,
141
+ collateralFactor: 0,
142
+ borrowFactor: 1,
143
+ },
144
+ },
145
+ collateralActive: false,
146
+ borrowingEnabled: true,
147
+ hasStable: false,
148
+ isActive: true,
149
+ isFrozen: false,
150
+ }
151
+
152
+ const ltv = parseLtv(lltv)
153
+
154
+ const collateralAssetAddress = collateralAsset.address.toLowerCase()
155
+ const metaCollateral = tokens[collateralAssetAddress] ?? collateralAsset
156
+ // 2. COLLATERAL asset entry
157
+ data[m].data[collateralAssetAddress] = {
158
+ poolId: collateralAssetAddress,
159
+ underlying: collateralAssetAddress,
160
+ asset: metaCollateral,
161
+ totalDeposits: 0, // we do not have these metrics when querying on-chain
162
+ totalDebtStable: 0,
163
+ totalDebt: 0,
164
+ totalLiquidity: 0,
165
+ totalLiquidityUSD: 0,
166
+ totalDepositsUSD: 0,
167
+ totalDebtStableUSD: 0,
168
+ totalDebtUSD: 0,
169
+ depositRate: 0,
170
+ variableBorrowRate: 0,
171
+ stableBorrowRate: 0,
172
+ stakingYield:
173
+ additionalYields.intrinsicYields[metaCollateral?.assetGroup] ?? 0,
174
+ rewards: undefined,
175
+ decimals: collateralAsset.decimals,
176
+ config: {
177
+ 0: {
178
+ category: 0,
179
+ borrowCollateralFactor: ltv,
180
+ collateralFactor: ltv,
181
+ borrowFactor: 1,
182
+ },
183
+ },
184
+ collateralActive: true,
185
+ borrowingEnabled: false,
186
+ hasStable: false,
187
+ isActive: true,
188
+ isFrozen: false,
189
+ }
190
+
191
+ data[m].params = {
192
+ market: {
193
+ lender: m,
194
+ collateralDecimals: collateralAsset.decimals,
195
+ loanDecimals: loanAsset.decimals,
196
+ id: uniqueKey,
197
+ lltv: lltv.toString(),
198
+ oracle: oracle,
199
+ irm: irm,
200
+ collateralAddress: collateralAssetAddress,
201
+ loanAddress: loanTokenAddress,
202
+ },
203
+ }
204
+ data[m].chainId = chainId
205
+ }
206
+ })
207
+
208
+ return data
209
+ }
210
+
211
+ export function getMorphoMarketDataConverter(
212
+ lender: string,
213
+ chainId: string,
214
+ prices: any,
215
+ additionalYields: AdditionalYields = {
216
+ intrinsicYields: {},
217
+ lenderRewards: {},
218
+ loaded: true,
219
+ },
220
+ tokens: GenericTokenList = {},
221
+ ): [(data: any[]) => any | undefined, number] {
222
+ const markets = MORPHO_MARKETS[chainId] ?? []
223
+ return [
224
+ (rData: any[]) => {
225
+ const decoded = decodeMarkets(rData[0] ?? '0x')
226
+
227
+ const data: { [m: string]: MorphoGeneralPublicResponse } = {}
228
+ decoded.forEach((market, i) => {
229
+ const uniqueKey = markets[i]
230
+ const { lltv, irm, oracle, loanToken, collateralToken, ...state } =
231
+ market
232
+ if (collateralToken && loanToken && oracle) {
233
+ const m = 'MORPHO_BLUE_' + uniqueKey.slice(2).toUpperCase()
234
+ // @ts-ignore
235
+ if (!data[m]) data[m] = { data: {} }
236
+ // 1. LOAN asset entry
237
+ const loanRewards: any = {}
238
+
239
+ // state.rewards?.forEach((reward) => {
240
+ // loanRewards[reward.asset.address] = {
241
+ // depositRate: formatNr(reward.amountPerSuppliedToken, reward.asset.decimals),
242
+ // variableBorrowRate: formatNr(reward.amountPerBorrowedToken, reward.asset.decimals),
243
+ // stableBorrowRate: 0,
244
+ // }
245
+ // })
246
+
247
+ // get assets from list
248
+ const loanAsset = tokens[loanToken.toLowerCase()]
249
+ const collateralAsset = tokens[collateralToken.toLowerCase()]
250
+
251
+ const loanKey =
252
+ toOracleKey(loanAsset?.assetGroup!) ??
253
+ toGenericPriceKey(loanAsset.address, chainId)
254
+
255
+ let loanPrice = prices[loanKey]
256
+
257
+ // try to infer loan price from collateral price if any
258
+ if (!loanPrice) {
259
+ const collateralKey =
260
+ toOracleKey(collateralAsset?.assetGroup!) ??
261
+ toGenericPriceKey(collateralAsset.address, chainId)
262
+ const collateralPrice = prices[collateralKey]
263
+ // get debt price by collateral price
264
+ if (collateralPrice) {
265
+ const priceDebtToCollateral = formatMorphoPrice(
266
+ state.price.toString(),
267
+ loanAsset.decimals,
268
+ collateralAsset.decimals,
269
+ )
270
+ loanPrice = collateralPrice / priceDebtToCollateral
271
+ }
272
+ }
273
+
274
+ const loanTokenAddress = loanAsset.address.toLowerCase()
275
+
276
+ const meta = tokens[loanTokenAddress] ?? loanAsset
277
+ const totalDeposits = formatNr(
278
+ state.totalSupplyAssets,
279
+ loanAsset.decimals,
280
+ )
281
+ const totalDebt = formatNr(
282
+ state.totalBorrowAssets,
283
+ loanAsset.decimals,
284
+ )
285
+
286
+ const utilization = MathLib.getUtilization({
287
+ totalBorrowAssets: state.totalBorrowAssets,
288
+ totalSupplyAssets: state.totalSupplyAssets,
289
+ })
290
+
291
+ let borrowApy = 0n
292
+ let supplyApy = 0n
293
+
294
+ try {
295
+ borrowApy = MathLib.getBorrowApy(
296
+ state.rateAtTarget,
297
+ utilization,
298
+ undefined,
299
+ Number(state.lastUpdate),
300
+ )
301
+ supplyApy = MathLib.getSupplyApy(borrowApy, utilization, state.fee)
302
+ } catch {}
303
+ const borrowApr = apyToApr(Number(formatEther(borrowApy))) * 100
304
+ const depositApr = apyToApr(Number(formatEther(supplyApy))) * 100
305
+
306
+ data[m].data[loanTokenAddress] = {
307
+ poolId: loanTokenAddress,
308
+ underlying: loanTokenAddress,
309
+ asset: meta,
310
+ totalDeposits,
311
+ totalDebtStable: 0,
312
+ totalDebt,
313
+ totalDepositsUSD: totalDeposits * loanPrice,
314
+ totalDebtStableUSD: 0,
315
+ totalLiquidity: totalDeposits - totalDebt,
316
+ totalLiquidityUSD: (totalDeposits - totalDebt) * loanPrice,
317
+ totalDebtUSD: totalDebt * loanPrice,
318
+ depositRate: depositApr,
319
+ variableBorrowRate: borrowApr,
320
+ stableBorrowRate: 0,
321
+ stakingYield:
322
+ additionalYields.intrinsicYields[meta?.assetGroup] ?? 0,
323
+ rewards:
324
+ Object.keys(loanRewards).length > 0 ? loanRewards : undefined,
325
+ decimals: loanAsset.decimals,
326
+ config: {
327
+ 0: {
328
+ category: 0,
329
+ borrowCollateralFactor: 0,
330
+ collateralFactor: 0,
331
+ borrowFactor: 1,
332
+ },
333
+ },
334
+ collateralActive: false,
335
+ borrowingEnabled: true,
336
+ hasStable: false,
337
+ isActive: true,
338
+ isFrozen: false,
339
+ }
340
+
341
+ const ltv = parseLtv(lltv)
342
+
343
+ const collateralAssetAddress = collateralAsset.address.toLowerCase()
344
+ const metaCollateral =
345
+ tokens[collateralAssetAddress] ?? collateralAsset
346
+ // 2. COLLATERAL asset entry
347
+ data[m].data[collateralAssetAddress] = {
348
+ poolId: collateralAssetAddress,
349
+ underlying: collateralAssetAddress,
350
+ asset: metaCollateral,
351
+ totalDeposits: 0, // we do not have these metrics when querying on-chain
352
+ totalDebtStable: 0,
353
+ totalDebt: 0,
354
+ totalLiquidity: 0,
355
+ totalLiquidityUSD: 0,
356
+ totalDepositsUSD: 0,
357
+ totalDebtStableUSD: 0,
358
+ totalDebtUSD: 0,
359
+ depositRate: 0,
360
+ variableBorrowRate: 0,
361
+ stableBorrowRate: 0,
362
+ stakingYield:
363
+ additionalYields.intrinsicYields[metaCollateral?.assetGroup] ?? 0,
364
+ rewards: undefined,
365
+ decimals: collateralAsset.decimals,
366
+ config: {
367
+ 0: {
368
+ category: 0,
369
+ borrowCollateralFactor: ltv,
370
+ collateralFactor: ltv,
371
+ borrowFactor: 1,
372
+ },
373
+ },
374
+ collateralActive: true,
375
+ borrowingEnabled: false,
376
+ hasStable: false,
377
+ isActive: true,
378
+ isFrozen: false,
379
+ }
380
+
381
+ data[m].params = {
382
+ market: {
383
+ lender: m,
384
+ collateralDecimals: collateralAsset.decimals,
385
+ loanDecimals: loanAsset.decimals,
386
+ id: uniqueKey,
387
+ lltv: lltv.toString(),
388
+ oracle: oracle,
389
+ irm: irm,
390
+ collateralAddress: collateralAssetAddress,
391
+ loanAddress: loanTokenAddress,
392
+ },
393
+ }
394
+ data[m].chainId = chainId
395
+ }
396
+ })
397
+
398
+ return data
399
+ },
400
+ markets.length > 0 ? 1 : 0,
401
+ ]
402
+ }
@@ -1,4 +1,7 @@
1
+ import { morphoPools } from '@1delta/data-sdk'
1
2
  import { AdditionalYields } from '../../types'
3
+ import { MORPHO_LENS } from '../user-data/morpho/userCallBuild'
4
+ import { MORPHO_MARKETS } from './constants/markets'
2
5
  import { convertMarketsToMorphoResponse } from './convertPublic'
3
6
  import { fetchMorphoMarkets } from './fetchPublic'
4
7
 
@@ -13,3 +16,17 @@ export async function fetchMorphoPublicData(
13
16
  const mbData = await fetchMorphoMarkets(chainId)
14
17
  return convertMarketsToMorphoResponse(mbData, chainId, yields)
15
18
  }
19
+
20
+ export function buildMorphoCall(chainId: string) {
21
+ const markets = MORPHO_MARKETS[chainId] ?? []
22
+ const mb = morphoPools()?.MORPHO_BLUE?.[chainId]
23
+ if (!mb || markets.length === 0) return []
24
+
25
+ return [
26
+ {
27
+ address: MORPHO_LENS[chainId],
28
+ name: 'getMarketDataCompact',
29
+ params: [mb, markets],
30
+ },
31
+ ]
32
+ }
@@ -0,0 +1,122 @@
1
+ type Market = {
2
+ loanToken: string; // 20 bytes (EVM address, hex)
3
+ collateralToken: string; // 20 bytes (EVM address, hex)
4
+ oracle: string; // 20 bytes (EVM address, hex)
5
+ irm: string; // 20 bytes (EVM address, hex)
6
+ lltv: bigint; // 16 bytes
7
+ price: bigint; // 32 bytes
8
+ rateAtTarget: bigint; // 32 bytes
9
+ totalSupplyAssets: bigint; // 16 bytes
10
+ totalSupplyShares: bigint; // 16 bytes
11
+ totalBorrowAssets: bigint; // 16 bytes
12
+ totalBorrowShares: bigint; // 16 bytes
13
+ lastUpdate: bigint; // 16 bytes
14
+ fee: bigint; // 16 bytes
15
+ };
16
+
17
+ const FIELD_SIZES = {
18
+ addr: 20,
19
+ u128: 16,
20
+ u256: 32,
21
+ };
22
+
23
+ const RECORD_SIZE =
24
+ 4 * FIELD_SIZES.addr + // loanToken, collateralToken, oracle, irm
25
+ 1 * FIELD_SIZES.u128 + // lltv
26
+ 2 * FIELD_SIZES.u256 + // price, rateAtTarget
27
+ 5 * FIELD_SIZES.u128 + // totals (4) + lastUpdate
28
+ 1 * FIELD_SIZES.u128; // fee
29
+ // = 256 bytes
30
+
31
+ /**
32
+ * Decode packed markets bytes into typed objects.
33
+ * Integers are parsed as big-endian BigInt. Addresses are 0x-prefixed lowercase hex.
34
+ */
35
+ export function decodeMarkets(input: string | Uint8Array): Market[] {
36
+ const bytes = normalizeToBytes(input);
37
+
38
+ if (bytes.length % RECORD_SIZE !== 0) {
39
+ throw new Error(
40
+ `Invalid data length ${bytes.length}; not a multiple of ${RECORD_SIZE} bytes per record`
41
+ );
42
+ }
43
+
44
+ const markets: Market[] = [];
45
+ for (let i = 0; i < bytes.length; i += RECORD_SIZE) {
46
+ let o = i;
47
+
48
+ const loanToken = readAddress(bytes, o, FIELD_SIZES.addr); o += FIELD_SIZES.addr;
49
+ const collateralToken = readAddress(bytes, o, FIELD_SIZES.addr); o += FIELD_SIZES.addr;
50
+ const oracle = readAddress(bytes, o, FIELD_SIZES.addr); o += FIELD_SIZES.addr;
51
+ const irm = readAddress(bytes, o, FIELD_SIZES.addr); o += FIELD_SIZES.addr;
52
+
53
+ const lltv = readUintBE(bytes, o, FIELD_SIZES.u128); o += FIELD_SIZES.u128;
54
+ const price = readUintBE(bytes, o, FIELD_SIZES.u256); o += FIELD_SIZES.u256;
55
+ const rateAtTarget = readUintBE(bytes, o, FIELD_SIZES.u256); o += FIELD_SIZES.u256;
56
+
57
+ const totalSupplyAssets= readUintBE(bytes, o, FIELD_SIZES.u128); o += FIELD_SIZES.u128;
58
+ const totalSupplyShares= readUintBE(bytes, o, FIELD_SIZES.u128); o += FIELD_SIZES.u128;
59
+ const totalBorrowAssets= readUintBE(bytes, o, FIELD_SIZES.u128); o += FIELD_SIZES.u128;
60
+ const totalBorrowShares= readUintBE(bytes, o, FIELD_SIZES.u128); o += FIELD_SIZES.u128;
61
+ const lastUpdate = readUintBE(bytes, o, FIELD_SIZES.u128); o += FIELD_SIZES.u128;
62
+ const fee = readUintBE(bytes, o, FIELD_SIZES.u128); o += FIELD_SIZES.u128;
63
+
64
+ markets.push({
65
+ loanToken,
66
+ collateralToken,
67
+ oracle,
68
+ irm,
69
+ lltv,
70
+ price,
71
+ rateAtTarget,
72
+ totalSupplyAssets,
73
+ totalSupplyShares,
74
+ totalBorrowAssets,
75
+ totalBorrowShares,
76
+ lastUpdate,
77
+ fee,
78
+ });
79
+ }
80
+
81
+ return markets;
82
+ }
83
+
84
+ // ---------- helpers ----------
85
+
86
+ function normalizeToBytes(input: string | Uint8Array): Uint8Array {
87
+ if (typeof input !== "string") {
88
+ return input;
89
+ }
90
+ let hex = input.startsWith("0x") ? input.slice(2) : input;
91
+ if (hex.length % 2 !== 0) throw new Error("Hex string must have even length");
92
+ const out = new Uint8Array(hex.length / 2);
93
+ for (let i = 0; i < out.length; i++) {
94
+ out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
95
+ }
96
+ return out;
97
+ }
98
+
99
+ function readAddress(bytes: Uint8Array, offset: number, len: number): string {
100
+ // Addresses are the raw 20 bytes, render as 0x + 40 hex chars (lowercase).
101
+ const hex = toHex(bytes.subarray(offset, offset + len));
102
+ return "0x" + hex;
103
+ }
104
+
105
+ function readUintBE(bytes: Uint8Array, offset: number, len: number): bigint {
106
+ // Big-endian: (((b0 * 256) + b1) * 256 + ...) pattern.
107
+ let v = 0n;
108
+ const end = offset + len;
109
+ for (let i = offset; i < end; i++) {
110
+ v = (v << 8n) | BigInt(bytes[i]);
111
+ }
112
+ return v;
113
+ }
114
+
115
+ function toHex(arr: Uint8Array): string {
116
+ let s = "";
117
+ for (let i = 0; i < arr.length; i++) {
118
+ const h = arr[i].toString(16).padStart(2, "0");
119
+ s += h;
120
+ }
121
+ return s;
122
+ }