@1delta/margin-fetcher 0.0.15 → 0.0.17

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 (37) hide show
  1. package/dist/abis/oracle/ProxyOracle.d.ts +12 -0
  2. package/dist/abis/oracle/ProxyOracle.d.ts.map +1 -0
  3. package/dist/abis/oracle/ProxyOracle.js +15 -0
  4. package/dist/lending/aave-v3-type/publicCallParse.d.ts +4 -4
  5. package/dist/lending/aave-v3-type/publicCallParse.d.ts.map +1 -1
  6. package/dist/lending/aave-v3-type/publicCallParse.js +68 -44
  7. package/dist/lending/fetchLender.d.ts.map +1 -1
  8. package/dist/lending/morpho/convertPublic.d.ts.map +1 -1
  9. package/dist/lending/morpho/convertPublic.js +8 -2
  10. package/dist/lending/morpho/fetchPublic.d.ts.map +1 -1
  11. package/dist/lending/morpho/types.d.ts +2 -0
  12. package/dist/lending/morpho/types.d.ts.map +1 -1
  13. package/dist/lending/user-data/morpho/userCallParse.d.ts.map +1 -1
  14. package/dist/lending/user-data/morpho/userCallParse.js +60 -0
  15. package/dist/prices/main-prices/addresses/morpho.d.ts +11 -0
  16. package/dist/prices/main-prices/addresses/morpho.d.ts.map +1 -0
  17. package/dist/prices/main-prices/addresses/morpho.js +903 -0
  18. package/dist/prices/main-prices/fetchOracleData.d.ts +1 -0
  19. package/dist/prices/main-prices/fetchOracleData.d.ts.map +1 -1
  20. package/dist/prices/main-prices/fetchOracleData.js +70 -4
  21. package/dist/types/providers.d.ts +1 -1
  22. package/dist/types/providers.d.ts.map +1 -1
  23. package/package.json +1 -1
  24. package/src/abis/oracle/ProxyOracle.ts +15 -0
  25. package/src/lending/aave-v3-type/publicCallParse.ts +312 -110
  26. package/src/lending/fetchLender.ts +1 -0
  27. package/src/lending/morpho/convertPublic.ts +10 -3
  28. package/src/lending/morpho/fetchPublic.ts +0 -1
  29. package/src/lending/morpho/types.ts +5 -0
  30. package/src/lending/user-data/morpho/userCallParse.ts +63 -0
  31. package/src/prices/main-prices/addresses/morpho.ts +912 -0
  32. package/src/prices/main-prices/fetchOracleData.ts +120 -8
  33. package/src/types/providers.ts +4 -3
  34. package/test/mainPriceMB.test.ts +32 -0
  35. package/test/morpho.ts +66 -0
  36. package/test/morphoPrice.test.ts +31 -0
  37. package/test/userDataAll.test.ts +82 -0
@@ -6,7 +6,7 @@ import { RWADynamicOracleAbi } from '../../abis/oracle/RWADynamicOracle'
6
6
 
7
7
  import { api3OracleAddresses } from './addresses/api3'
8
8
  import { AAVE_V2_LENDERS, ASSET_META, Chain } from '@1delta/asset-registry'
9
- import { formatEther } from 'viem'
9
+ import { formatEther, formatUnits } from 'viem'
10
10
  import { getAaveAssets } from '../../assets'
