[Sui 20/x]- refactor Pyth governance code path (#991)
* - refactor Pyth governance code path to not use wormhole::governance_message module - use our own custom WormholeVAAVerificationReceipt struct instead of DecreeReceipt * delete print * delete print * contract edits * add test vaa / test for set_update_fee * bring back set data sources test * use correct VAA for test set data sources * delete commented out code * write test for set stale price threshold * update pyth verify_vaa * simplify pyth::governance::verify_vaa * use sequence number for replay protection in both governance and contract upgrade code paths * only use sequence number for replay protection
This commit is contained in:
parent
ec63330cf0
commit
f79cfd8669
|
@ -11,6 +11,7 @@ module pyth::data_source {
|
|||
friend pyth::set_data_sources;
|
||||
friend pyth::pyth;
|
||||
friend pyth::set_governance_data_source;
|
||||
friend pyth::governance;
|
||||
#[test_only]
|
||||
friend pyth::pyth_tests;
|
||||
#[test_only]
|
||||
|
|
|
@ -14,12 +14,11 @@ module pyth::contract_upgrade {
|
|||
use wormhole::bytes32::{Self, Bytes32};
|
||||
use wormhole::bytes::{Self};
|
||||
use wormhole::cursor::{Self};
|
||||
use wormhole::governance_message::{Self, DecreeTicket, DecreeReceipt};
|
||||
|
||||
use pyth::state::{Self, State};
|
||||
use pyth::governance_witness::{GovernanceWitness, new_governance_witness};
|
||||
use pyth::governance_instruction::{Self};
|
||||
use pyth::governance_action::{Self};
|
||||
use pyth::governance::{Self, WormholeVAAVerificationReceipt};
|
||||
|
||||
friend pyth::migrate;
|
||||
|
||||
|
@ -27,6 +26,7 @@ module pyth::contract_upgrade {
|
|||
const E_DIGEST_ZERO_BYTES: u64 = 0;
|
||||
const E_GOVERNANCE_ACTION_MUST_BE_CONTRACT_UPGRADE: u64 = 1;
|
||||
const E_GOVERNANCE_CONTRACT_UPGRADE_CHAIN_ID_ZERO: u64 = 2;
|
||||
const E_CANNOT_EXECUTE_GOVERNANCE_ACTION_WITH_OBSOLETE_SEQUENCE_NUMBER: u64 = 3;
|
||||
|
||||
/// Specific governance payload ID (action) to complete upgrading the
|
||||
/// contract.
|
||||
|
@ -43,35 +43,27 @@ module pyth::contract_upgrade {
|
|||
digest: Bytes32
|
||||
}
|
||||
|
||||
public fun authorize_governance(
|
||||
pyth_state: &State
|
||||
): DecreeTicket<GovernanceWitness> {
|
||||
governance_message::authorize_verify_local(
|
||||
new_governance_witness(),
|
||||
state::governance_chain(pyth_state),
|
||||
state::governance_contract(pyth_state),
|
||||
state::governance_module(),
|
||||
CONTRACT_UPGRADE
|
||||
)
|
||||
}
|
||||
|
||||
/// Redeem governance VAA to issue an `UpgradeTicket` for the upgrade given
|
||||
/// a contract upgrade VAA. This governance message is only relevant for Sui
|
||||
/// because a contract upgrade is only relevant to one particular network
|
||||
/// (in this case Sui), whose build digest is encoded in this message.
|
||||
public fun authorize_upgrade(
|
||||
pyth_state: &mut State,
|
||||
receipt: DecreeReceipt<GovernanceWitness>
|
||||
receipt: WormholeVAAVerificationReceipt,
|
||||
): UpgradeTicket {
|
||||
|
||||
// Current package checking when consuming VAA hashes. This is because
|
||||
// upgrades are protected by the Sui VM, enforcing the latest package
|
||||
// is the one performing the upgrade.
|
||||
let consumed =
|
||||
state::borrow_mut_consumed_vaas_unchecked(pyth_state);
|
||||
// Get the sequence number of the governance VAA that was used to
|
||||
// generate the receipt.
|
||||
let sequence = governance::take_sequence(&receipt);
|
||||
|
||||
// And consume.
|
||||
let payload = governance_message::take_payload(consumed, receipt);
|
||||
// Require that new sequence number is greater than last executed sequence number.
|
||||
assert!(sequence > state::get_last_executed_governance_sequence(pyth_state),
|
||||
E_CANNOT_EXECUTE_GOVERNANCE_ACTION_WITH_OBSOLETE_SEQUENCE_NUMBER);
|
||||
|
||||
// Update latest executed sequence number to current one.
|
||||
state::set_last_executed_governance_sequence_unchecked(pyth_state, sequence);
|
||||
|
||||
let payload = governance::take_payload(&receipt);
|
||||
|
||||
let instruction = governance_instruction::from_byte_vec(payload);
|
||||
|
||||
|
@ -87,6 +79,8 @@ module pyth::contract_upgrade {
|
|||
// upgrade_payload contains a 32-byte digest
|
||||
let upgrade_payload = governance_instruction::destroy(instruction);
|
||||
|
||||
governance::destroy(receipt);
|
||||
|
||||
// Proceed with processing new implementation version.
|
||||
handle_upgrade_contract(pyth_state, upgrade_payload)
|
||||
}
|
||||
|
|
|
@ -7,26 +7,78 @@ module pyth::governance {
|
|||
use pyth::set_fee_recipient;
|
||||
use pyth::state::{Self, State};
|
||||
use pyth::set_update_fee;
|
||||
use pyth::governance_witness::{GovernanceWitness};
|
||||
|
||||
use wormhole::governance_message::{Self, DecreeReceipt};
|
||||
use wormhole::vaa::{Self, VAA};
|
||||
use wormhole::bytes32::Bytes32;
|
||||
|
||||
const E_INVALID_GOVERNANCE_ACTION: u64 = 0;
|
||||
const E_MUST_USE_CONTRACT_UPGRADE_MODULE_TO_DO_UPGRADES: u64 = 1;
|
||||
const E_CANNOT_EXECUTE_GOVERNANCE_ACTION_WITH_OBSOLETE_SEQUENCE_NUMBER: u64 = 2;
|
||||
const E_OLD_GUARDIAN_SET_GOVERNANCE: u64 = 3;
|
||||
const E_INVALID_GOVERNANCE_DATA_SOURCE: u64 = 4;
|
||||
|
||||
// this struct does not have the store or key ability so it must be
|
||||
// used in the same txn chain in which it is created
|
||||
struct WormholeVAAVerificationReceipt{
|
||||
payload: vector<u8>,
|
||||
digest: Bytes32,
|
||||
sequence: u64, // used for replay protection
|
||||
}
|
||||
|
||||
public fun take_payload(receipt: &WormholeVAAVerificationReceipt): vector<u8> {
|
||||
receipt.payload
|
||||
}
|
||||
|
||||
public fun take_digest(receipt: &WormholeVAAVerificationReceipt): Bytes32 {
|
||||
receipt.digest
|
||||
}
|
||||
|
||||
public fun take_sequence(receipt: &WormholeVAAVerificationReceipt): u64 {
|
||||
receipt.sequence
|
||||
}
|
||||
|
||||
public fun destroy(receipt: WormholeVAAVerificationReceipt) {
|
||||
let WormholeVAAVerificationReceipt{payload: _, digest: _, sequence: _} = receipt;
|
||||
}
|
||||
|
||||
// We define a custom verify_vaa function instead of using wormhole::governance_message::verify_vaa
|
||||
// because that function makes extra assumptions about the VAA payload headers. Pyth uses a
|
||||
// different header format compared to Wormhole, so
|
||||
public fun verify_vaa(
|
||||
pyth_state: &State,
|
||||
verified_vaa: VAA,
|
||||
): WormholeVAAVerificationReceipt {
|
||||
state::assert_latest_only(pyth_state);
|
||||
|
||||
let vaa_data_source = pyth::data_source::new((vaa::emitter_chain(&verified_vaa) as u64), vaa::emitter_address(&verified_vaa));
|
||||
|
||||
// The emitter chain and address must correspond to the Pyth governance emitter chain and contract.
|
||||
assert!(
|
||||
pyth::state::is_valid_governance_data_source(pyth_state, vaa_data_source),
|
||||
E_INVALID_GOVERNANCE_DATA_SOURCE
|
||||
);
|
||||
|
||||
let digest = vaa::digest(&verified_vaa);
|
||||
|
||||
let sequence = vaa::sequence(&verified_vaa);
|
||||
|
||||
let payload = vaa::take_payload(verified_vaa);
|
||||
|
||||
WormholeVAAVerificationReceipt { payload, digest, sequence }
|
||||
}
|
||||
|
||||
/// Execute a governance instruction other than contract upgrade, which is
|
||||
/// handled separately in the contract_upgrade.move module.
|
||||
public fun execute_governance_instruction(
|
||||
pyth_state : &mut State,
|
||||
receipt: DecreeReceipt<GovernanceWitness>,
|
||||
receipt: WormholeVAAVerificationReceipt,
|
||||
) {
|
||||
// This capability ensures that the current build version is used.
|
||||
let latest_only = state::assert_latest_only(pyth_state);
|
||||
|
||||
// Get the sequence number of the governance VAA that was used to
|
||||
// generate the receipt.
|
||||
let sequence = governance_message::sequence(&receipt);
|
||||
let sequence = receipt.sequence;
|
||||
|
||||
// Require that new sequence number is greater than last executed sequence number.
|
||||
assert!(sequence > state::get_last_executed_governance_sequence(pyth_state),
|
||||
|
@ -35,15 +87,9 @@ module pyth::governance {
|
|||
// Update latest executed sequence number to current one.
|
||||
state::set_last_executed_governance_sequence(&latest_only, pyth_state, sequence);
|
||||
|
||||
// governance_message::take_payload takes care of replay protection.
|
||||
let payload =
|
||||
governance_message::take_payload(
|
||||
state::borrow_mut_consumed_vaas(
|
||||
&latest_only,
|
||||
pyth_state
|
||||
),
|
||||
receipt
|
||||
);
|
||||
let payload = receipt.payload;
|
||||
|
||||
destroy(receipt);
|
||||
|
||||
let instruction = governance_instruction::from_byte_vec(payload);
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ module pyth::governance_instruction {
|
|||
target_chain_id : (target_chain_id as u64),
|
||||
payload
|
||||
};
|
||||
|
||||
// validate validates that module and target chain are correct
|
||||
validate(&instruction);
|
||||
|
||||
instruction
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
module pyth::governance_witness {
|
||||
|
||||
friend pyth::set_data_sources;
|
||||
friend pyth::set_stale_price_threshold;
|
||||
friend pyth::set_update_fee;
|
||||
friend pyth::set_governance_data_source;
|
||||
friend pyth::set_fee_recipient;
|
||||
friend pyth::contract_upgrade;
|
||||
|
||||
/// A hot potato that ensures that only DecreeTickets
|
||||
/// and DecreeReceipts associated with Sui Pyth governance
|
||||
/// are passed to execute_governance_instruction or
|
||||
/// execute_contract_upgrade_governance_instruction.
|
||||
///
|
||||
/// DecreeTickets and DecreeReceipts are Wormhole structs
|
||||
/// that are used in the VAA verification process.
|
||||
struct GovernanceWitness has drop {}
|
||||
|
||||
public(friend) fun new_governance_witness(): GovernanceWitness{
|
||||
GovernanceWitness{}
|
||||
}
|
||||
}
|
|
@ -4,13 +4,10 @@ module pyth::set_data_sources {
|
|||
use wormhole::cursor;
|
||||
use wormhole::external_address::{Self};
|
||||
use wormhole::bytes32::{Self};
|
||||
use wormhole::governance_message::{Self, DecreeTicket};
|
||||
|
||||
use pyth::deserialize;
|
||||
use pyth::data_source::{Self, DataSource};
|
||||
use pyth::state::{Self, State, LatestOnly};
|
||||
use pyth::governance_action::{Self};
|
||||
use pyth::governance_witness::{Self, GovernanceWitness};
|
||||
|
||||
friend pyth::governance;
|
||||
|
||||
|
@ -18,29 +15,6 @@ module pyth::set_data_sources {
|
|||
sources: vector<DataSource>,
|
||||
}
|
||||
|
||||
public fun authorize_governance(
|
||||
pyth_state: &State,
|
||||
global: bool
|
||||
): DecreeTicket<GovernanceWitness> {
|
||||
if (global) {
|
||||
governance_message::authorize_verify_global(
|
||||
governance_witness::new_governance_witness(),
|
||||
state::governance_chain(pyth_state),
|
||||
state::governance_contract(pyth_state),
|
||||
state::governance_module(),
|
||||
governance_action::get_value(governance_action::new_set_data_sources())
|
||||
)
|
||||
} else {
|
||||
governance_message::authorize_verify_local(
|
||||
governance_witness::new_governance_witness(),
|
||||
state::governance_chain(pyth_state),
|
||||
state::governance_contract(pyth_state),
|
||||
state::governance_module(),
|
||||
governance_action::get_value(governance_action::new_set_data_sources())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public(friend) fun execute(
|
||||
latest_only: &LatestOnly,
|
||||
state: &mut State,
|
||||
|
@ -78,16 +52,14 @@ module pyth::set_data_sources_tests {
|
|||
use sui::test_scenario::{Self};
|
||||
use sui::coin::Self;
|
||||
|
||||
use wormhole::governance_message::verify_vaa;
|
||||
use wormhole::external_address::{Self};
|
||||
use wormhole::bytes32::{Self};
|
||||
|
||||
use pyth::pyth_tests::{Self, setup_test, take_wormhole_and_pyth_states};
|
||||
use pyth::set_data_sources::{Self};
|
||||
use pyth::state::Self;
|
||||
use pyth::data_source::Self;
|
||||
|
||||
const SET_DATA_SOURCES_VAA: vector<u8> = x"01000000000100ac52663a7e50ab23db4f00f0607d930ffd438c5a214b3013418b57117590f76c32d2f790ec62be5f6e69d96273b1a567b8a698a8f5069c1ccd27a6874af2adc00100bc614e00000000000163278d271099bfd491951b3e648f08b1c71631e4a53674ad43e8f9f98068c38500000000000000010100000000000000000000000000000000000000000000000000000000000000010200155054474d01020015030001f346195ac02f37d60d4db8ffa6ef74cb1be3550047543a4a9ee9acf4d78697b0001aa27839d641b07743c0cb5f68c51f8cd31d2c0762bec00dc6fcd25433ef1ab5b6001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71";
|
||||
const SET_DATA_SOURCES_VAA: vector<u8> = x"01000000000100b29ee59868b9066b04d8d59e1c7cc66f0678eaf4c58b8c87e4405d6de615f64b04da4025719aeed349e03900f37829454d62cc7fc7bca80328c31fe40be7b21b010000000000000000000163278d271099bfd491951b3e648f08b1c71631e4a53674ad43e8f9f98068c3850000000000000001015054474d0102001503001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71001aa27839d641b07743c0cb5f68c51f8cd31d2c0762bec00dc6fcd25433ef1ab5b60001f346195ac02f37d60d4db8ffa6ef74cb1be3550047543a4a9ee9acf4d78697b0";
|
||||
// VAA Info:
|
||||
// module name: 0x1
|
||||
// action: 2
|
||||
|
@ -104,11 +76,9 @@ module pyth::set_data_sources_tests {
|
|||
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
||||
let (pyth_state, worm_state) = take_wormhole_and_pyth_states(&scenario);
|
||||
|
||||
let ticket = set_data_sources::authorize_governance(&pyth_state, false);
|
||||
|
||||
let verified_vaa = wormhole::vaa::parse_and_verify(&mut worm_state, SET_DATA_SOURCES_VAA, &clock);
|
||||
|
||||
let receipt = verify_vaa(&worm_state, verified_vaa, ticket);
|
||||
let receipt = pyth::governance::verify_vaa(&pyth_state, verified_vaa);
|
||||
|
||||
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
||||
|
||||
|
|
|
@ -3,11 +3,8 @@
|
|||
module pyth::set_fee_recipient {
|
||||
use wormhole::cursor;
|
||||
use wormhole::external_address::{Self};
|
||||
use wormhole::governance_message::{Self, DecreeTicket};
|
||||
|
||||
use pyth::state::{Self, State, LatestOnly};
|
||||
use pyth::governance_action::{Self};
|
||||
use pyth::governance_witness::{Self, GovernanceWitness};
|
||||
|
||||
friend pyth::governance;
|
||||
|
||||
|
@ -15,18 +12,6 @@ module pyth::set_fee_recipient {
|
|||
recipient: address
|
||||
}
|
||||
|
||||
public fun authorize_governance(
|
||||
pyth_state: &State
|
||||
): DecreeTicket<GovernanceWitness> {
|
||||
governance_message::authorize_verify_local(
|
||||
governance_witness::new_governance_witness(),
|
||||
state::governance_chain(pyth_state),
|
||||
state::governance_contract(pyth_state),
|
||||
state::governance_module(),
|
||||
governance_action::get_value(governance_action::new_set_fee_recipient())
|
||||
)
|
||||
}
|
||||
|
||||
public(friend) fun execute(latest_only: &LatestOnly, state: &mut State, payload: vector<u8>) {
|
||||
let PythFeeRecipient { recipient } = from_byte_vec(payload);
|
||||
state::set_fee_recipient(latest_only, state, recipient);
|
||||
|
|
|
@ -2,13 +2,10 @@ module pyth::set_governance_data_source {
|
|||
use pyth::deserialize;
|
||||
use pyth::data_source;
|
||||
use pyth::state::{Self, State, LatestOnly};
|
||||
use pyth::governance_action::{Self};
|
||||
use pyth::governance_witness::{Self, GovernanceWitness};
|
||||
|
||||
use wormhole::cursor;
|
||||
use wormhole::external_address::{Self, ExternalAddress};
|
||||
use wormhole::bytes32::{Self};
|
||||
use wormhole::governance_message::{Self, DecreeTicket};
|
||||
|
||||
friend pyth::governance;
|
||||
|
||||
|
@ -18,29 +15,6 @@ module pyth::set_governance_data_source {
|
|||
initial_sequence: u64,
|
||||
}
|
||||
|
||||
public fun authorize_governance(
|
||||
pyth_state: &State,
|
||||
global: bool
|
||||
): DecreeTicket<GovernanceWitness> {
|
||||
if (global){
|
||||
governance_message::authorize_verify_global(
|
||||
governance_witness::new_governance_witness(),
|
||||
state::governance_chain(pyth_state),
|
||||
state::governance_contract(pyth_state),
|
||||
state::governance_module(),
|
||||
governance_action::get_value(governance_action::new_set_governance_data_source())
|
||||
)
|
||||
} else {
|
||||
governance_message::authorize_verify_local(
|
||||
governance_witness::new_governance_witness(),
|
||||
state::governance_chain(pyth_state),
|
||||
state::governance_contract(pyth_state),
|
||||
state::governance_module(),
|
||||
governance_action::get_value(governance_action::new_set_governance_data_source())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public(friend) fun execute(latest_only: &LatestOnly, pyth_state: &mut State, payload: vector<u8>) {
|
||||
let GovernanceDataSource { emitter_chain_id, emitter_address, initial_sequence: initial_sequence } = from_byte_vec(payload);
|
||||
state::set_governance_data_source(latest_only, pyth_state, data_source::new(emitter_chain_id, emitter_address));
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
module pyth::set_stale_price_threshold {
|
||||
use wormhole::cursor;
|
||||
use wormhole::governance_message::{Self, DecreeTicket};
|
||||
|
||||
use pyth::deserialize;
|
||||
use pyth::state::{Self, State, LatestOnly};
|
||||
use pyth::governance_action::{Self};
|
||||
use pyth::governance_witness::{Self, GovernanceWitness};
|
||||
|
||||
friend pyth::governance;
|
||||
|
||||
|
@ -13,29 +10,6 @@ module pyth::set_stale_price_threshold {
|
|||
threshold: u64,
|
||||
}
|
||||
|
||||
public fun authorize_governance(
|
||||
pyth_state: &State,
|
||||
global: bool
|
||||
): DecreeTicket<GovernanceWitness> {
|
||||
if (global){
|
||||
governance_message::authorize_verify_global(
|
||||
governance_witness::new_governance_witness(),
|
||||
state::governance_chain(pyth_state),
|
||||
state::governance_contract(pyth_state),
|
||||
state::governance_module(),
|
||||
governance_action::get_value(governance_action::new_set_stale_price_threshold())
|
||||
)
|
||||
} else{
|
||||
governance_message::authorize_verify_local(
|
||||
governance_witness::new_governance_witness(),
|
||||
state::governance_chain(pyth_state),
|
||||
state::governance_contract(pyth_state),
|
||||
state::governance_module(),
|
||||
governance_action::get_value(governance_action::new_set_stale_price_threshold())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public(friend) fun execute(latest_only: &LatestOnly, state: &mut State, payload: vector<u8>) {
|
||||
let StalePriceThreshold { threshold } = from_byte_vec(payload);
|
||||
state::set_stale_price_threshold_secs(latest_only, state, threshold);
|
||||
|
@ -56,18 +30,15 @@ module pyth::set_stale_price_threshold_test {
|
|||
use sui::test_scenario::{Self};
|
||||
use sui::coin::Self;
|
||||
|
||||
use wormhole::governance_message::verify_vaa;
|
||||
|
||||
use pyth::pyth_tests::{Self, setup_test, take_wormhole_and_pyth_states};
|
||||
use pyth::set_stale_price_threshold::{Self};
|
||||
use pyth::state::Self;
|
||||
|
||||
const SET_STALE_PRICE_THRESHOLD_VAA: vector<u8> = x"01000000000100196a91724d472b6c160c44ddcc9f9cef531aa95442739300023048bd066b77ca1a02bbfd9ff1799f3d63a4dd10c5348ab3b231e3bb66232e0cb4c07daa3647090100bc614e00000000000163278d271099bfd491951b3e648f08b1c71631e4a53674ad43e8f9f98068c38500000000000000010100000000000000000000000000000000000000000000000000000000000000010400155054474d0104001500000000000aee23";
|
||||
const SET_STALE_PRICE_THRESHOLD_VAA: vector<u8> = x"010000000001000393eabdb4983e91e0fcfe7e6b2fc5c8fca2847fde52fd2f51a9b26b12298da13af09c271ce7723af8e0b1f52afa02b56f0b64764739b1b05e2f2c5cec80567c000000000000000000000163278d271099bfd491951b3e648f08b1c71631e4a53674ad43e8f9f98068c3850000000000000001015054474d0104001500000000000f4020";
|
||||
// VAA Info:
|
||||
// module name: 0x1
|
||||
// action: 4
|
||||
// chain: 21
|
||||
// stale price threshold: 716323
|
||||
// stale price threshold: 999456
|
||||
|
||||
const DEPLOYER: address = @0x1234;
|
||||
const DEFAULT_BASE_UPDATE_FEE: u64 = 0;
|
||||
|
@ -80,11 +51,9 @@ module pyth::set_stale_price_threshold_test {
|
|||
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
||||
let (pyth_state, worm_state) = take_wormhole_and_pyth_states(&scenario);
|
||||
|
||||
let ticket = set_stale_price_threshold::authorize_governance(&pyth_state, false);
|
||||
|
||||
let verified_vaa = wormhole::vaa::parse_and_verify(&mut worm_state, SET_STALE_PRICE_THRESHOLD_VAA, &clock);
|
||||
|
||||
let receipt = verify_vaa(&worm_state, verified_vaa, ticket);
|
||||
let receipt = pyth::governance::verify_vaa(&pyth_state, verified_vaa);
|
||||
|
||||
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
||||
|
||||
|
@ -93,7 +62,7 @@ module pyth::set_stale_price_threshold_test {
|
|||
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
||||
|
||||
// assert stale price threshold is set correctly
|
||||
assert!(state::get_stale_price_threshold_secs(&pyth_state)==716323, 0);
|
||||
assert!(state::get_stale_price_threshold_secs(&pyth_state)==999456, 0);
|
||||
|
||||
// clean up
|
||||
coin::burn_for_testing(test_coins);
|
||||
|
|
|
@ -2,12 +2,9 @@ module pyth::set_update_fee {
|
|||
use sui::math::{Self};
|
||||
|
||||
use wormhole::cursor;
|
||||
use wormhole::governance_message::{Self, DecreeTicket};
|
||||
|
||||
use pyth::deserialize;
|
||||
use pyth::state::{Self, State, LatestOnly};
|
||||
use pyth::governance_action::{Self};
|
||||
use pyth::governance_witness::{Self, GovernanceWitness};
|
||||
|
||||
friend pyth::governance;
|
||||
|
||||
|
@ -19,30 +16,6 @@ module pyth::set_update_fee {
|
|||
exponent: u64,
|
||||
}
|
||||
|
||||
public fun authorize_governance(
|
||||
pyth_state: &State,
|
||||
global: bool
|
||||
): DecreeTicket<GovernanceWitness> {
|
||||
if (global){
|
||||
governance_message::authorize_verify_global(
|
||||
governance_witness::new_governance_witness(),
|
||||
state::governance_chain(pyth_state),
|
||||
state::governance_contract(pyth_state),
|
||||
state::governance_module(),
|
||||
governance_action::get_value(governance_action::new_set_update_fee())
|
||||
)
|
||||
} else{
|
||||
governance_message::authorize_verify_local(
|
||||
governance_witness::new_governance_witness(),
|
||||
state::governance_chain(pyth_state),
|
||||
state::governance_contract(pyth_state),
|
||||
state::governance_module(),
|
||||
governance_action::get_value(governance_action::new_set_update_fee())
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public(friend) fun execute(latest_only: &LatestOnly, pyth_state: &mut State, payload: vector<u8>) {
|
||||
let UpdateFee { mantissa, exponent } = from_byte_vec(payload);
|
||||
assert!(exponent <= 255, E_EXPONENT_DOES_NOT_FIT_IN_U8);
|
||||
|
@ -71,35 +44,30 @@ module pyth::set_update_fee_tests {
|
|||
use sui::test_scenario::{Self};
|
||||
use sui::coin::Self;
|
||||
|
||||
use wormhole::governance_message::verify_vaa;
|
||||
|
||||
use pyth::pyth_tests::{Self, setup_test, take_wormhole_and_pyth_states};
|
||||
use pyth::set_update_fee::{Self};
|
||||
use pyth::state::Self;
|
||||
|
||||
const SET_FEE_VAA: vector<u8> = x"01000000000100e773bfd4a262ecd012333a953aadd243b8c116cc059b970ecb91216675eff89a39438570efb6eedcea15dad71d6ad0a18a7d01617e3cf61d53339df705a36df00100bc614e00000000000163278d271099bfd491951b3e648f08b1c71631e4a53674ad43e8f9f98068c38500000000000000010100000000000000000000000000000000000000000000000000000000000000010300155054474d0103001500000000000000030000000000000002";
|
||||
const SET_FEE_VAA: vector<u8> = x"01000000000100189d01616814b185b5a26bde6123d48e0d44dd490bbb3bde5d12076247b2180068a8261165777076ae532b7b0739aaee6411c8ba0695d20d4fa548227ce15d8d010000000000000000000163278d271099bfd491951b3e648f08b1c71631e4a53674ad43e8f9f98068c3850000000000000001015054474d0103001500000000000000050000000000000005";
|
||||
// VAA Info:
|
||||
// module name: 0x1
|
||||
// action: 3
|
||||
// chain: 21
|
||||
// new fee: 3, new exponent: 2
|
||||
// new fee: 5, new exponent: 5
|
||||
|
||||
const DEPLOYER: address = @0x1234;
|
||||
const DEFAULT_BASE_UPDATE_FEE: u64 = 0;
|
||||
const DEFAULT_COIN_TO_MINT: u64 = 0;
|
||||
|
||||
#[test]
|
||||
fun set_update_fee(){
|
||||
fun test_set_update_fee(){
|
||||
|
||||
let (scenario, test_coins, clock) = setup_test(500, 1, x"63278d271099bfd491951b3e648f08b1c71631e4a53674ad43e8f9f98068c385", pyth_tests::data_sources_for_test_vaa(), vector[x"13947bd48b18e53fdaeee77f3473391ac727c638"], DEFAULT_BASE_UPDATE_FEE, DEFAULT_COIN_TO_MINT);
|
||||
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
||||
let (pyth_state, worm_state) = take_wormhole_and_pyth_states(&scenario);
|
||||
|
||||
let ticket = set_update_fee::authorize_governance(&pyth_state, false);
|
||||
|
||||
let verified_vaa = wormhole::vaa::parse_and_verify(&mut worm_state, SET_FEE_VAA, &clock);
|
||||
|
||||
let receipt = verify_vaa(&worm_state, verified_vaa, ticket);
|
||||
let receipt = pyth::governance::verify_vaa(&pyth_state, verified_vaa);
|
||||
|
||||
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
||||
|
||||
|
@ -108,7 +76,7 @@ module pyth::set_update_fee_tests {
|
|||
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
||||
|
||||
// assert fee is set correctly
|
||||
assert!(state::get_base_update_fee(&pyth_state)==300, 0);
|
||||
assert!(state::get_base_update_fee(&pyth_state)==500000, 0);
|
||||
|
||||
// clean up
|
||||
coin::burn_for_testing(test_coins);
|
||||
|
|
|
@ -12,11 +12,10 @@
|
|||
/// their required minimum version.
|
||||
module pyth::migrate {
|
||||
use sui::object::{ID};
|
||||
use wormhole::governance_message::{Self, DecreeReceipt};
|
||||
|
||||
use pyth::state::{Self, State};
|
||||
use pyth::contract_upgrade::{Self};
|
||||
use pyth::governance_witness::{GovernanceWitness};
|
||||
use pyth::governance::{Self, WormholeVAAVerificationReceipt};
|
||||
|
||||
struct MigrateComplete has drop, copy {
|
||||
package: ID
|
||||
|
@ -24,7 +23,7 @@ module pyth::migrate {
|
|||
|
||||
public fun migrate(
|
||||
pyth_state: &mut State,
|
||||
receipt: DecreeReceipt<GovernanceWitness>
|
||||
receipt: WormholeVAAVerificationReceipt,
|
||||
) {
|
||||
|
||||
// Perform standard migrate.
|
||||
|
@ -51,7 +50,7 @@ module pyth::migrate {
|
|||
|
||||
fun handle_migrate(
|
||||
pyth_state: &mut State,
|
||||
receipt: DecreeReceipt<GovernanceWitness>
|
||||
receipt: WormholeVAAVerificationReceipt,
|
||||
) {
|
||||
// See `version_control` module for hard-coded configuration.
|
||||
state::migrate_version(pyth_state);
|
||||
|
@ -62,14 +61,15 @@ module pyth::migrate {
|
|||
// Check if build digest is the current one.
|
||||
let digest =
|
||||
contract_upgrade::take_digest(
|
||||
governance_message::payload(&receipt)
|
||||
governance::take_payload(&receipt)
|
||||
);
|
||||
state::assert_authorized_digest(
|
||||
&latest_only,
|
||||
pyth_state,
|
||||
digest
|
||||
);
|
||||
governance_message::destroy(receipt);
|
||||
|
||||
governance::destroy(receipt);
|
||||
|
||||
// Finally emit an event reflecting a successful migrate.
|
||||
let package = state::current_package(&latest_only, pyth_state);
|
||||
|
|
|
@ -36,12 +36,6 @@ module pyth::pyth {
|
|||
|
||||
#[test_only]
|
||||
friend pyth::pyth_tests;
|
||||
#[test_only]
|
||||
friend pyth::set_data_sources_tests;
|
||||
#[test_only]
|
||||
friend pyth::set_stale_price_threshold_test;
|
||||
#[test_only]
|
||||
friend pyth::set_update_fee_tests;
|
||||
|
||||
/// Init state and emit event corresponding to Pyth initialization.
|
||||
public entry fun init_pyth(
|
||||
|
@ -753,9 +747,9 @@ module pyth::pyth_tests{
|
|||
vector<DataSource>[
|
||||
data_source::new(
|
||||
1, external_address::new(bytes32::from_bytes(x"0000000000000000000000000000000000000000000000000000000000000004"))),
|
||||
data_source::new(
|
||||
data_source::new(
|
||||
5, external_address::new(bytes32::new(x"0000000000000000000000000000000000000000000000000000000000007637"))),
|
||||
data_source::new(
|
||||
data_source::new(
|
||||
17, external_address::new(bytes32::new(ACCUMULATOR_TESTS_EMITTER_ADDRESS)))
|
||||
]
|
||||
}
|
||||
|
|
|
@ -254,6 +254,13 @@ module pyth::state {
|
|||
s.last_executed_governance_sequence = sequence;
|
||||
}
|
||||
|
||||
// We have an unchecked version of set_last_executed_governance_sequence, because in the governance contract
|
||||
// upgrade code path, no LatestOnly is created (for example, see authorize_upgrade and commit_upgrade in
|
||||
// governance/contract_upgrade.move)
|
||||
public(friend) fun set_last_executed_governance_sequence_unchecked(s: &mut State, sequence: u64) {
|
||||
s.last_executed_governance_sequence = sequence;
|
||||
}
|
||||
|
||||
public(friend) fun set_base_update_fee(_: &LatestOnly, s: &mut State, fee: u64) {
|
||||
s.base_update_fee = fee;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue