@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.
- package/dist/abis/oracle/ProxyOracle.d.ts +12 -0
- package/dist/abis/oracle/ProxyOracle.d.ts.map +1 -0
- package/dist/abis/oracle/ProxyOracle.js +15 -0
- package/dist/lending/aave-v3-type/publicCallParse.d.ts +4 -4
- package/dist/lending/aave-v3-type/publicCallParse.d.ts.map +1 -1
- package/dist/lending/aave-v3-type/publicCallParse.js +68 -44
- package/dist/lending/fetchLender.d.ts.map +1 -1
- package/dist/lending/morpho/convertPublic.d.ts.map +1 -1
- package/dist/lending/morpho/convertPublic.js +8 -2
- package/dist/lending/morpho/fetchPublic.d.ts.map +1 -1
- package/dist/lending/morpho/types.d.ts +2 -0
- package/dist/lending/morpho/types.d.ts.map +1 -1
- package/dist/lending/user-data/morpho/userCallParse.d.ts.map +1 -1
- package/dist/lending/user-data/morpho/userCallParse.js +60 -0
- package/dist/prices/main-prices/addresses/morpho.d.ts +11 -0
- package/dist/prices/main-prices/addresses/morpho.d.ts.map +1 -0
- package/dist/prices/main-prices/addresses/morpho.js +903 -0
- package/dist/prices/main-prices/fetchOracleData.d.ts +1 -0
- package/dist/prices/main-prices/fetchOracleData.d.ts.map +1 -1
- package/dist/prices/main-prices/fetchOracleData.js +70 -4
- package/dist/types/providers.d.ts +1 -1
- package/dist/types/providers.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/abis/oracle/ProxyOracle.ts +15 -0
- package/src/lending/aave-v3-type/publicCallParse.ts +312 -110
- package/src/lending/fetchLender.ts +1 -0
- package/src/lending/morpho/convertPublic.ts +10 -3
- package/src/lending/morpho/fetchPublic.ts +0 -1
- package/src/lending/morpho/types.ts +5 -0
- package/src/lending/user-data/morpho/userCallParse.ts +63 -0
- package/src/prices/main-prices/addresses/morpho.ts +912 -0
- package/src/prices/main-prices/fetchOracleData.ts +120 -8
- package/src/types/providers.ts +4 -3
- package/test/mainPriceMB.test.ts +32 -0
- package/test/morpho.ts +66 -0
- package/test/morphoPrice.test.ts +31 -0
- 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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/src/types/providers.ts
CHANGED
|
@@ -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
|
+
)
|