11
11
  import {
12
12
  chainlinkOracles,
@@ -19,15 +19,39 @@ import { AAVE_STYLE_ORACLES } from './addresses/aaveOracles'
19
19
  import { AAVES_PER_CHAIN } from '../../utils'
20
20
  import { GetEvmClientFunction } from '../../types'
21
21
  import { parseRawAmount } from '../../utils/parsing'
22
+ import { ProxyOracleAbi } from '../../abis/oracle/ProxyOracle'
23
+ import { MrophoOracleInfo, MrophoOracles } from './addresses/morpho'
22
24
 
23
25
  export const formatAavePrice = (price: string, isV2 = false): number => {
24
- return Number(
25
- formatEther(
26
- BigInt(price ?? '0') *
26
+ try {
27
+ return Number(
28
+ formatEther(
29
+ BigInt(price ?? '0') *
30
+ // 10^(18 - decimals)
31
+ 10n ** (isV2 ? 0n : 10n),
32
+ ),
33
+ )
34
+ } catch {
35
+ return NaN
36
+ }
37
+ }
38
+
39
+ export const formatMorphoPrice = (
40
+ price: string,
41
+ collateralDec: number,
42
+ debtDec: number,
43
+ ): number => {
44
+ try {
45
+ return Number(
46
+ formatUnits(
47
+ BigInt(price ?? '0'),
27
48
  // 10^(18 - decimals)
28
- 10n ** (isV2 ? 0n : 10n),
29
- ),
30
- )
49
+ 36 + collateralDec - debtDec,
50
+ ),
51
+ )
52
+ } catch {
53
+ return NaN
54
+ }
31
55
  }
32
56
 
33
57
  const LENDLE_PAIR_MANTLE = '0x4c57BE599d0e0414785943569E9B6A66dA79Aa6b'
@@ -40,6 +64,10 @@ interface OracleData {
40
64
  }
41
65
 
42
66
  type QueryAave = { oracle: string; assets: string[]; fork: string }
67
+ type QueryMorpho = {
68
+ oracle: string
69
+ assets: [string, string, number, number][]
70
+ }
43
71
 
44
72
  /**
45
73
  * Fetches Aave and uniswap V2 oracle data
@@ -67,6 +95,14 @@ export const fetchMainPrices = async (
67
95
  handled = [...handled, ...newOnes]
68
96
  }
69
97
  })
98
+
99
+ const morphoQueries = (MrophoOracles[chainId] ?? []).filter(
100
+ (a) =>
101
+ !handled.includes(a.collateralAsset) || !handled.includes(a.loanAsset),
102
+ )
103
+
104
+ const morphoCalls = getMorphoCalls(morphoQueries)
105
+
70
106
  const callAave = getAaveCalls(queries)
71
107
 
72
108
  const [callsChainLink, chainLinkNames] = getChainLinkCalls(chainId)
@@ -85,6 +121,7 @@ export const fetchMainPrices = async (
85
121
  ...AaveOracleAbi,
86
122
  ...Api3OracleAbi,
87
123
  ...RWADynamicOracleAbi,
124
+ ...ProxyOracleAbi,
88
125
  ],
89
126
  [
90
127
  ...callsChainLink,
@@ -92,6 +129,7 @@ export const fetchMainPrices = async (
92
129
  ...uniswapV2Calls,
93
130
  ...api3Calls,
94
131
  ...rwaCalls,
132
+ ...morphoCalls,
95
133
  ],
96
134
  getEvmClient,
97
135
  ).then((multicallResult) => {
@@ -140,13 +178,37 @@ export const fetchMainPrices = async (
140
178
  )
141
179
 
142
180
  const rwaData = parseRWADynamicOracleResults(chainId, rwaResult, rwaNames)
143
- return {
181
+
182
+ const morphoResult = multicallResult.slice(
183
+ callsChainLink.length +
184
+ callAave.length +
185
+ uniswapV2Calls.length +
186
+ api3Calls.length +
187
+ rwaCalls.length,
188
+ callsChainLink.length +
189
+ callAave.length +
190
+ uniswapV2Calls.length +
191
+ api3Calls.length +
192
+ morphoCalls.length,
193
+ )
194
+ const prices = {
144
195
  ...uniswapData,
145
196
  ...aaveData,
146
197
  ...chainLinkData,
147
198
  ...api3Data,
148
199
  ...rwaData,
149
200
  }
201
+ const morphoData = parseMorphoResults(
202
+ chainId,
203
+ morphoResult,
204
+ morphoQueries,
205
+ prices,
206
+ )
207
+
208
+ return {
209
+ ...prices,
210
+ ...morphoData,
211
+ }
150
212
  })
151
213
  })
152
214
  promises.push(fetchDefillamaData())
@@ -206,6 +268,21 @@ const getAaveCalls = (query: QueryAave[]) => {
206
268
  .flat()
207
269
  }
208
270
 
271
+ /**
272
+ * Create calldata for aave oracles
273
+ * @param chainId network
274
+ * @param addressesAaveUnderlyings address array
275
+ * @returns call data
276
+ */
277
+ const getMorphoCalls = (query: MrophoOracleInfo[] = []) => {
278
+ if (query.length === 0) return []
279
+ return query.map(({ oracle }) => ({
280
+ address: oracle,
281
+ name: 'price',
282
+ params: [],
283
+ }))
284
+ }
285
+
209
286
  /**
210
287
  * Create calldata for chainLink oracles
211
288
  * @param chainId network
@@ -328,6 +405,41 @@ const parseAaveResults = (
328
405
  return prices
329
406
  }
330
407
 
408
+ const parseMorphoResults = (
409
+ chainId: string,
410
+ data: any[],
411
+ queries: MrophoOracleInfo[],
412
+ donePrices: any = {},
413
+ ) => {
414
+ let prices: any = {}
415
+
416
+ data.forEach((d, i) => {
417
+ const details = queries[i]
418
+ const {
419
+ loanAsset,
420
+ collateralAsset,
421
+ loanAssetDecimals,
422
+ collateralAssetDecimals,
423
+ } = details
424
+ const oracleId =
425
+ ASSET_META[chainId][loanAsset]?.assetGroup ?? chainId + '-' + loanAsset
426
+ const debtPrice = donePrices[oracleId]
427
+ const oracleIdCollateral =
428
+ ASSET_META[chainId][collateralAsset]?.assetGroup ??
429
+ chainId + '-' + collateralAsset
430
+ if (debtPrice) {
431
+ const priceCollateral = formatMorphoPrice(
432
+ d.toString(),
433
+ loanAssetDecimals,
434
+ collateralAssetDecimals,
435
+ )
436
+ prices[oracleIdCollateral] = priceCollateral * debtPrice
437
+ }
438
+ })
439
+
440
+ return prices
441
+ }
442
+
331
443
  /**
332
444
  * Parser for aave results in ulticall slice
333
445
  * @param chainId network
@@ -7,12 +7,13 @@ export type MulticallRetryFunction = (
7
7
  batchSize?: number,
8
8
  maxRetries?: number,
9
9
  providerId?: number,
10
- allowFailure?: boolean
10
+ allowFailure?: boolean,
11
+ orverrides?: any,
11
12
  ) => Promise<any[]>
12
13
 
13
14
  export type GetEvmClientFunction = (
14
15
  chain: string,
15
- rpcId?: number
16
+ rpcId?: number,
16
17
  ) => PublicClient
17
18
 
18
19
  export interface ProviderDependencies {
@@ -23,4 +24,4 @@ export interface ProviderDependencies {
23
24
  export interface OptionalProviderDependencies {
24
25
  multicallRetry?: MulticallRetryFunction
25
26
  getEvmClient?: GetEvmClientFunction
26
- }
27
+ }
@@ -0,0 +1,32 @@
1
+ import { describe, it } from 'vitest'
2
+ import { Chain } from '@1delta/asset-registry'
3
+ import { fetchMainPrices } from '../src'
4
+ import { getEvmClient } from '@1delta/providers'
5
+
6
+ const chainId = Chain.POLYGON_MAINNET
7
+ describe(
8
+ 'find prices',
9
+ () => {
10
+ it('should return prices for valid tokens', async () => {
11
+ const prices = await fetchMainPrices([chainId], getEvmClient)
12
+
13
+ prettyPrint(prices)
14
+ })
15
+ },
16
+ { timeout: 10000 },
17
+ )
18
+
19
+ function prettyPrint(obj: any) {
20
+ for (const key in obj) {
21
+ const value = obj[key]
22
+ const keyStr = `\x1b[1m\x1b[36m${key}:\x1b[0m` // bold cyan
23
+ if (typeof value === 'object' && value !== null) {
24
+ if (!Number.isNaN(Number(keyStr))) console.log(`${keyStr}`)
25
+ console.dir(value, { depth: null, colors: true })
26
+ console.log(',')
27
+ } else {
28
+ console.log(`${keyStr} ${value}`)
29
+ console.log(',')
30
+ }
31
+ }
32
+ }
package/test/morpho.ts ADDED
@@ -0,0 +1,66 @@
1
+ import { zeroAddress } from "viem"
2
+
3
+ const query = (first: number, skip: number, chainId: string) => `
4
+ query GetMarkets {
5
+ markets(first: ${first}, skip: ${skip}, where: {
6
+ chainId_in: [${chainId}],
7
+ whitelisted: true
8
+ },
9
+ orderBy: SupplyAssetsUsd,
10
+ orderDirection: Desc
11
+ ) {
12
+ items {
13
+ oracleAddress
14
+ loanAsset {
15
+ address
16
+ decimals
17
+ }
18
+ collateralAsset {
19
+ address
20
+ decimals
21
+ }
22
+ }
23
+ }
24
+ }
25
+ `
26
+
27
+ const BASE_URL = 'https://blue-api.morpho.org/graphql'
28
+
29
+ export async function fetchMorphoPriceMeta(chainId: string) {
30
+ const requestBody = {
31
+ query: query(200, 0, chainId),
32
+ variables: {},
33
+ }
34
+ const response = await fetch(BASE_URL, {
35
+ method: 'POST',
36
+ headers: {
37
+ 'Content-Type': 'application/json',
38
+ },
39
+ body: JSON.stringify(requestBody),
40
+ })
41
+
42
+ if (!response.ok) {
43
+ throw new Error(
44
+ `Network error: ${response.status} - ${response.statusText}`,
45
+ )
46
+ }
47
+
48
+ const data: any = await response.json()
49
+
50
+ return getOracleMeta(data.data)
51
+ }
52
+
53
+ function getOracleMeta(response: any) {
54
+ const res: any[] = []
55
+
56
+ response.markets.items.forEach((data) => {
57
+ const oracle = data.oracleAddress
58
+ const loanAsset = data.loanAsset.address.toLowerCase()
59
+ const collateralAsset = data.collateralAsset?.address.toLowerCase()
60
+ const loanAssetDecimals = data.loanAsset.decimals
61
+ const collateralAssetDecimals = data.collateralAsset?.decimals
62
+ if (collateralAsset && loanAsset && oracle !== zeroAddress)
63
+ res.push({ oracle, loanAsset, collateralAsset, loanAssetDecimals, collateralAssetDecimals })
64
+ })
65
+ return res
66
+ }
@@ -0,0 +1,31 @@
1
+ import { describe, it } from 'vitest'
2
+ import { fetchMorphoPriceMeta } from './morpho'
3
+ import { Chain } from '@1delta/asset-registry'
4
+
5
+ const chainId = Chain.BASE
6
+ describe(
7
+ 'find prices',
8
+ () => {
9
+ it('should return prices for valid tokens', async () => {
10
+ const price = await fetchMorphoPriceMeta(chainId)
11
+
12
+ prettyPrint(price)
13
+ })
14
+ },
15
+ { timeout: 10000 },
16
+ )
17
+
18
+ function prettyPrint(obj: any) {
19
+ for (const key in obj) {
20
+ const value = obj[key]
21
+ const keyStr = `\x1b[1m\x1b[36m${key}:\x1b[0m` // bold cyan
22
+ if (typeof value === 'object' && value !== null) {
23
+ if (!Number.isNaN(Number(keyStr))) console.log(`${keyStr}`)
24
+ console.dir(value, { depth: null, colors: true })
25
+ console.log(',')
26
+ } else {
27
+ console.log(`${keyStr} ${value}`)
28
+ console.log(',')
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,82 @@
1
+ import { describe, it, expect, beforeAll } from 'vitest'
2
+ import {
3
+ getLenderUserDataResult,
4
+ convertLenderUserDataResult,
5
+ } from '../src/lending/user-data/fetchUserData'
6
+ import { fetchGeneralYields, fetchMainPrices } from '../src'
7
+ import { getEvmClient } from '@1delta/providers'
8
+ import { Chain, Lender } from '@1delta/asset-registry'
9
+ import { LenderUserQuery } from '../src/lending/user-data/types'
10
+ import { fetchMorphoPublicData } from '../src/lending/morpho/publicCallBuild'
11
+ import { prettyPrint } from './utils'
12
+
13
+ // random user with ETH
14
+ const TEST_ADDRESS = '0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5'
15
+ let prices, yields
16
+
17
+ async function getUserData(chainId: Chain, lenders: string[]) {
18
+ const publicData = {
19
+ data: await fetchMorphoPublicData(chainId),
20
+ }
21
+ // Define user queries
22
+ const queries: LenderUserQuery[] = lenders.map((lender) => ({
23
+ lender: lender,
24
+ account: TEST_ADDRESS.toLowerCase(),
25
+ // params: lenders,
26
+ }))
27
+
28
+ // Fetch raw user data
29
+ const rawUserData = await getLenderUserDataResult(
30
+ chainId,
31
+ queries,
32
+ getEvmClient,
33
+ )
34
+
35
+ // Convert raw data to structured format
36
+ const userData = convertLenderUserDataResult(
37
+ chainId,
38
+ queries,
39
+ rawUserData,
40
+ prices as any,
41
+ prices as any,
42
+ { [chainId]: publicData },
43
+ )
44
+
45
+ return { userData, rawUserData, publicData, queries }
46
+ }
47
+
48
+ describe(
49
+ 'user data fetching',
50
+ () => {
51
+ beforeAll(async () => {
52
+ ;[prices, yields] = await Promise.all([
53
+ fetchMainPrices([Chain.BASE], getEvmClient),
54
+ fetchGeneralYields(),
55
+ ])
56
+ }, 30000)
57
+
58
+ it(
59
+ 'should fetch user data for Morpho on Base',
60
+ async () => {
61
+ try {
62
+ const { userData } = await getUserData(Chain.BASE, [
63
+ 'MORPHO_BLUE_6600AAE6C56D242FA6BA68BD527AFF1A146E77813074413186828FD3F1CDCA91',
64
+ 'MORPHO_BLUE_3A4048C64BA1B375330D376B1CE40E4047D03B47AB4D48AF484EDEC9FEC801BA',
65
+ Lender.AAVE_V3,
66
+ Lender.ZEROLEND,
67
+ ])
68
+
69
+ prettyPrint(userData)
70
+
71
+ // Basic validation
72
+ expect(userData).toBeDefined()
73
+ expect(typeof userData).toBe('object')
74
+ } catch (error) {
75
+ console.log('Error fetching Morpho Base data:', error)
76
+ }
77
+ },
78
+ { timeout: 30000 },
79
+ )
80
+ },
81
+ { timeout: 90000 },
82
+ )