Skip to content

Commit 1f76e82

Browse files
authored
feat(target_chains/ton): add more tests for ton price_feeds contract (#2008)
* add test for correctly handling stale prices * add more tests * precommit * add test for executing governance action with invalid chain ID
1 parent 04280ea commit 1f76e82

File tree

2 files changed

+125
-6
lines changed

2 files changed

+125
-6
lines changed

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

Lines changed: 117 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import {
1313
PYTH_AUTHORIZE_GOVERNANCE_DATA_SOURCE_TRANSFER,
1414
PYTH_REQUEST_GOVERNANCE_DATA_SOURCE_TRANSFER,
1515
TEST_GUARDIAN_ADDRESS2,
16+
ETH_PRICE_FEED_ID,
17+
HERMES_BTC_PRICE,
18+
HERMES_ETH_PRICE,
19+
HERMES_ETH_PUBLISH_TIME,
20+
HERMES_BTC_PUBLISH_TIME,
1621
} from "./utils/pyth";
1722
import { GUARDIAN_SET_0, MAINNET_UPGRADE_VAAS } from "./utils/wormhole";
1823
import { DataSource } from "@pythnetwork/xc-admin-common";
@@ -235,6 +240,14 @@ describe("PythTest", () => {
235240

236241
await updateGuardianSets(pythTest, deployer);
237242

243+
// Check initial prices
244+
const initialBtcPrice = await pythTest.getPriceUnsafe(BTC_PRICE_FEED_ID);
245+
expect(initialBtcPrice.price).not.toBe(HERMES_BTC_PRICE);
246+
// Expect an error for ETH price feed as it doesn't exist initially
247+
await expect(pythTest.getPriceUnsafe(ETH_PRICE_FEED_ID)).rejects.toThrow(
248+
"Unable to execute get method. Got exit_code: 1019"
249+
); // ERROR_PRICE_FEED_NOT_FOUND = 1019
250+
238251
const updateData = Buffer.from(HERMES_BTC_ETH_UPDATE, "hex");
239252
const updateFee = await pythTest.getUpdateFee(updateData);
240253

@@ -250,10 +263,14 @@ describe("PythTest", () => {
250263
success: true,
251264
});
252265

253-
// Check if the price has been updated correctly
254-
const updatedPrice = await pythTest.getPriceUnsafe(BTC_PRICE_FEED_ID);
255-
expect(updatedPrice.price).not.toBe(Number(PRICE.price)); // Since we updated the price, it should not be the same as the initial price
256-
expect(updatedPrice.publishTime).toBeGreaterThan(PRICE.publishTime);
266+
// Check if both BTC and ETH prices have been updated
267+
const updatedBtcPrice = await pythTest.getPriceUnsafe(BTC_PRICE_FEED_ID);
268+
expect(updatedBtcPrice.price).toBe(HERMES_BTC_PRICE);
269+
expect(updatedBtcPrice.publishTime).toBe(HERMES_BTC_PUBLISH_TIME);
270+
271+
const updatedEthPrice = await pythTest.getPriceUnsafe(ETH_PRICE_FEED_ID);
272+
expect(updatedEthPrice.price).toBe(HERMES_ETH_PRICE);
273+
expect(updatedEthPrice.publishTime).toBe(HERMES_ETH_PUBLISH_TIME);
257274
});
258275

259276
it("should fail to get update fee with invalid data", async () => {
@@ -339,6 +356,21 @@ describe("PythTest", () => {
339356
});
340357
});
341358

359+
it("should correctly handle stale prices", async () => {
360+
const staleTime = Math.floor(Date.now() / 1000) - TIME_PERIOD - 10; // 10 seconds past the allowed period
361+
const stalePrice = new Price({
362+
price: "1",
363+
conf: "2",
364+
expo: 3,
365+
publishTime: staleTime,
366+
});
367+
await deployContract(BTC_PRICE_FEED_ID, TIME_PERIOD, stalePrice, EMA_PRICE);
368+
369+
await expect(
370+
pythTest.getPriceNoOlderThan(TIME_PERIOD, BTC_PRICE_FEED_ID)
371+
).rejects.toThrow("Unable to execute get method. Got exit_code: 1020"); // ERROR_OUTDATED_PRICE = 1020
372+
});
373+
342374
it("should fail to update price feeds with insufficient gas", async () => {
343375
await deployContract();
344376
await updateGuardianSets(pythTest, deployer);
@@ -385,7 +417,7 @@ describe("PythTest", () => {
385417
});
386418
});
387419

388-
it("should fail to get price for non-existent price feed", async () => {
420+
it("should fail to get prices for non-existent price feed", async () => {
389421
await deployContract();
390422

391423
const nonExistentPriceFeedId =
@@ -394,6 +426,14 @@ describe("PythTest", () => {
394426
await expect(
395427
pythTest.getPriceUnsafe(nonExistentPriceFeedId)
396428
).rejects.toThrow("Unable to execute get method. Got exit_code: 1019"); // ERROR_PRICE_FEED_NOT_FOUND = 1019
429+
430+
await expect(
431+
pythTest.getPriceNoOlderThan(TIME_PERIOD, nonExistentPriceFeedId)
432+
).rejects.toThrow("Unable to execute get method. Got exit_code: 1019"); // ERROR_PRICE_FEED_NOT_FOUND
433+
434+
await expect(
435+
pythTest.getEmaPriceUnsafe(nonExistentPriceFeedId)
436+
).rejects.toThrow("Unable to execute get method. Got exit_code: 1019"); // ERROR_PRICE_FEED_NOT_FOUND
397437
});
398438

399439
it("should correctly get chain ID", async () => {
@@ -518,7 +558,7 @@ describe("PythTest", () => {
518558
expect(result).toBe(SINGLE_UPDATE_FEE);
519559
});
520560

521-
it("should execute set fee governance instruction", async () => {
561+
it("should execute set data sources governance instruction", async () => {
522562
await deployContract(
523563
BTC_PRICE_FEED_ID,
524564
TIME_PERIOD,
@@ -572,6 +612,47 @@ describe("PythTest", () => {
572612
expect(oldDataSourceIsValid).toBe(false);
573613
});
574614

615+
it("should execute set fee governance instruction", async () => {
616+
await deployContract(
617+
BTC_PRICE_FEED_ID,
618+
TIME_PERIOD,
619+
PRICE,
620+
EMA_PRICE,
621+
SINGLE_UPDATE_FEE,
622+
DATA_SOURCES,
623+
0,
624+
[TEST_GUARDIAN_ADDRESS1],
625+
60051, // CHAIN_ID of starknet since we are using the test payload for starknet
626+
1,
627+
"0000000000000000000000000000000000000000000000000000000000000004",
628+
TEST_GOVERNANCE_DATA_SOURCES[0]
629+
);
630+
631+
// Get the initial fee
632+
const initialFee = await pythTest.getSingleUpdateFee();
633+
expect(initialFee).toBe(SINGLE_UPDATE_FEE);
634+
635+
// Execute the governance action
636+
const result = await pythTest.sendExecuteGovernanceAction(
637+
deployer.getSender(),
638+
Buffer.from(PYTH_SET_FEE, "hex")
639+
);
640+
expect(result.transactions).toHaveTransaction({
641+
from: deployer.address,
642+
to: pythTest.address,
643+
success: true,
644+
});
645+
646+
// Get the new fee
647+
const newFee = await pythTest.getSingleUpdateFee();
648+
expect(newFee).toBe(4200); // The new fee value is 4200 in the PYTH_SET_FEE payload
649+
650+
// Verify that the new fee is used for updates
651+
const updateData = Buffer.from(HERMES_BTC_ETH_UPDATE, "hex");
652+
const updateFee = await pythTest.getUpdateFee(updateData);
653+
expect(updateFee).toBe(8400); // There are two price updates in HERMES_BTC_ETH_UPDATE
654+
});
655+
575656
it("should execute authorize governance data source transfer", async () => {
576657
await deployContract(
577658
BTC_PRICE_FEED_ID,
@@ -732,6 +813,36 @@ describe("PythTest", () => {
732813
});
733814
});
734815

816+
it("should fail to execute governance action with invalid chain ID", async () => {
817+
const invalidChainId = 999;
818+
await deployContract(
819+
BTC_PRICE_FEED_ID,
820+
TIME_PERIOD,
821+
PRICE,
822+
EMA_PRICE,
823+
SINGLE_UPDATE_FEE,
824+
DATA_SOURCES,
825+
0,
826+
[TEST_GUARDIAN_ADDRESS1],
827+
invalidChainId,
828+
1,
829+
"0000000000000000000000000000000000000000000000000000000000000004",
830+
TEST_GOVERNANCE_DATA_SOURCES[0]
831+
);
832+
833+
const result = await pythTest.sendExecuteGovernanceAction(
834+
deployer.getSender(),
835+
Buffer.from(PYTH_SET_FEE, "hex")
836+
);
837+
838+
expect(result.transactions).toHaveTransaction({
839+
from: deployer.address,
840+
to: pythTest.address,
841+
success: false,
842+
exitCode: 1034, // ERROR_INVALID_GOVERNANCE_TARGET
843+
});
844+
});
845+
735846
it("should successfully upgrade the contract", async () => {
736847
// Compile the upgraded contract
737848
const upgradedCode = await compile("PythTestUpgraded");

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,17 @@
3434
export const HERMES_BTC_ETH_UPDATE =
3535
"504e41550100000003b801000000040d00a0bb18e08c0a4152eba8293e88d0ed43084dfd4677fd5dc0ff48b05d065e25511ea12181325e92541290f28e00487a7ed852fdecbee414cab803dbe1dac2392201023e177888eba8922eac9b0668566f15c61e945cd47c10fa4ca2e4d472d7d216f149f3378b4edc5f8d802c3ef9b8156ca53c9ae2d4f75dd91f7713946b4108c5910003af26c2426a1bf19f24a171bcc990dad056b670f76894e3bdb9925b21b40b3904757d8e6175133b8608431d7435e29c5fcc2912349c2c8b5588803c06f203c73401048a30050ebafd161c3cfa5531896040b6da88502734c8e42ca3197d52ea08f6ec785a24f24bc9325c16ee7b6a9791bc523523f9086162ed4ccf746b55e1b0f192010886c5256df6ca2719fe97c10b79a4a8c8574fb70add9bfe0d879ae5f6c69b2459360b50b58c43a65e881081174cce56827880e0c330b5c5681294dc3fcb78a86d010a4e0ebb1992f0e48263f6188cb5f8e871cdcd7879f54fe7ad53bbd28d5e7ff70e73441836f0d11076bd7a791aceb05d501500f6878cf26e641fffa7c8fd143371000b3ad70bd80e52a82cd740ffbd4a080bd22523bc7ac2b1242169516d7aaf2753cd7ee5b500134ef32c02284e9d806fbeab2e055ea4a94be9cbfcfbc39b249b5e6b010c97d60c0f15b18c8fb2f36331ab0a1ce0efa13e9f2118c32140bd2118823d50f12deffc40b5d0c9642b4e44a6bd1cf4f38de471536a6610e698a942f049abef35010da2004619d8b31e33037ffed4afdd97459a241dfc7fa3bcc426f175461c938a182db560547dfcdd8ede345f0cc69da33fd588c30e912b7521c3ac1b0455882628000e81868d37eb16e1988451c26cfea8bb7969ce11c89488cedea30c80e3416dd2147c0554e9a9cce1a864eb0db625baa2cbb226ae2c2f1051f84b0a711c4bf69647010f02f18088ddbabd7c4528a1f7582f5fb11e60c5e434e9fd4ca2b33d6646e2ac6e6459c651778d1531711b44d2a1204a0d9c17e218aba5e60800e80aade9f1d90400108c783ad40f93184ad4f7e84229b207b17099e78b8bd93ddf2434cba21c99b4a904d74555ced9977e6becc34fa346c3cca9332b3598e66e58eb56f9ac700074e0001270a31d95bd5426ffe943dcc2b93f05b93f8301848f0b19c56e0dea51b7742c467b6bb557f6fc6762ef4600988c2dbcad0a2be84d4c6839fbae05d227e30ce5f50166cec2c600000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000493073601415557560000000000099e556100002710c0905b1576f0bb86fe861a51273f2bcc43d12dd702005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000005634a12c5d50000000096b3a0ebfffffff80000000066cec2c60000000066cec2c600000566c715d5a000000000895abaa20a83db6da7dfbe7cc34f56265123320d7765dda3ae132c1518c53ead6cde500c139f68a894f564d817c0dfaeefa80d4ed93d36b82f7fcfe80e4092bb54d4dae770124803c592f17cb918c9ac381ce82bd6817041aa5ae95d917d75687b7a389a188846dd79bd55cb6cb9b9d0e1c0c040f1110362a8e1e87c74887326d66b213d19f7dcd1766b6f8505be50f5c98783c07ec08f913cbe38c20a31e440e42bb5a8883356dd19288e618e938ae4e7031d52d684f7bd1ddcf0d4ff63844800e14ff0c6888ff26626ea9874005500ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace000000396f6987dd00000000052fbd87fffffff80000000066cec2c60000000066cec2c6000000398c4513280000000006c9a0a10a5307d6b780c8c5579b4b61de5fe0f12a789efdc628f14603df77ba31734c5611291df9a86e51430b243b3b61ee716bd758360783bdb7ef2f96ab8e92d509d85940a832b3de426d243a6d52ccf1e538af48b1bfad061dec1e4293898ca9ca9f37d0050d7b9e6a54357e77e7d79156fa1c70d54484ce52df49e79ab3fde203359f760fd9cf78be10644a43b52a171026829814590e8ba4853f6c8f0a16ce0fe3b532bcc96ea72723ab7d19f700c153e7cfb950f4aaa691e731e6f1de4edf43a6b9dd532a8ee785f084";
3636

37+
export const HERMES_BTC_PRICE = 5924002645461;
38+
export const HERMES_BTC_PUBLISH_TIME = 1724826310;
39+
export const HERMES_ETH_PRICE = 246682322909;
40+
export const HERMES_ETH_PUBLISH_TIME = 1724826310;
41+
3742
export const BTC_PRICE_FEED_ID =
3843
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43";
3944

45+
export const ETH_PRICE_FEED_ID =
46+
"0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace";
47+
4048
export const TEST_GUARDIAN_ADDRESS1 =
4149
"0x686b9ea8e3237110eaaba1f1b7467559a3273819";
4250

0 commit comments

Comments
 (0)