@@ -2,95 +2,216 @@ import { Write } from "../utils/dbInterfaces";
2
2
import { getApi } from "../utils/sdk" ;
3
3
import getWrites from "../utils/getWrites" ;
4
4
5
- const DATA_FEED_ABI = "function getDataInBase18() external view returns (int256 answer)" ;
6
- const AGGREGATOR_ABI = "function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)" ;
5
+ const DATA_FEED_ABI =
6
+ "function getDataInBase18() external view returns (int256 answer)" ;
7
+ const AGGREGATOR_ABI =
8
+ "function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)" ;
9
+
10
+ type Denomination = "USD" | "BTC" | "SOL" ;
11
+
12
+ interface TokenConfig {
13
+ name : string ;
14
+ token : string ;
15
+ oracle ?: string ;
16
+ denomination ?: Denomination ;
17
+ }
18
+
19
+ // Base asset price oracles on Ethereum
20
+ const BASE_ASSET_ORACLES = {
21
+ BTC : "0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c" , // BTC/USD on Ethereum
22
+ SOL : "0x4ffC43a60e009B551865A93d232E33Fce9f01507" , // SOL/USD on Ethereum
23
+ } as const ;
7
24
8
- const contracts : {
9
- [ chain : string ] : { name : string ; token : string ; oracle ?: string ; requiresConversion ?: boolean } [ ] ;
10
- } = {
25
+ const contracts : Record < string , TokenConfig [ ] > = {
11
26
ethereum : [
12
- { name : "mTBILL" , token : "0xDD629E5241CbC5919847783e6C96B2De4754e438" , oracle : "0xfCEE9754E8C375e145303b7cE7BEca3201734A2B" } ,
13
- { name : "mBASIS" , token : "0x2a8c22E3b10036f3AEF5875d04f8441d4188b656" , oracle : "0x1615cBC603192ae8A9FF20E98dd0e40a405d76e4" } ,
14
- { name : "mBTC" , token : "0x007115416AB6c266329a03B09a8aa39aC2eF7d9d" , oracle : "0x9987BE0c1dc5Cd284a4D766f4B5feB4F3cb3E28e" , requiresConversion : true } ,
15
- { name : "mEDGE" , token : "0xbB51E2a15A9158EBE2b0Ceb8678511e063AB7a55" , oracle : "0x20cd58F72cF1727a2937eB1816593390cf8d91cB" } ,
16
- { name : "mMEV" , token : "0x030b69280892c888670EDCDCD8B69Fd8026A0BF3" , oracle : "0x9BF00b7CFC00D6A7a2e2C994DB8c8dCa467ee359" } ,
17
- { name : "mRe7YIELD" , token : "0x87C9053C819bB28e0D73d33059E1b3DA80AFb0cf" , oracle : "0x7E8C632ab231479886AF1Bc02B9D646e4634Da93" } ,
18
- { name : "mF-ONE" , token : "0x238a700eD6165261Cf8b2e544ba797BC11e466Ba" , oracle : "0xCF4e49f5e750Af8F2f9Aa1642B68E5839D9c1C00" } ,
19
- { name : "mHYPER" , token : "0x9b5528528656DBC094765E2abB79F293c21191B9" , oracle : "0x92004DCC5359eD67f287F32d12715A37916deCdE" } ,
20
- { name : "mAPOLLO" , token : "0x7CF9DEC92ca9FD46f8d86e7798B72624Bc116C05" , oracle : "0x9aEBf5d6F9411BAc355021ddFbe9B2c756BDD358" } ,
21
- { name : "mevBTC" , token : "0xb64C014307622eB15046C66fF71D04258F5963DC" , oracle : "0x56814399caaEDCEE4F58D2e55DA058A81DDE744f" } ,
22
- { name : "mFARM" , token : "0xA19f6e0dF08a7917F2F8A33Db66D0AF31fF5ECA6" , oracle : "0x9f49B0980B141b539e2A94Ec0864Faf699fF9524" } ,
27
+ {
28
+ name : "mTBILL" ,
29
+ token : "0xDD629E5241CbC5919847783e6C96B2De4754e438" ,
30
+ oracle : "0xfCEE9754E8C375e145303b7cE7BEca3201734A2B" ,
31
+ } ,
32
+ {
33
+ name : "mBASIS" ,
34
+ token : "0x2a8c22E3b10036f3AEF5875d04f8441d4188b656" ,
35
+ oracle : "0x1615cBC603192ae8A9FF20E98dd0e40a405d76e4" ,
36
+ } ,
37
+ {
38
+ name : "mBTC" ,
39
+ token : "0x007115416AB6c266329a03B09a8aa39aC2eF7d9d" ,
40
+ oracle : "0x9987BE0c1dc5Cd284a4D766f4B5feB4F3cb3E28e" ,
41
+ denomination : "BTC" ,
42
+ } ,
43
+ {
44
+ name : "mEDGE" ,
45
+ token : "0xbB51E2a15A9158EBE2b0Ceb8678511e063AB7a55" ,
46
+ oracle : "0x20cd58F72cF1727a2937eB1816593390cf8d91cB" ,
47
+ } ,
48
+ {
49
+ name : "mMEV" ,
50
+ token : "0x030b69280892c888670EDCDCD8B69Fd8026A0BF3" ,
51
+ oracle : "0x9BF00b7CFC00D6A7a2e2C994DB8c8dCa467ee359" ,
52
+ } ,
53
+ {
54
+ name : "mRe7YIELD" ,
55
+ token : "0x87C9053C819bB28e0D73d33059E1b3DA80AFb0cf" ,
56
+ oracle : "0x7E8C632ab231479886AF1Bc02B9D646e4634Da93" ,
57
+ } ,
58
+ {
59
+ name : "mF-ONE" ,
60
+ token : "0x238a700eD6165261Cf8b2e544ba797BC11e466Ba" ,
61
+ oracle : "0xCF4e49f5e750Af8F2f9Aa1642B68E5839D9c1C00" ,
62
+ } ,
63
+ {
64
+ name : "mHYPER" ,
65
+ token : "0x9b5528528656DBC094765E2abB79F293c21191B9" ,
66
+ oracle : "0x92004DCC5359eD67f287F32d12715A37916deCdE" ,
67
+ } ,
68
+ {
69
+ name : "mAPOLLO" ,
70
+ token : "0x7CF9DEC92ca9FD46f8d86e7798B72624Bc116C05" ,
71
+ oracle : "0x9aEBf5d6F9411BAc355021ddFbe9B2c756BDD358" ,
72
+ } ,
73
+ {
74
+ name : "mevBTC" ,
75
+ token : "0xb64C014307622eB15046C66fF71D04258F5963DC" ,
76
+ oracle : "0x56814399caaEDCEE4F58D2e55DA058A81DDE744f" ,
77
+ denomination : "BTC" ,
78
+ } ,
79
+ {
80
+ name : "mFARM" ,
81
+ token : "0xA19f6e0dF08a7917F2F8A33Db66D0AF31fF5ECA6" ,
82
+ oracle : "0x9f49B0980B141b539e2A94Ec0864Faf699fF9524" ,
83
+ } ,
23
84
] ,
24
85
base : [
25
- { name : "mTBILL" , token : "0xDD629E5241CbC5919847783e6C96B2De4754e438" , oracle : "0xcbCf1e67F1988e2572a2A620321Aef2ff73369f0" } ,
26
- { name : "mBASIS" , token : "0x1C2757c1FeF1038428b5bEF062495ce94BBe92b2" , oracle : "0xD48D38Ec56CDB44c4281068129038A37F5Df04e5" } ,
86
+ {
87
+ name : "mTBILL" ,
88
+ token : "0xDD629E5241CbC5919847783e6C96B2De4754e438" ,
89
+ oracle : "0xcbCf1e67F1988e2572a2A620321Aef2ff73369f0" ,
90
+ } ,
91
+ {
92
+ name : "mBASIS" ,
93
+ token : "0x1C2757c1FeF1038428b5bEF062495ce94BBe92b2" ,
94
+ oracle : "0xD48D38Ec56CDB44c4281068129038A37F5Df04e5" ,
95
+ } ,
27
96
] ,
28
97
sapphire : [
29
98
{ name : "mTBILL" , token : "0xDD629E5241CbC5919847783e6C96B2De4754e438" } ,
30
99
] ,
31
100
etlk : [
32
101
{ name : "mTBILL" , token : "0xDD629E5241CbC5919847783e6C96B2De4754e438" } ,
33
102
{ name : "mBASIS" , token : "0x2247B5A46BB79421a314aB0f0b67fFd11dd37Ee4" } ,
103
+ { name : "mMEV" , token : "0x5542F82389b76C23f5848268893234d8A63fd5c8" } ,
104
+ { name : "mRe7YIELD" , token : "0x733d504435a49FC8C4e9759e756C2846c92f0160" } ,
34
105
] ,
35
106
rsk : [
36
107
{ name : "mTBILL" , token : "0xDD629E5241CbC5919847783e6C96B2De4754e438" } ,
37
- { name : "mBTC" , token : "0xEF85254Aa4a8490bcC9C02Ae38513Cae8303FB53" } ,
108
+ {
109
+ name : "mBTC" ,
110
+ token : "0xEF85254Aa4a8490bcC9C02Ae38513Cae8303FB53" ,
111
+ denomination : "BTC" ,
112
+ } ,
38
113
] ,
39
114
plume_mainnet : [
40
- { name : "mTBILL" , token : "0xE85f2B707Ec5Ae8e07238F99562264f304E30109" , oracle : "0x73a64469E0974371005ca0f60Dfc10405613b411" } ,
41
- { name : "mBASIS" , token : "0x0c78Ca789e826fE339dE61934896F5D170b66d78" , oracle : "0x7588139737f32A6da49b9BB03A0a91a45603b45F" } ,
42
- { name : "mEDGE" , token : "0x69020311836D29BA7d38C1D3578736fD3dED03ED" , oracle : "0xa30e78AF094EFC51434693803fEE1D77f568321E" } ,
43
- { name : "mMEV" , token : "0x7d611dC23267F508DE90724731Dc88CA28Ef7473" , oracle : "0x06fa9188680D8487e2b743b182CCc39654211C84" } ,
115
+ {
116
+ name : "mTBILL" ,
117
+ token : "0xE85f2B707Ec5Ae8e07238F99562264f304E30109" ,
118
+ oracle : "0x73a64469E0974371005ca0f60Dfc10405613b411" ,
119
+ } ,
120
+ {
121
+ name : "mBASIS" ,
122
+ token : "0x0c78Ca789e826fE339dE61934896F5D170b66d78" ,
123
+ oracle : "0x7588139737f32A6da49b9BB03A0a91a45603b45F" ,
124
+ } ,
125
+ {
126
+ name : "mEDGE" ,
127
+ token : "0x69020311836D29BA7d38C1D3578736fD3dED03ED" ,
128
+ oracle : "0xa30e78AF094EFC51434693803fEE1D77f568321E" ,
129
+ } ,
130
+ {
131
+ name : "mMEV" ,
132
+ token : "0x7d611dC23267F508DE90724731Dc88CA28Ef7473" ,
133
+ oracle : "0x06fa9188680D8487e2b743b182CCc39654211C84" ,
134
+ } ,
44
135
] ,
45
136
katana : [
46
- { name : "mRE7SOL" , token : "0xC6135d59F8D10c9C035963ce9037B3635170D716" , oracle : "0x001b3731c706fEd93BDA240A5BF848C28ae1cC12" } ,
47
- ]
137
+ {
138
+ name : "mRE7SOL" ,
139
+ token : "0xC6135d59F8D10c9C035963ce9037B3635170D716" ,
140
+ oracle : "0x001b3731c706fEd93BDA240A5BF848C28ae1cC12" ,
141
+ denomination : "SOL" ,
142
+ } ,
143
+ ] ,
48
144
} ;
49
145
50
- const btcToUsdOracleEth = "0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c" ;
51
-
52
- async function getBtcToUsdPrice ( timestamp : number ) : Promise < number > {
146
+ async function getBaseAssetPrices (
147
+ timestamp : number
148
+ ) : Promise < Record < string , number > > {
53
149
const api = await getApi ( "ethereum" , timestamp ) ;
54
- const response = await api . call ( { abi : AGGREGATOR_ABI , target : btcToUsdOracleEth } ) ;
55
- return response . answer / 1e8 ;
150
+ const prices : Record < string , number > = { } ;
151
+
152
+ const calls = await api . multiCall ( {
153
+ abi : AGGREGATOR_ABI ,
154
+ calls : Object . values ( BASE_ASSET_ORACLES ) ,
155
+ } ) ;
156
+
157
+ Object . keys ( BASE_ASSET_ORACLES ) . forEach ( ( asset , i ) => {
158
+ if ( calls [ i ] ?. answer ) {
159
+ prices [ asset ] = Number ( calls [ i ] . answer ) / 1e8 ;
160
+ }
161
+ } ) ;
162
+
163
+ return prices ;
56
164
}
57
165
58
- async function getTokenPrices ( chain : string , timestamp : number , ethereumPrices : Record < string , number > ) : Promise < Write [ ] > {
166
+ async function getTokenPrices (
167
+ chain : string ,
168
+ timestamp : number ,
169
+ baseAssetPrices : Record < string , number > ,
170
+ ethereumPrices : Record < string , number >
171
+ ) : Promise < Write [ ] > {
59
172
const api = await getApi ( chain , timestamp ) ;
60
173
const tokens = contracts [ chain ] || [ ] ;
61
- const btcToUsdPrice = await getBtcToUsdPrice ( timestamp ) ;
62
174
63
- const tokensWithOracles = tokens . filter ( t => t . oracle ) ;
64
- const tokensWithoutOracles = tokens . filter ( t => ! t . oracle ) ;
175
+ const tokensWithOracles = tokens . filter ( ( t ) => t . oracle ) ;
176
+ const tokensWithoutOracles = tokens . filter ( ( t ) => ! t . oracle ) ;
177
+
178
+ const prices : Record < string , { price : number } > = { } ;
65
179
66
- let prices : Record < string , { price : number } > = { } ;
67
180
if ( tokensWithOracles . length > 0 ) {
68
- const dataFeedResponses = await api . multiCall ( {
181
+ const oracleResponses = await api . multiCall ( {
69
182
abi : DATA_FEED_ABI ,
70
- calls : tokensWithOracles . map ( ( { oracle } ) => oracle as string ) ,
183
+ calls : tokensWithOracles . map ( ( t ) => t . oracle as string ) ,
71
184
} ) ;
72
185
73
- prices = tokensWithOracles . reduce ( ( acc , { token, requiresConversion, name } , i ) => {
74
- const rawVal = dataFeedResponses [ i ] ;
75
- if ( rawVal !== null && rawVal !== undefined ) {
76
- const price = ( rawVal / 1e18 ) * ( requiresConversion ? btcToUsdPrice : 1 ) ;
77
- acc [ token ] = { price } ;
186
+ tokensWithOracles . forEach ( ( token , i ) => {
187
+ const rawPrice = oracleResponses [ i ] ;
188
+ if ( rawPrice !== null && rawPrice !== undefined ) {
189
+ let usdPrice = Number ( rawPrice ) / 1e18 ;
190
+
191
+ // Convert to USD if denominated in another asset
192
+ if ( token . denomination && token . denomination !== "USD" ) {
193
+ const basePrice = baseAssetPrices [ token . denomination ] ;
194
+ if ( basePrice ) {
195
+ usdPrice = usdPrice * basePrice ;
196
+ }
197
+ }
198
+
199
+ prices [ token . token ] = { price : usdPrice } ;
78
200
79
- if ( chain === 'ethereum' ) {
80
- ethereumPrices [ name ] = price ;
201
+ // Store Ethereum prices for other chains to use as fallback
202
+ if ( chain === "ethereum" ) {
203
+ ethereumPrices [ token . name ] = usdPrice ;
81
204
}
82
205
}
83
- return acc ;
84
- } , { } as Record < string , { price : number } > ) ;
206
+ } ) ;
85
207
}
86
208
87
- for ( const t of tokensWithoutOracles ) {
88
- const { name, token } = t ;
89
- const fallbackPrice = ethereumPrices [ name ] ;
209
+ tokensWithoutOracles . forEach ( ( token ) => {
210
+ const fallbackPrice = ethereumPrices [ token . name ] ;
90
211
if ( fallbackPrice !== undefined ) {
91
- prices [ token ] = { price : fallbackPrice } ;
212
+ prices [ token . token ] = { price : fallbackPrice } ;
92
213
}
93
- }
214
+ } ) ;
94
215
95
216
return getWrites ( {
96
217
chain,
@@ -101,21 +222,32 @@ async function getTokenPrices(chain: string, timestamp: number, ethereumPrices:
101
222
}
102
223
103
224
export async function midas ( timestamp : number = 0 ) : Promise < Write [ ] > {
225
+ const baseAssetPrices = await getBaseAssetPrices ( timestamp ) ;
226
+
104
227
const ethereumPrices : Record < string , number > = { } ;
105
228
106
229
const chains = Object . keys ( contracts ) ;
107
- const ethereumIndex = chains . indexOf ( ' ethereum' ) ;
230
+ const ethereumIndex = chains . indexOf ( " ethereum" ) ;
108
231
109
232
let ethereumWrites : Write [ ] = [ ] ;
110
233
let otherChainWrites : Write [ ] = [ ] ;
111
234
112
235
if ( ethereumIndex !== - 1 ) {
113
- ethereumWrites = await getTokenPrices ( 'ethereum' , timestamp , ethereumPrices ) ;
236
+ ethereumWrites = await getTokenPrices (
237
+ "ethereum" ,
238
+ timestamp ,
239
+ baseAssetPrices ,
240
+ ethereumPrices
241
+ ) ;
114
242
chains . splice ( ethereumIndex , 1 ) ;
115
243
}
116
244
117
245
if ( chains . length > 0 ) {
118
- const results = await Promise . all ( chains . map ( c => getTokenPrices ( c , timestamp , ethereumPrices ) ) ) ;
246
+ const results = await Promise . all (
247
+ chains . map ( ( chain ) =>
248
+ getTokenPrices ( chain , timestamp , baseAssetPrices , ethereumPrices )
249
+ )
250
+ ) ;
119
251
otherChainWrites = results . flat ( ) ;
120
252
}
121
253
0 commit comments