Skip to content

Commit 2b19e8f

Browse files
MidasRWA: base asset price refactor (#10575)
1 parent 4284a40 commit 2b19e8f

File tree

1 file changed

+186
-54
lines changed

1 file changed

+186
-54
lines changed

coins/src/adapters/rwa/midas.ts

Lines changed: 186 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,95 +2,216 @@ import { Write } from "../utils/dbInterfaces";
22
import { getApi } from "../utils/sdk";
33
import getWrites from "../utils/getWrites";
44

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;
724

8-
const contracts: {
9-
[chain: string]: { name: string; token: string; oracle?: string; requiresConversion?: boolean }[];
10-
} = {
25+
const contracts: Record<string, TokenConfig[]> = {
1126
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+
},
2384
],
2485
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+
},
2796
],
2897
sapphire: [
2998
{ name: "mTBILL", token: "0xDD629E5241CbC5919847783e6C96B2De4754e438" },
3099
],
31100
etlk: [
32101
{ name: "mTBILL", token: "0xDD629E5241CbC5919847783e6C96B2De4754e438" },
33102
{ name: "mBASIS", token: "0x2247B5A46BB79421a314aB0f0b67fFd11dd37Ee4" },
103+
{ name: "mMEV", token: "0x5542F82389b76C23f5848268893234d8A63fd5c8" },
104+
{ name: "mRe7YIELD", token: "0x733d504435a49FC8C4e9759e756C2846c92f0160" },
34105
],
35106
rsk: [
36107
{ name: "mTBILL", token: "0xDD629E5241CbC5919847783e6C96B2De4754e438" },
37-
{ name: "mBTC", token: "0xEF85254Aa4a8490bcC9C02Ae38513Cae8303FB53" },
108+
{
109+
name: "mBTC",
110+
token: "0xEF85254Aa4a8490bcC9C02Ae38513Cae8303FB53",
111+
denomination: "BTC",
112+
},
38113
],
39114
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+
},
44135
],
45136
katana: [
46-
{ name: "mRE7SOL", token: "0xC6135d59F8D10c9C035963ce9037B3635170D716", oracle: "0x001b3731c706fEd93BDA240A5BF848C28ae1cC12" },
47-
]
137+
{
138+
name: "mRE7SOL",
139+
token: "0xC6135d59F8D10c9C035963ce9037B3635170D716",
140+
oracle: "0x001b3731c706fEd93BDA240A5BF848C28ae1cC12",
141+
denomination: "SOL",
142+
},
143+
],
48144
};
49145

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>> {
53149
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;
56164
}
57165

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[]> {
59172
const api = await getApi(chain, timestamp);
60173
const tokens = contracts[chain] || [];
61-
const btcToUsdPrice = await getBtcToUsdPrice(timestamp);
62174

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 }> = {};
65179

66-
let prices: Record<string, { price: number }> = {};
67180
if (tokensWithOracles.length > 0) {
68-
const dataFeedResponses = await api.multiCall({
181+
const oracleResponses = await api.multiCall({
69182
abi: DATA_FEED_ABI,
70-
calls: tokensWithOracles.map(({ oracle }) => oracle as string),
183+
calls: tokensWithOracles.map((t) => t.oracle as string),
71184
});
72185

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 };
78200

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;
81204
}
82205
}
83-
return acc;
84-
}, {} as Record<string, { price: number }>);
206+
});
85207
}
86208

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];
90211
if (fallbackPrice !== undefined) {
91-
prices[token] = { price: fallbackPrice };
212+
prices[token.token] = { price: fallbackPrice };
92213
}
93-
}
214+
});
94215

95216
return getWrites({
96217
chain,
@@ -101,21 +222,32 @@ async function getTokenPrices(chain: string, timestamp: number, ethereumPrices:
101222
}
102223

103224
export async function midas(timestamp: number = 0): Promise<Write[]> {
225+
const baseAssetPrices = await getBaseAssetPrices(timestamp);
226+
104227
const ethereumPrices: Record<string, number> = {};
105228

106229
const chains = Object.keys(contracts);
107-
const ethereumIndex = chains.indexOf('ethereum');
230+
const ethereumIndex = chains.indexOf("ethereum");
108231

109232
let ethereumWrites: Write[] = [];
110233
let otherChainWrites: Write[] = [];
111234

112235
if (ethereumIndex !== -1) {
113-
ethereumWrites = await getTokenPrices('ethereum', timestamp, ethereumPrices);
236+
ethereumWrites = await getTokenPrices(
237+
"ethereum",
238+
timestamp,
239+
baseAssetPrices,
240+
ethereumPrices
241+
);
114242
chains.splice(ethereumIndex, 1);
115243
}
116244

117245
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+
);
119251
otherChainWrites = results.flat();
120252
}
121253

0 commit comments

Comments
 (0)