Skip to content
Merged
5 changes: 1 addition & 4 deletions target_chains/ton/contracts/contracts/Main.fc
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
#include "imports/stdlib.fc";
#include "common/errors.fc";
#include "common/storage.fc";
#include "common/op.fc";
#include "Wormhole.fc";
#include "Pyth.fc";

;; Opcodes
const int OP_UPDATE_GUARDIAN_SET = 1;
const int OP_EXECUTE_GOVERNANCE_ACTION = 2;

;; Internal message handler
() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
if (in_msg_body.slice_empty?()) { ;; ignore empty messages
Expand Down
149 changes: 147 additions & 2 deletions target_chains/ton/contracts/contracts/Pyth.fc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "common/utils.fc";
#include "common/constants.fc";
#include "common/merkle_tree.fc";
#include "common/governance_actions.fc";
#include "./Wormhole.fc";

cell store_price(int price, int conf, int expo, int publish_time) {
Expand Down Expand Up @@ -59,7 +60,7 @@ slice read_and_verify_header(slice data) {
return (price, conf, expo, publish_time);
}

(int) get_update_fee(slice data) method_id {
int get_update_fee(slice data) method_id {
load_data();
slice cs = read_and_verify_header(data);
int wormhole_proof_size_bytes = cs~load_uint(16);
Expand All @@ -68,6 +69,11 @@ slice read_and_verify_header(slice data) {
return single_update_fee * num_updates;
}

int get_single_update_fee() method_id {
load_data();
return single_update_fee;
}

int get_governance_data_source_index() method_id {
load_data();
return governance_data_source_index;
Expand All @@ -83,6 +89,17 @@ int get_last_executed_governance_sequence() method_id {
return last_executed_governance_sequence;
}

int get_is_valid_data_source(cell data_source) method_id {
load_data();
int data_source_key = cell_hash(data_source);
(slice value, int found?) = is_valid_data_source.udict_get?(256, data_source_key);
if (found?) {
return value~load_int(1);
} else {
return 0;
}
}

(int, int, int, int) get_price_unsafe(int price_feed_id) method_id {
load_data();
(slice result, int success) = latest_price_feeds.udict_get?(256, price_feed_id);
Expand Down Expand Up @@ -203,6 +220,134 @@ int parse_pyth_payload_in_wormhole_vm(slice payload) impure {
store_data();
}

() execute_governance_action(slice in_msg_body) impure {
() verify_governance_vm(int emitter_chain_id, int emitter_address, int sequence) impure {
(int gov_chain_id, int gov_address) = parse_data_source(governance_data_source);
throw_unless(ERROR_INVALID_GOVERNANCE_DATA_SOURCE, emitter_chain_id == gov_chain_id);
throw_unless(ERROR_INVALID_GOVERNANCE_DATA_SOURCE, emitter_address == gov_address);
throw_if(ERROR_OLD_GOVERNANCE_MESSAGE, sequence <= last_executed_governance_sequence);
last_executed_governance_sequence = sequence;
}

(int, int, slice) parse_governance_instruction(slice payload) {
int magic = payload~load_uint(32);
throw_unless(ERROR_INVALID_GOVERNANCE_MAGIC, magic == GOVERNANCE_MAGIC);

int module = payload~load_uint(8);
throw_unless(ERROR_INVALID_GOVERNANCE_MODULE, module == GOVERNANCE_MODULE);

int action = payload~load_uint(8);

int target_chain_id = payload~load_uint(16);

return (target_chain_id, action, payload);
}

int apply_decimal_expo(int value, int expo) {
int result = value;
repeat (expo) {
result *= 10;
}
return result;
}

() execute_upgrade_contract(slice payload) impure {
;; TODO: Implement
}
Comment on lines +257 to 259
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will implement in a following PR


() execute_authorize_governance_data_source_transfer(slice payload) impure {
;; Verify the claim VAA
(_, _, _, _, int emitter_chain_id, int emitter_address, int sequence, _, slice claim_payload, _) = parse_and_verify_wormhole_vm(payload);

;; Parse the claim payload
(int target_chain_id, int action, slice claim_payload) = parse_governance_instruction(claim_payload);

;; Verify that this is a valid governance action for this chain
throw_if(ERROR_INVALID_GOVERNANCE_TARGET, (target_chain_id != 0) & (target_chain_id != chain_id));
throw_unless(ERROR_INVALID_GOVERNANCE_ACTION, action == REQUEST_GOVERNANCE_DATA_SOURCE_TRANSFER);

;; Extract the new governance data source index from the claim payload
int new_governance_data_source_index = claim_payload~load_uint(32);

;; Verify that the new index is greater than the current index
int current_index = governance_data_source_index;
throw_if(ERROR_OLD_GOVERNANCE_MESSAGE, new_governance_data_source_index <= current_index);

;; Update the governance data source
governance_data_source = begin_cell()
.store_uint(emitter_chain_id, 16)
.store_uint(emitter_address, 256)
.end_cell();

governance_data_source_index = new_governance_data_source_index;

;; Update the last executed governance sequence
last_executed_governance_sequence = sequence;
}

() execute_set_data_sources(slice payload) impure {
int num_sources = payload~load_uint(8);
cell new_data_sources = new_dict();

repeat(num_sources) {
(cell data_source, slice new_payload) = read_and_store_large_data(payload, 272); ;; 272 = 256 + 16
payload = new_payload;
slice data_source_slice = data_source.begin_parse();
int emitter_chain_id = data_source_slice~load_uint(16);
int emitter_address = data_source_slice~load_uint(256);
cell data_source = begin_cell()
.store_uint(emitter_chain_id, 16)
.store_uint(emitter_address, 256)
.end_cell();
int data_source_key = cell_hash(data_source);
new_data_sources~udict_set(256, data_source_key, begin_cell().store_int(true, 1).end_cell().begin_parse());
}

is_valid_data_source = new_data_sources;
}

() execute_set_fee(slice payload) impure {
int value = payload~load_uint(64);
int expo = payload~load_uint(64);
int new_fee = apply_decimal_expo(value, expo);
single_update_fee = new_fee;
}

() execute_set_valid_period(slice payload) impure {
;; TODO: Implement
}

() execute_governance_payload(int action, slice payload) impure {
if (action == UPGRADE_CONTRACT) {
execute_upgrade_contract(payload);
} elseif (action == AUTHORIZE_GOVERNANCE_DATA_SOURCE_TRANSFER) {
execute_authorize_governance_data_source_transfer(payload);
} elseif (action == SET_DATA_SOURCES) {
execute_set_data_sources(payload);
} elseif (action == SET_FEE) {
execute_set_fee(payload);
} elseif (action == SET_VALID_PERIOD) {
execute_set_valid_period(payload);
} elseif (action == REQUEST_GOVERNANCE_DATA_SOURCE_TRANSFER) {
;; RequestGovernanceDataSourceTransfer can only be part of
;; AuthorizeGovernanceDataSourceTransfer message
throw(ERROR_INVALID_GOVERNANCE_ACTION);
} else {
throw(ERROR_INVALID_GOVERNANCE_ACTION);
}
}

() execute_governance_action(slice in_msg_body) impure {
load_data();

(_, _, _, _, int emitter_chain_id, int emitter_address, int sequence, _, slice payload, _) = parse_and_verify_wormhole_vm(in_msg_body);

verify_governance_vm(emitter_chain_id, emitter_address, sequence);

(int target_chain_id, int action, slice payload) = parse_governance_instruction(payload);

throw_if(ERROR_INVALID_GOVERNANCE_TARGET, (target_chain_id != 0) & (target_chain_id != chain_id));

execute_governance_payload(action, payload);

store_data();
}
4 changes: 3 additions & 1 deletion target_chains/ton/contracts/contracts/common/constants.fc
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const int ACCUMULATOR_MAGIC = 0x504e4155; ;; "PNAU" (Pyth Network Accumulator Update)
const int ACCUMULATOR_WORMHOLE_MAGIC = 0x41555756; ;; Stands for AUWV (Accumulator Update Wormhole Verficiation)
const int ACCUMULATOR_WORMHOLE_MAGIC = 0x41555756; ;; "AUWV" (Accumulator Update Wormhole Verficiation)
const int GOVERNANCE_MAGIC = 0x5054474d; ;; "PTGM" (Pyth Governance Message)
const int GOVERNANCE_MODULE = 1;
const int MAJOR_VERSION = 1;
const int MINIMUM_ALLOWED_MINOR_VERSION = 0;

Expand Down
5 changes: 5 additions & 0 deletions target_chains/ton/contracts/contracts/common/errors.fc
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,8 @@ 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;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const int UPGRADE_CONTRACT = 0;
const int AUTHORIZE_GOVERNANCE_DATA_SOURCE_TRANSFER = 1;
const int SET_DATA_SOURCES = 2;
const int SET_FEE = 3;
const int SET_VALID_PERIOD = 4;
const int REQUEST_GOVERNANCE_DATA_SOURCE_TRANSFER = 5;
1 change: 1 addition & 0 deletions target_chains/ton/contracts/contracts/common/op.fc
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
const int OP_UPDATE_GUARDIAN_SET = 1;
const int OP_UPDATE_PRICE_FEEDS = 2;
const int OP_EXECUTE_GOVERNANCE_ACTION = 3;
10 changes: 10 additions & 0 deletions target_chains/ton/contracts/contracts/tests/PythTest.fc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
update_guardian_set(data.begin_parse());
} elseif (op == OP_UPDATE_PRICE_FEEDS) {
update_price_feeds(msg_value, data.begin_parse());
} elseif (op == OP_EXECUTE_GOVERNANCE_ACTION) {
execute_governance_action(data.begin_parse());
} else {
throw(0xffff); ;; Throw exception for unknown op
}
Expand All @@ -49,6 +51,10 @@
return get_update_fee(in_msg_body);
}

(int) test_get_single_update_fee() method_id {
return get_single_update_fee();
}

(int) test_get_chain_id() method_id {
return get_chain_id();
}
Expand All @@ -64,3 +70,7 @@
(cell) test_get_governance_data_source() method_id {
return get_governance_data_source();
}

(int) test_get_is_valid_data_source(cell data_source) method_id {
return get_is_valid_data_source(data_source);
}
Loading
Loading