Parcourir la source

fix(target_chains/ton): fix ton contract checks (#2073)

* fix ton contract

* make sure guardian set is not empty

* precommit
Daniel Chew il y a 1 an
Parent
commit
c720bf1afb

+ 3 - 0
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);

+ 5 - 0
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) {

+ 21 - 20
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;

+ 19 - 19
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