Skip to content

Commit e35bd17

Browse files
committed
feat(target_chains/ton): add helper function to parse price IDs beyond a single cell and enhance update handling
1 parent cd44d2b commit e35bd17

File tree

3 files changed

+305
-14
lines changed

3 files changed

+305
-14
lines changed

target_chains/ton/contracts/contracts/Pyth.fc

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -369,17 +369,51 @@ cell create_price_feed_cell_chain(tuple price_feeds) {
369369
0);
370370
}
371371

372+
;; Helper function to parse price IDs from a slice, handling cell chain traversal
373+
;; Returns a tuple containing the parsed price IDs
374+
tuple parse_price_ids_from_slice(slice price_ids_slice) {
375+
int price_ids_len = price_ids_slice~load_uint(8);
376+
tuple price_ids = empty_tuple();
377+
378+
;; Process each price ID, handling potential cell boundaries
379+
int i = 0;
380+
while (i < price_ids_len) {
381+
builder price_id_builder = begin_cell();
382+
int bits_loaded = 0;
383+
384+
;; We need to load exactly 256 bits for each price ID
385+
while (bits_loaded < 256) {
386+
;; Calculate how many bits we can load from the current slice
387+
int bits_to_load = min(price_ids_slice.slice_bits(), 256 - bits_loaded);
388+
389+
;; Load and store those bits
390+
price_id_builder = price_id_builder.store_slice(price_ids_slice~load_bits(bits_to_load));
391+
bits_loaded += bits_to_load;
392+
393+
;; If we haven't loaded all 256 bits yet, we need to move to the next cell
394+
if (bits_loaded < 256) {
395+
;; Make sure we have a next cell to load from
396+
throw_unless(35, ~ price_ids_slice.slice_refs_empty?());
397+
price_ids_slice = price_ids_slice~load_ref().begin_parse();
398+
}
399+
}
400+
401+
;; Extract the complete price ID from the builder
402+
slice price_id_slice = price_id_builder.end_cell().begin_parse();
403+
int price_id = price_id_slice~load_uint(256);
404+
price_ids~tpush(price_id);
405+
i += 1;
406+
}
407+
408+
return price_ids;
409+
}
410+
372411
() parse_price_feed_updates(int msg_value, slice update_data_slice, slice price_ids_slice, int min_publish_time, int max_publish_time, slice sender_address, slice target_address, slice custom_payload) impure {
373412
try {
374413
load_data();
375414

376-
;; Load price_ids tuple
377-
int price_ids_len = price_ids_slice~load_uint(8);
378-
tuple price_ids = empty_tuple();
379-
repeat(price_ids_len) {
380-
int price_id = price_ids_slice~load_uint(256);
381-
price_ids~tpush(price_id);
382-
}
415+
;; Use the helper function to parse price IDs
416+
tuple price_ids = parse_price_ids_from_slice(price_ids_slice);
383417

384418
tuple price_feeds = parse_price_feeds_from_data(msg_value, update_data_slice, price_ids, min_publish_time, max_publish_time, false);
385419
send_price_feeds_response(price_feeds, msg_value, OP_PARSE_PRICE_FEED_UPDATES,
@@ -395,13 +429,8 @@ cell create_price_feed_cell_chain(tuple price_feeds) {
395429
try {
396430
load_data();
397431

398-
;; Load price_ids tuple
399-
int price_ids_len = price_ids_slice~load_uint(8);
400-
tuple price_ids = empty_tuple();
401-
repeat(price_ids_len) {
402-
int price_id = price_ids_slice~load_uint(256);
403-
price_ids~tpush(price_id);
404-
}
432+
;; Use the helper function to parse price IDs
433+
tuple price_ids = parse_price_ids_from_slice(price_ids_slice);
405434

406435
tuple price_feeds = parse_price_feeds_from_data(msg_value, update_data_slice, price_ids, publish_time, publish_time + max_staleness, true);
407436
send_price_feeds_response(price_feeds, msg_value, OP_PARSE_UNIQUE_PRICE_FEED_UPDATES, sender_address, target_address, custom_payload);

target_chains/ton/contracts/tests/PythTest.spec.ts

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ import {
4545
HERMES_ETH_UNIQUE_EXPO,
4646
HERMES_ETH_UNIQUE_PRICE,
4747
HERMES_ETH_UNIQUE_PUBLISH_TIME,
48+
HERMES_SOL_TON_PYTH_USDT_UPDATE,
49+
PYTH_PRICE_FEED_ID,
50+
SOL_PRICE_FEED_ID,
51+
TON_PRICE_FEED_ID,
52+
USDT_PRICE_FEED_ID,
53+
HERMES_SOL_UNIQUE_PUBLISH_TIME,
54+
HERMES_SOL_UNIQUE_PRICE,
55+
HERMES_SOL_UNIQUE_CONF,
56+
HERMES_SOL_UNIQUE_EXPO,
4857
} from "./utils/pyth";
4958
import { GUARDIAN_SET_0, MAINNET_UPGRADE_VAAS } from "./utils/wormhole";
5059
import { DataSource } from "@pythnetwork/xc-admin-common";
@@ -1110,6 +1119,86 @@ describe("PythTest", () => {
11101119
);
11111120
});
11121121

1122+
it("should successfully parse price feed updates with more than 3 price feed ids", async () => {
1123+
await deployContract();
1124+
await updateGuardianSets(pythTest, deployer);
1125+
1126+
const sentValue = toNano("1");
1127+
const result = await pythTest.sendParsePriceFeedUpdates(
1128+
deployer.getSender(),
1129+
Buffer.from(HERMES_SOL_TON_PYTH_USDT_UPDATE, "hex"),
1130+
sentValue,
1131+
[SOL_PRICE_FEED_ID, TON_PRICE_FEED_ID, PYTH_PRICE_FEED_ID, USDT_PRICE_FEED_ID],
1132+
HERMES_SOL_UNIQUE_PUBLISH_TIME,
1133+
HERMES_SOL_UNIQUE_PUBLISH_TIME,
1134+
deployer.address,
1135+
CUSTOM_PAYLOAD,
1136+
);
1137+
1138+
// Verify transaction success and message count
1139+
expect(result.transactions).toHaveTransaction({
1140+
from: deployer.address,
1141+
to: pythTest.address,
1142+
success: true,
1143+
outMessagesCount: 1,
1144+
});
1145+
1146+
// Get the output message
1147+
const outMessage = result.transactions[1].outMessages.values()[0];
1148+
1149+
// Verify excess value is returned
1150+
expect(
1151+
(outMessage.info as CommonMessageInfoInternal).value.coins,
1152+
).toBeGreaterThan(0);
1153+
1154+
const cs = outMessage.body.beginParse();
1155+
1156+
// Verify message header
1157+
const op = cs.loadUint(32);
1158+
expect(op).toBe(5); // OP_PARSE_PRICE_FEED_UPDATES
1159+
1160+
// Verify number of price feeds
1161+
const numPriceFeeds = cs.loadUint(8);
1162+
expect(numPriceFeeds).toBe(4); // We expect SOL, TON, PYTH and USDT price feeds
1163+
1164+
// Load and verify price feeds
1165+
const priceFeedsCell = cs.loadRef();
1166+
let currentCell = priceFeedsCell;
1167+
1168+
// First price feed (SOL)
1169+
const solCs = currentCell.beginParse();
1170+
const solPriceId =
1171+
"0x" + solCs.loadUintBig(256).toString(16).padStart(64, "0");
1172+
expect(solPriceId).toBe(SOL_PRICE_FEED_ID);
1173+
1174+
const solPriceFeedCell = solCs.loadRef();
1175+
const solPriceFeedSlice = solPriceFeedCell.beginParse();
1176+
1177+
// Verify SOL current price
1178+
const solCurrentPriceCell = solPriceFeedSlice.loadRef();
1179+
const solCurrentPrice = solCurrentPriceCell.beginParse();
1180+
expect(solCurrentPrice.loadInt(64)).toBe(HERMES_SOL_UNIQUE_PRICE);
1181+
expect(solCurrentPrice.loadUint(64)).toBe(HERMES_SOL_UNIQUE_CONF);
1182+
expect(solCurrentPrice.loadInt(32)).toBe(HERMES_SOL_UNIQUE_EXPO);
1183+
expect(solCurrentPrice.loadUint(64)).toBe(HERMES_SOL_UNIQUE_PUBLISH_TIME);
1184+
1185+
// Verify sender address
1186+
const senderAddress = cs.loadAddress();
1187+
expect(senderAddress?.toString()).toBe(
1188+
deployer.getSender().address.toString(),
1189+
);
1190+
1191+
// Verify custom payload
1192+
const customPayloadCell = cs.loadRef();
1193+
const customPayloadSlice = customPayloadCell.beginParse();
1194+
const receivedPayload = Buffer.from(
1195+
customPayloadSlice.loadBuffer(CUSTOM_PAYLOAD.length),
1196+
);
1197+
expect(receivedPayload.toString("hex")).toBe(
1198+
CUSTOM_PAYLOAD.toString("hex"),
1199+
);
1200+
});
1201+
11131202
it("should successfully parse unique price feed updates", async () => {
11141203
await deployContract();
11151204
await updateGuardianSets(pythTest, deployer);
@@ -1229,6 +1318,85 @@ describe("PythTest", () => {
12291318
);
12301319
});
12311320

1321+
it("should successfully parse unique price feed updates with more than 3 price feed ids", async () => {
1322+
await deployContract();
1323+
await updateGuardianSets(pythTest, deployer);
1324+
1325+
const sentValue = toNano("1");
1326+
const result = await pythTest.sendParseUniquePriceFeedUpdates(
1327+
deployer.getSender(),
1328+
Buffer.from(HERMES_SOL_TON_PYTH_USDT_UPDATE, "hex"),
1329+
sentValue,
1330+
[SOL_PRICE_FEED_ID, TON_PRICE_FEED_ID, PYTH_PRICE_FEED_ID, USDT_PRICE_FEED_ID],
1331+
HERMES_SOL_UNIQUE_PUBLISH_TIME,
1332+
60,
1333+
deployer.address,
1334+
CUSTOM_PAYLOAD,
1335+
);
1336+
1337+
// Verify transaction success and message count
1338+
expect(result.transactions).toHaveTransaction({
1339+
from: deployer.address,
1340+
to: pythTest.address,
1341+
success: true,
1342+
outMessagesCount: 1,
1343+
});
1344+
1345+
// Get the output message
1346+
const outMessage = result.transactions[1].outMessages.values()[0];
1347+
1348+
// Verify excess value is returned
1349+
expect(
1350+
(outMessage.info as CommonMessageInfoInternal).value.coins,
1351+
).toBeGreaterThan(0);
1352+
1353+
const cs = outMessage.body.beginParse();
1354+
1355+
// Verify message header
1356+
const op = cs.loadUint(32);
1357+
expect(op).toBe(6); // OP_PARSE_UNIQUE_PRICE_FEED_UPDATES
1358+
1359+
// Verify number of price feeds
1360+
const numPriceFeeds = cs.loadUint(8);
1361+
expect(numPriceFeeds).toBe(4); // We expect SOL, TON, PYTH and USDT price feeds
1362+
1363+
// Load and verify price feeds
1364+
const priceFeedsCell = cs.loadRef();
1365+
let currentCell = priceFeedsCell;
1366+
1367+
// First price feed (SOL)
1368+
const solCs = currentCell.beginParse();
1369+
const solPriceId =
1370+
"0x" + solCs.loadUintBig(256).toString(16).padStart(64, "0");
1371+
expect(solPriceId).toBe(SOL_PRICE_FEED_ID);
1372+
1373+
const solPriceFeedCell = solCs.loadRef();
1374+
const solPriceFeedSlice = solPriceFeedCell.beginParse();
1375+
1376+
// Verify SOL current price
1377+
const solCurrentPriceCell = solPriceFeedSlice.loadRef();
1378+
const solCurrentPrice = solCurrentPriceCell.beginParse();
1379+
expect(solCurrentPrice.loadInt(64)).toBe(HERMES_SOL_UNIQUE_PRICE);
1380+
expect(solCurrentPrice.loadUint(64)).toBe(HERMES_SOL_UNIQUE_CONF);
1381+
expect(solCurrentPrice.loadInt(32)).toBe(HERMES_SOL_UNIQUE_EXPO);
1382+
expect(solCurrentPrice.loadUint(64)).toBe(HERMES_SOL_UNIQUE_PUBLISH_TIME);
1383+
// Verify sender address
1384+
const senderAddress = cs.loadAddress();
1385+
expect(senderAddress?.toString()).toBe(
1386+
deployer.getSender().address.toString(),
1387+
);
1388+
1389+
// Verify custom payload
1390+
const customPayloadCell = cs.loadRef();
1391+
const customPayloadSlice = customPayloadCell.beginParse();
1392+
const receivedPayload = Buffer.from(
1393+
customPayloadSlice.loadBuffer(CUSTOM_PAYLOAD.length),
1394+
);
1395+
expect(receivedPayload.toString("hex")).toBe(
1396+
CUSTOM_PAYLOAD.toString("hex"),
1397+
);
1398+
});
1399+
12321400
it("should fail to parse invalid price feed updates", async () => {
12331401
await deployContract();
12341402
await updateGuardianSets(pythTest, deployer);

target_chains/ton/contracts/tests/utils/pyth.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,97 @@ export const PYTH_SET_DATA_SOURCES =
108108
// From: target_chains/starknet/contracts/tests/data.cairo::pyth_request_transfer()
109109
export const PYTH_REQUEST_GOVERNANCE_DATA_SOURCE_TRANSFER =
110110
"01000000000100b3abee2eed7d504284c57387abcbb87fe9cf4807228d2d08b776ea94347bdaa73e6958ce95a49d11b9a07fdc93a6705b666fb8a76c0cff0578eb2c881d80b29e0100000001000000020002000000000000000000000000000000000000000000000000000000000000002b0000000000000001065054474d0105ea9300000001";
111+
112+
/*
113+
This update contains price information for four assets:
114+
1. SOL/USD (id: ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d)
115+
price:
116+
- price: 11497583407
117+
- conf: 5485109
118+
- expo: -8
119+
- publish_time: 1743742256
120+
ema_price:
121+
- price: 11524090900
122+
- conf: 6082720
123+
- expo: -8
124+
- publish_time: 1743742256
125+
metadata:
126+
- slot: 208345111
127+
- proof_available_time: 1743742257
128+
- prev_publish_time: 1743742255
129+
2. TON/USD (id: 8963217838ab4cf5cadc172203c1f0b763fbaa45f346d8ee50ba994bbcac3026)
130+
price:
131+
- price: 350942142
132+
- conf: 410727
133+
- expo: -8
134+
- publish_time: 1743742256
135+
ema_price:
136+
- price: 351975630
137+
- conf: 406678
138+
- expo: -8
139+
- publish_time: 1743742256
140+
metadata:
141+
- slot: 208345111
142+
- proof_available_time: 1743742257
143+
- prev_publish_time: 1743742255
144+
3. PYTH/USD (id: 0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff)
145+
price:
146+
- price: 12970522
147+
- conf: 16981
148+
- expo: -8
149+
- publish_time: 1743742256
150+
ema_price:
151+
- price: 13006200
152+
- conf: 17661
153+
- expo: -8
154+
- publish_time: 1743742256
155+
metadata:
156+
- slot: 208345111
157+
- proof_available_time: 1743742257
158+
- prev_publish_time: 1743742255
159+
4. USDT/USD (id: 2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b)
160+
price:
161+
- price: 99964242
162+
- conf: 52240
163+
- expo: -8
164+
- publish_time: 1743742256
165+
ema_price:
166+
- price: 99963419
167+
- conf: 65279
168+
- expo: -8
169+
- publish_time: 1743742256
170+
metadata:
171+
- slot: 208345111
172+
- proof_available_time: 1743742257
173+
- prev_publish_time: 1743742255
174+
*/
175+
export const HERMES_SOL_TON_PYTH_USDT_UPDATE = "504e41550100000003b801000000040d00a699130558c81e1326548d3e8066a9ad7e00d775bbd76ecc0d23b986eb049a2e3f8d6717318a5ac1316ca37c25251b28ecf900a86acb196e87311d1d663fc1b301022bab82b2b65d442f9018583a12a46ea6d51734dd00b8110627cb250ea45e1c040fd95b82ed60d2e998323a373e60dddf96a50f09e5b57ec8eca3b1bbcc2a3d3d0103762903038517f06d83f26e0dfc8e96aca662be75384d7533b5664cae4463e7db083c0c3a3fab130651a2e75b6e8c39cbe828025b18dbfe2869761769a27bfdab0004e55635d2887f1ed0fe95fe96396ae7fc36d9c099e3f580035b4e0dfe44e6273f31c60c3adcad567cb983dbdf954fac688d34c9b429fcf6dd09eeaa9ab64ec23401060572e9399dc50608ecabc7a58389b2df675d727e3f7f8cd697685c3555b6ff463368b535a6100e84e445a420bcd4369d1b76320cac160ba60a60a9e0ad007dad0008ab89305615bdfebdd35377dbe6e665cf4aa59150bfe18b31a545d48eb75c023242854f3a9bec6c5a38898323f56e41747f1f8c4c2d8e98fc57f3b840d120435c000a5f726e236ffdadad272a0cc5972ee326a3436db009de80dcf4aa6491a71321722c8e68a7c65ac3528b87c42a50c268148aec512defb2e074281bbb85835dbbd3000b361860629b7cea436a81f7e73d3daaa6697ab6a250a35e35ca9da121a4fc627a304b18aa2740b1f9462c28c07a60a3f964b38979ba5bc0d7f44c961637ab67d5000cc9994b20b8fa52c3d3e461a173d8ca062fc2965eefde9551d054693095a0ced619958b2c76b9f385496abb7bdf6618cccf2ffb355d43ae287504b9e4105c52f6010d69300bae67d8a39ee458f351f34ab3ae81c0ab005c9bdb70b27db266d9a105315c9259da11cdae73155d9b4db7e89da6c2367721c2e015efc8d3a6e3259cbd7d010e63d9e740f33b345557887702bc75be800631cfcad686b23d04072be36d02416e3deee9d090390651f53099df558f7e56a95e8f2cb4bb0bbfb23a74508d58f39c000f6d64d1f7e23ebc8164ebed052796ce35f150fe24a89129bd1f00b9d79b1bf4e256a308c0b77777b1fb29d72e0219867648e097f67c3782c9f3f097ffd7b237d3011088a52c3298ec2f5ea9f4b205afb9413fecbf55531399c429d79d9fed568cb7db02620c43ee573cabb4992c9f43b056bae4c19747965d366e4ac018896c43015a0067ef653000000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa7100000000075dd077014155575600000000000c6b18170000271001792ab62bbcfe4a0075c69ec3d0efc811aba31304005500ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d00000002ad4f332f000000000053b235fffffff80000000067ef65300000000067ef652f00000002aee3ac1400000000005cd0a00cba900a539aff592eec3badf4d8ce65b2f2defcd16c3707475f792d837dae4aadb7ecf0885006f67a1eeb41aea7b27d7164fe5c7d48f284aad1cdb0117fb3b3c2966dc36ad1fc2f13d80090d83f8a1cb73354aedeeacce8d01445dcaf91b0fce506b2fafa680621e940629ed7ff7e30beb0fa65f2419d692e44c3c88c780c00932c814f99c07a2c1434eeae42dab0406471a6fe43128d89e8a57239acf78b24d4886af436c8e5fa15900dc9314576a0beaa191bdf1eaea528893c7823097f5b66cd2e53a954a01e5018ec3a52b1c8fdd57b611e46c8b0bf327543d953a0168a859e832e5bbe3b68be339667fd74870dc70055008963217838ab4cf5cadc172203c1f0b763fbaa45f346d8ee50ba994bbcac30260000000014eaf3be0000000000064467fffffff80000000067ef65300000000067ef652f0000000014fab8ce00000000000634960c7ce9b36e2e29e615f61a96aab7de93a24352ec1b16d3d1817dedfc059ba8bc6122841f57c631ed55d9fc8f1255ab59fec80446534b48bef6ae94398a4152943498df64ab8617d0bcba8a34f09a910aedd4f28fb48e0b985b06b79535b0db48aa93fdeb1e9441e62912428632000ec14968f1f7e57c06932dae5d5199a436f53b39ea32534b4d831b42b1dced15f9fecf554f775dd826e2baf6dc24b50b057bb856458cb740d61ebb3573bc47e5bff2fcb8f920f1c3e05e16bb2882f9f8e9985aa95e8b0eefb49e77494dca59cdbd03b1ab12edb5b9500e660595d114a0168a859e832e5bbe3b68be339667fd74870dc70055000bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff0000000000c5ea1a0000000000004255fffffff80000000067ef65300000000067ef652f0000000000c6757800000000000044fd0cd96d0a4d7bcd660823ec72348e515182e431c160bce78f8bd62d8c4b25880827df715a65da0fc7b7d307adf46e376ce0bebbd3fbb4b57ce6abc0d535eff844a06ee0cc53b8799f034b6103c93a35f9ecee5f66cb95c873414d6d8f5ed3b9589d4d7a9e9a69da9c2becb6532935e74ecdd2c514e19e3d0f567510f182db3aad233517aac06a5a4ad07ce53304a0574a3eb9592abb0aa82de1047945659e374a7507d4fb148a9492a1ea00a7e1946f86fd2a310f8e5ed290e2d75627e1d7549cab8411b5c595b196e1494dca59cdbd03b1ab12edb5b9500e660595d114a0168a859e832e5bbe3b68be339667fd74870dc70055002b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b0000000005f55552000000000000cc10fffffff80000000067ef65300000000067ef652f0000000005f5521b000000000000feff0ce0fcd4d8f57fab900d72db1dd5bcfc0827dbf3c7f0fd02d308f63ea261b7033de5fb74e9ed7ea9fa7b1cea9c390503d0a0141ec54bb59366e9091339087139a2710703cedf2e021e244d3a0e0ec875482a744865366074d5f3c2412bb72042bf1f1f80f2cf854b3cb3ca2338b91559d5ab17404631d4f38989db698290fac116d1db42abcb0dc0f1af93d4a0a63d9f371c5d78f79248f4b4b4156dd7b044333b8c728e42c745dfb341a8802b1fd033dd7864aa0a5ed290e2d75627e1d7549cab8411b5c595b196e1494dca59cdbd03b1ab12edb5b9500e660595d114a0168a859e832e5bbe3b68be339667fd74870dc7"
176+
177+
export const SOL_PRICE_FEED_ID =
178+
"0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d";
179+
export const TON_PRICE_FEED_ID =
180+
"0x8963217838ab4cf5cadc172203c1f0b763fbaa45f346d8ee50ba994bbcac3026";
181+
export const PYTH_PRICE_FEED_ID =
182+
"0x0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff";
183+
export const USDT_PRICE_FEED_ID =
184+
"0x2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b";
185+
186+
export const HERMES_SOL_UNIQUE_PRICE = 11497583407;
187+
export const HERMES_SOL_UNIQUE_CONF = 5485109;
188+
export const HERMES_SOL_UNIQUE_EXPO = -8;
189+
export const HERMES_SOL_UNIQUE_PUBLISH_TIME = 1743742256;
190+
191+
export const HERMES_TON_UNIQUE_PRICE = 350942142;
192+
export const HERMES_TON_UNIQUE_CONF = 410727;
193+
export const HERMES_TON_UNIQUE_EXPO = -8;
194+
export const HERMES_TON_UNIQUE_PUBLISH_TIME = 1743742256;
195+
196+
export const HERMES_PYTH_UNIQUE_PRICE = 12970522;
197+
export const HERMES_PYTH_UNIQUE_CONF = 16981;
198+
export const HERMES_PYTH_UNIQUE_EXPO = -8;
199+
export const HERMES_PYTH_UNIQUE_PUBLISH_TIME = 1743742256;
200+
201+
export const HERMES_USDT_UNIQUE_EMA_PRICE = 99964242;
202+
export const HERMES_USDT_UNIQUE_EMA_CONF = 52240;
203+
export const HERMES_USDT_UNIQUE_EMA_EXPO = -8;
204+
export const HERMES_USDT_UNIQUE_EMA_PUBLISH_TIME = 1743742256;

0 commit comments

Comments
 (0)