diff --git a/target_chains/ton/contracts/tests/PythTest.spec.ts b/target_chains/ton/contracts/tests/PythTest.spec.ts index 34be57a879..00cf001389 100644 --- a/target_chains/ton/contracts/tests/PythTest.spec.ts +++ b/target_chains/ton/contracts/tests/PythTest.spec.ts @@ -13,6 +13,11 @@ import { PYTH_AUTHORIZE_GOVERNANCE_DATA_SOURCE_TRANSFER, PYTH_REQUEST_GOVERNANCE_DATA_SOURCE_TRANSFER, TEST_GUARDIAN_ADDRESS2, + ETH_PRICE_FEED_ID, + HERMES_BTC_PRICE, + HERMES_ETH_PRICE, + HERMES_ETH_PUBLISH_TIME, + HERMES_BTC_PUBLISH_TIME, } from "./utils/pyth"; import { GUARDIAN_SET_0, MAINNET_UPGRADE_VAAS } from "./utils/wormhole"; import { DataSource } from "@pythnetwork/xc-admin-common"; @@ -235,6 +240,14 @@ describe("PythTest", () => { await updateGuardianSets(pythTest, deployer); + // Check initial prices + const initialBtcPrice = await pythTest.getPriceUnsafe(BTC_PRICE_FEED_ID); + expect(initialBtcPrice.price).not.toBe(HERMES_BTC_PRICE); + // Expect an error for ETH price feed as it doesn't exist initially + await expect(pythTest.getPriceUnsafe(ETH_PRICE_FEED_ID)).rejects.toThrow( + "Unable to execute get method. Got exit_code: 1019" + ); // ERROR_PRICE_FEED_NOT_FOUND = 1019 + const updateData = Buffer.from(HERMES_BTC_ETH_UPDATE, "hex"); const updateFee = await pythTest.getUpdateFee(updateData); @@ -250,10 +263,14 @@ describe("PythTest", () => { success: true, }); - // Check if the price has been updated correctly - const updatedPrice = await pythTest.getPriceUnsafe(BTC_PRICE_FEED_ID); - expect(updatedPrice.price).not.toBe(Number(PRICE.price)); // Since we updated the price, it should not be the same as the initial price - expect(updatedPrice.publishTime).toBeGreaterThan(PRICE.publishTime); + // Check if both BTC and ETH prices have been updated + const updatedBtcPrice = await pythTest.getPriceUnsafe(BTC_PRICE_FEED_ID); + expect(updatedBtcPrice.price).toBe(HERMES_BTC_PRICE); + expect(updatedBtcPrice.publishTime).toBe(HERMES_BTC_PUBLISH_TIME); + + const updatedEthPrice = await pythTest.getPriceUnsafe(ETH_PRICE_FEED_ID); + expect(updatedEthPrice.price).toBe(HERMES_ETH_PRICE); + expect(updatedEthPrice.publishTime).toBe(HERMES_ETH_PUBLISH_TIME); }); it("should fail to get update fee with invalid data", async () => { @@ -339,6 +356,21 @@ describe("PythTest", () => { }); }); + it("should correctly handle stale prices", async () => { + const staleTime = Math.floor(Date.now() / 1000) - TIME_PERIOD - 10; // 10 seconds past the allowed period + const stalePrice = new Price({ + price: "1", + conf: "2", + expo: 3, + publishTime: staleTime, + }); + await deployContract(BTC_PRICE_FEED_ID, TIME_PERIOD, stalePrice, EMA_PRICE); + + await expect( + pythTest.getPriceNoOlderThan(TIME_PERIOD, BTC_PRICE_FEED_ID) + ).rejects.toThrow("Unable to execute get method. Got exit_code: 1020"); // ERROR_OUTDATED_PRICE = 1020 + }); + it("should fail to update price feeds with insufficient gas", async () => { await deployContract(); await updateGuardianSets(pythTest, deployer); @@ -385,7 +417,7 @@ describe("PythTest", () => { }); }); - it("should fail to get price for non-existent price feed", async () => { + it("should fail to get prices for non-existent price feed", async () => { await deployContract(); const nonExistentPriceFeedId = @@ -394,6 +426,14 @@ describe("PythTest", () => { await expect( pythTest.getPriceUnsafe(nonExistentPriceFeedId) ).rejects.toThrow("Unable to execute get method. Got exit_code: 1019"); // ERROR_PRICE_FEED_NOT_FOUND = 1019 + + await expect( + pythTest.getPriceNoOlderThan(TIME_PERIOD, nonExistentPriceFeedId) + ).rejects.toThrow("Unable to execute get method. Got exit_code: 1019"); // ERROR_PRICE_FEED_NOT_FOUND + + await expect( + pythTest.getEmaPriceUnsafe(nonExistentPriceFeedId) + ).rejects.toThrow("Unable to execute get method. Got exit_code: 1019"); // ERROR_PRICE_FEED_NOT_FOUND }); it("should correctly get chain ID", async () => { @@ -518,7 +558,7 @@ describe("PythTest", () => { expect(result).toBe(SINGLE_UPDATE_FEE); }); - it("should execute set fee governance instruction", async () => { + it("should execute set data sources governance instruction", async () => { await deployContract( BTC_PRICE_FEED_ID, TIME_PERIOD, @@ -572,6 +612,47 @@ describe("PythTest", () => { expect(oldDataSourceIsValid).toBe(false); }); + it("should execute set fee governance instruction", async () => { + await deployContract( + BTC_PRICE_FEED_ID, + TIME_PERIOD, + PRICE, + EMA_PRICE, + SINGLE_UPDATE_FEE, + DATA_SOURCES, + 0, + [TEST_GUARDIAN_ADDRESS1], + 60051, // CHAIN_ID of starknet since we are using the test payload for starknet + 1, + "0000000000000000000000000000000000000000000000000000000000000004", + TEST_GOVERNANCE_DATA_SOURCES[0] + ); + + // Get the initial fee + const initialFee = await pythTest.getSingleUpdateFee(); + expect(initialFee).toBe(SINGLE_UPDATE_FEE); + + // Execute the governance action + const result = await pythTest.sendExecuteGovernanceAction( + deployer.getSender(), + Buffer.from(PYTH_SET_FEE, "hex") + ); + expect(result.transactions).toHaveTransaction({ + from: deployer.address, + to: pythTest.address, + success: true, + }); + + // Get the new fee + const newFee = await pythTest.getSingleUpdateFee(); + expect(newFee).toBe(4200); // The new fee value is 4200 in the PYTH_SET_FEE payload + + // Verify that the new fee is used for updates + const updateData = Buffer.from(HERMES_BTC_ETH_UPDATE, "hex"); + const updateFee = await pythTest.getUpdateFee(updateData); + expect(updateFee).toBe(8400); // There are two price updates in HERMES_BTC_ETH_UPDATE + }); + it("should execute authorize governance data source transfer", async () => { await deployContract( BTC_PRICE_FEED_ID, @@ -732,6 +813,36 @@ describe("PythTest", () => { }); }); + it("should fail to execute governance action with invalid chain ID", async () => { + const invalidChainId = 999; + await deployContract( + BTC_PRICE_FEED_ID, + TIME_PERIOD, + PRICE, + EMA_PRICE, + SINGLE_UPDATE_FEE, + DATA_SOURCES, + 0, + [TEST_GUARDIAN_ADDRESS1], + invalidChainId, + 1, + "0000000000000000000000000000000000000000000000000000000000000004", + TEST_GOVERNANCE_DATA_SOURCES[0] + ); + + const result = await pythTest.sendExecuteGovernanceAction( + deployer.getSender(), + Buffer.from(PYTH_SET_FEE, "hex") + ); + + expect(result.transactions).toHaveTransaction({ + from: deployer.address, + to: pythTest.address, + success: false, + exitCode: 1034, // ERROR_INVALID_GOVERNANCE_TARGET + }); + }); + it("should successfully upgrade the contract", async () => { // Compile the upgraded contract const upgradedCode = await compile("PythTestUpgraded"); diff --git a/target_chains/ton/contracts/tests/utils/pyth.ts b/target_chains/ton/contracts/tests/utils/pyth.ts index e631bccc1b..8da8d67794 100644 --- a/target_chains/ton/contracts/tests/utils/pyth.ts +++ b/target_chains/ton/contracts/tests/utils/pyth.ts @@ -34,9 +34,17 @@ export const HERMES_BTC_ETH_UPDATE = "504e41550100000003b801000000040d00a0bb18e08c0a4152eba8293e88d0ed43084dfd4677fd5dc0ff48b05d065e25511ea12181325e92541290f28e00487a7ed852fdecbee414cab803dbe1dac2392201023e177888eba8922eac9b0668566f15c61e945cd47c10fa4ca2e4d472d7d216f149f3378b4edc5f8d802c3ef9b8156ca53c9ae2d4f75dd91f7713946b4108c5910003af26c2426a1bf19f24a171bcc990dad056b670f76894e3bdb9925b21b40b3904757d8e6175133b8608431d7435e29c5fcc2912349c2c8b5588803c06f203c73401048a30050ebafd161c3cfa5531896040b6da88502734c8e42ca3197d52ea08f6ec785a24f24bc9325c16ee7b6a9791bc523523f9086162ed4ccf746b55e1b0f192010886c5256df6ca2719fe97c10b79a4a8c8574fb70add9bfe0d879ae5f6c69b2459360b50b58c43a65e881081174cce56827880e0c330b5c5681294dc3fcb78a86d010a4e0ebb1992f0e48263f6188cb5f8e871cdcd7879f54fe7ad53bbd28d5e7ff70e73441836f0d11076bd7a791aceb05d501500f6878cf26e641fffa7c8fd143371000b3ad70bd80e52a82cd740ffbd4a080bd22523bc7ac2b1242169516d7aaf2753cd7ee5b500134ef32c02284e9d806fbeab2e055ea4a94be9cbfcfbc39b249b5e6b010c97d60c0f15b18c8fb2f36331ab0a1ce0efa13e9f2118c32140bd2118823d50f12deffc40b5d0c9642b4e44a6bd1cf4f38de471536a6610e698a942f049abef35010da2004619d8b31e33037ffed4afdd97459a241dfc7fa3bcc426f175461c938a182db560547dfcdd8ede345f0cc69da33fd588c30e912b7521c3ac1b0455882628000e81868d37eb16e1988451c26cfea8bb7969ce11c89488cedea30c80e3416dd2147c0554e9a9cce1a864eb0db625baa2cbb226ae2c2f1051f84b0a711c4bf69647010f02f18088ddbabd7c4528a1f7582f5fb11e60c5e434e9fd4ca2b33d6646e2ac6e6459c651778d1531711b44d2a1204a0d9c17e218aba5e60800e80aade9f1d90400108c783ad40f93184ad4f7e84229b207b17099e78b8bd93ddf2434cba21c99b4a904d74555ced9977e6becc34fa346c3cca9332b3598e66e58eb56f9ac700074e0001270a31d95bd5426ffe943dcc2b93f05b93f8301848f0b19c56e0dea51b7742c467b6bb557f6fc6762ef4600988c2dbcad0a2be84d4c6839fbae05d227e30ce5f50166cec2c600000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000493073601415557560000000000099e556100002710c0905b1576f0bb86fe861a51273f2bcc43d12dd702005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000005634a12c5d50000000096b3a0ebfffffff80000000066cec2c60000000066cec2c600000566c715d5a000000000895abaa20a83db6da7dfbe7cc34f56265123320d7765dda3ae132c1518c53ead6cde500c139f68a894f564d817c0dfaeefa80d4ed93d36b82f7fcfe80e4092bb54d4dae770124803c592f17cb918c9ac381ce82bd6817041aa5ae95d917d75687b7a389a188846dd79bd55cb6cb9b9d0e1c0c040f1110362a8e1e87c74887326d66b213d19f7dcd1766b6f8505be50f5c98783c07ec08f913cbe38c20a31e440e42bb5a8883356dd19288e618e938ae4e7031d52d684f7bd1ddcf0d4ff63844800e14ff0c6888ff26626ea9874005500ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace000000396f6987dd00000000052fbd87fffffff80000000066cec2c60000000066cec2c6000000398c4513280000000006c9a0a10a5307d6b780c8c5579b4b61de5fe0f12a789efdc628f14603df77ba31734c5611291df9a86e51430b243b3b61ee716bd758360783bdb7ef2f96ab8e92d509d85940a832b3de426d243a6d52ccf1e538af48b1bfad061dec1e4293898ca9ca9f37d0050d7b9e6a54357e77e7d79156fa1c70d54484ce52df49e79ab3fde203359f760fd9cf78be10644a43b52a171026829814590e8ba4853f6c8f0a16ce0fe3b532bcc96ea72723ab7d19f700c153e7cfb950f4aaa691e731e6f1de4edf43a6b9dd532a8ee785f084"; +export const HERMES_BTC_PRICE = 5924002645461; +export const HERMES_BTC_PUBLISH_TIME = 1724826310; +export const HERMES_ETH_PRICE = 246682322909; +export const HERMES_ETH_PUBLISH_TIME = 1724826310; + export const BTC_PRICE_FEED_ID = "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"; +export const ETH_PRICE_FEED_ID = + "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace"; + export const TEST_GUARDIAN_ADDRESS1 = "0x686b9ea8e3237110eaaba1f1b7467559a3273819";