diff --git a/target_chains/ton/contracts/contracts/Pyth.fc b/target_chains/ton/contracts/contracts/Pyth.fc index 69d9f39d67..7e538210d7 100644 --- a/target_chains/ton/contracts/contracts/Pyth.fc +++ b/target_chains/ton/contracts/contracts/Pyth.fc @@ -265,6 +265,9 @@ int apply_decimal_expo(int value, int expo) { ;; Set the code continuation to the new code set_c3(new_code.begin_parse().bless()); + ;; Reset the upgrade code hash + upgrade_code_hash = 0; + ;; Throw an exception to end the current execution ;; The contract will be restarted with the new code throw(0); diff --git a/target_chains/ton/contracts/contracts/Wormhole.fc b/target_chains/ton/contracts/contracts/Wormhole.fc index e0b822b1a4..5978e51192 100644 --- a/target_chains/ton/contracts/contracts/Wormhole.fc +++ b/target_chains/ton/contracts/contracts/Wormhole.fc @@ -86,6 +86,7 @@ int governance_action_is_consumed(int hash) method_id { () verify_signatures(int hash, cell signatures, int signers_length, cell guardian_set_keys, int guardian_set_size) impure { slice cs = signatures.begin_parse(); int i = 0; + int last_signature_index = -1; int valid_signatures = 0; while (i < signers_length) { @@ -105,6 +106,7 @@ int governance_action_is_consumed(int hash) method_id { slice sig_slice = sig_builder.end_cell().begin_parse(); int guardian_index = sig_slice~load_uint(8); + throw_if(ERROR_SIGNATURE_INDEX_NOT_INCREASING, guardian_index <= last_signature_index); int r = sig_slice~load_uint(256); int s = sig_slice~load_uint(256); int v = sig_slice~load_uint(8); @@ -115,6 +117,7 @@ int governance_action_is_consumed(int hash) method_id { int guardian_address = guardian_key~load_uint(160); throw_unless(ERROR_INVALID_GUARDIAN_ADDRESS, parsed_address == guardian_address); valid_signatures += 1; + last_signature_index = guardian_index; i += 1; } @@ -198,6 +201,8 @@ int governance_action_is_consumed(int hash) method_id { throw_unless(ERROR_NEW_GUARDIAN_SET_INDEX_IS_INVALID, new_guardian_set_index == (current_guardian_set_index + 1)); int guardian_length = payload~load_uint(8); + throw_unless(ERROR_INVALID_GUARDIAN_SET_KEYS_LENGTH, guardian_length > 0); + cell new_guardian_set_keys = new_dict(); int key_count = 0; while (key_count < guardian_length) { diff --git a/target_chains/ton/contracts/contracts/common/errors.fc b/target_chains/ton/contracts/contracts/common/errors.fc index 11cb56e67b..514928f8ac 100644 --- a/target_chains/ton/contracts/contracts/common/errors.fc +++ b/target_chains/ton/contracts/contracts/common/errors.fc @@ -20,27 +20,28 @@ const int ERROR_INVALID_GUARDIAN_SET_UPGRADE_LENGTH = 1015; const int ERROR_INVALID_GOVERNANCE_CHAIN = 1016; const int ERROR_INVALID_GOVERNANCE_CONTRACT = 1017; const int ERROR_INVALID_GUARDIAN_ADDRESS = 1018; +const int ERROR_SIGNATURE_INDEX_NOT_INCREASING = 1019; ;; Pyth -const int ERROR_PRICE_FEED_NOT_FOUND = 1019; -const int ERROR_OUTDATED_PRICE = 1020; -const int ERROR_INVALID_MAGIC = 1021; -const int ERROR_INVALID_MAJOR_VERSION = 1022; -const int ERROR_INVALID_MINOR_VERSION = 1023; -const int ERROR_UPDATE_DATA_SOURCE_NOT_FOUND = 1024; -const int ERROR_INVALID_UPDATE_DATA_SOURCE = 1025; -const int ERROR_DIGEST_MISMATCH = 1026; -const int ERROR_INVALID_UPDATE_DATA_LENGTH = 1027; -const int ERROR_INVALID_UPDATE_DATA_TYPE = 1028; -const int ERROR_INVALID_MESSAGE_TYPE = 1029; -const int ERROR_INSUFFICIENT_FEE = 1030; -const int ERROR_INVALID_PROOF_SIZE = 1031; -const int ERROR_INVALID_GOVERNANCE_DATA_SOURCE = 1032; -const int ERROR_OLD_GOVERNANCE_MESSAGE = 1033; -const int ERROR_INVALID_GOVERNANCE_TARGET = 1034; -const int ERROR_INVALID_GOVERNANCE_MAGIC = 1035; -const int ERROR_INVALID_GOVERNANCE_MODULE = 1036; -const int ERROR_INVALID_CODE_HASH = 1037; +const int ERROR_PRICE_FEED_NOT_FOUND = 2000; +const int ERROR_OUTDATED_PRICE = 2001; +const int ERROR_INVALID_MAGIC = 2002; +const int ERROR_INVALID_MAJOR_VERSION = 2003; +const int ERROR_INVALID_MINOR_VERSION = 2004; +const int ERROR_UPDATE_DATA_SOURCE_NOT_FOUND = 2005; +const int ERROR_INVALID_UPDATE_DATA_SOURCE = 2006; +const int ERROR_DIGEST_MISMATCH = 2007; +const int ERROR_INVALID_UPDATE_DATA_LENGTH = 2008; +const int ERROR_INVALID_UPDATE_DATA_TYPE = 2009; +const int ERROR_INVALID_MESSAGE_TYPE = 2010; +const int ERROR_INSUFFICIENT_FEE = 2011; +const int ERROR_INVALID_PROOF_SIZE = 2012; +const int ERROR_INVALID_GOVERNANCE_DATA_SOURCE = 2013; +const int ERROR_OLD_GOVERNANCE_MESSAGE = 2014; +const int ERROR_INVALID_GOVERNANCE_TARGET = 2015; +const int ERROR_INVALID_GOVERNANCE_MAGIC = 2016; +const int ERROR_INVALID_GOVERNANCE_MODULE = 2017; +const int ERROR_INVALID_CODE_HASH = 2018; ;; Common -const int ERROR_INSUFFICIENT_GAS = 1038; +const int ERROR_INSUFFICIENT_GAS = 3000; diff --git a/target_chains/ton/contracts/tests/PythTest.spec.ts b/target_chains/ton/contracts/tests/PythTest.spec.ts index 00cf001389..689799797d 100644 --- a/target_chains/ton/contracts/tests/PythTest.spec.ts +++ b/target_chains/ton/contracts/tests/PythTest.spec.ts @@ -181,7 +181,7 @@ describe("PythTest", () => { 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 + ).rejects.toThrow("Unable to execute get method. Got exit_code: 2001"); // ERROR_OUTDATED_PRICE = 2001 }); it("should correctly get ema price no older than", async () => { @@ -210,7 +210,7 @@ describe("PythTest", () => { await expect( pythTest.getEmaPriceNoOlderThan(TIME_PERIOD, BTC_PRICE_FEED_ID) - ).rejects.toThrow("Unable to execute get method. Got exit_code: 1020"); // ERROR_OUTDATED_PRICE = 1020 + ).rejects.toThrow("Unable to execute get method. Got exit_code: 2001"); // ERROR_OUTDATED_PRICE = 2001 }); it("should correctly get ema price unsafe", async () => { @@ -245,8 +245,8 @@ describe("PythTest", () => { 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 + "Unable to execute get method. Got exit_code: 2000" + ); // ERROR_PRICE_FEED_NOT_FOUND = 2000 const updateData = Buffer.from(HERMES_BTC_ETH_UPDATE, "hex"); const updateFee = await pythTest.getUpdateFee(updateData); @@ -280,8 +280,8 @@ describe("PythTest", () => { const invalidUpdateData = Buffer.from("invalid data"); await expect(pythTest.getUpdateFee(invalidUpdateData)).rejects.toThrow( - "Unable to execute get method. Got exit_code: 1021" - ); // ERROR_INVALID_MAGIC = 1021 + "Unable to execute get method. Got exit_code: 2002" + ); // ERROR_INVALID_MAGIC = 2002 }); it("should fail to update price feeds with invalid data", async () => { @@ -303,7 +303,7 @@ describe("PythTest", () => { from: deployer.address, to: pythTest.address, success: false, - exitCode: 1021, // ERROR_INVALID_MAGIC + exitCode: 2002, // ERROR_INVALID_MAGIC }); }); @@ -352,7 +352,7 @@ describe("PythTest", () => { from: deployer.address, to: pythTest.address, success: false, - exitCode: 1024, // ERROR_UPDATE_DATA_SOURCE_NOT_FOUND + exitCode: 2005, // ERROR_UPDATE_DATA_SOURCE_NOT_FOUND }); }); @@ -368,7 +368,7 @@ describe("PythTest", () => { 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 + ).rejects.toThrow("Unable to execute get method. Got exit_code: 2001"); // ERROR_OUTDATED_PRICE = 2001 }); it("should fail to update price feeds with insufficient gas", async () => { @@ -387,7 +387,7 @@ describe("PythTest", () => { from: deployer.address, to: pythTest.address, success: false, - exitCode: 1038, // ERROR_INSUFFICIENT_GAS + exitCode: 3000, // ERROR_INSUFFICIENT_GAS }); }); @@ -413,7 +413,7 @@ describe("PythTest", () => { from: deployer.address, to: pythTest.address, success: false, - exitCode: 1030, // ERROR_INSUFFICIENT_FEE = 1030 + exitCode: 2011, // ERROR_INSUFFICIENT_FEE = 2011 }); }); @@ -425,15 +425,15 @@ describe("PythTest", () => { await expect( pythTest.getPriceUnsafe(nonExistentPriceFeedId) - ).rejects.toThrow("Unable to execute get method. Got exit_code: 1019"); // ERROR_PRICE_FEED_NOT_FOUND = 1019 + ).rejects.toThrow("Unable to execute get method. Got exit_code: 2000"); // ERROR_PRICE_FEED_NOT_FOUND = 2000 await expect( pythTest.getPriceNoOlderThan(TIME_PERIOD, nonExistentPriceFeedId) - ).rejects.toThrow("Unable to execute get method. Got exit_code: 1019"); // ERROR_PRICE_FEED_NOT_FOUND + ).rejects.toThrow("Unable to execute get method. Got exit_code: 2000"); // 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 + ).rejects.toThrow("Unable to execute get method. Got exit_code: 2000"); // ERROR_PRICE_FEED_NOT_FOUND }); it("should correctly get chain ID", async () => { @@ -735,7 +735,7 @@ describe("PythTest", () => { from: deployer.address, to: pythTest.address, success: false, - exitCode: 1012, // ERROR_INVALID_GOVERNANCE_ACTION = 1012 + exitCode: 1012, // ERROR_INVALID_GOVERNANCE_ACTION }); // Verify that the governance data source index hasn't changed @@ -773,7 +773,7 @@ describe("PythTest", () => { from: deployer.address, to: pythTest.address, success: false, - exitCode: 1032, // ERROR_INVALID_GOVERNANCE_DATA_SOURCE + exitCode: 2013, // ERROR_INVALID_GOVERNANCE_DATA_SOURCE }); }); @@ -809,7 +809,7 @@ describe("PythTest", () => { from: deployer.address, to: pythTest.address, success: false, - exitCode: 1033, // ERROR_OLD_GOVERNANCE_MESSAGE + exitCode: 2014, // ERROR_OLD_GOVERNANCE_MESSAGE }); }); @@ -839,7 +839,7 @@ describe("PythTest", () => { from: deployer.address, to: pythTest.address, success: false, - exitCode: 1034, // ERROR_INVALID_GOVERNANCE_TARGET + exitCode: 2015, // ERROR_INVALID_GOVERNANCE_TARGET }); }); @@ -976,7 +976,7 @@ describe("PythTest", () => { from: deployer.address, to: pythTest.address, success: false, - exitCode: 1037, // ERROR_INVALID_CODE_HASH + exitCode: 2018, // ERROR_INVALID_CODE_HASH }); // Verify that the contract has not been upgraded by attempting to call the new method