|
|
@@ -15,6 +15,7 @@ module pyth::pyth {
|
|
|
use pyth::price_feed::{Self};
|
|
|
use pyth::price::{Self, Price};
|
|
|
use pyth::price_identifier::{PriceIdentifier};
|
|
|
+ use pyth::version_control::{UpdatePriceFeeds, CreatePriceFeeds};
|
|
|
|
|
|
use wormhole::external_address::{Self};
|
|
|
use wormhole::vaa::{Self};
|
|
|
@@ -93,6 +94,8 @@ module pyth::pyth {
|
|
|
clock: &Clock,
|
|
|
ctx: &mut TxContext
|
|
|
){
|
|
|
+ // Version control.
|
|
|
+ state::check_minimum_requirement<CreatePriceFeeds>(pyth_state);
|
|
|
while (!vector::is_empty(&vaas)) {
|
|
|
let vaa = vector::pop_back(&mut vaas);
|
|
|
|
|
|
@@ -137,8 +140,8 @@ module pyth::pyth {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
- /// Update PriceInfo objects and corresponding price feeds with the
|
|
|
- /// data in the given VAAs.
|
|
|
+ /// Update Pyth Price Info objects (containing price feeds) with the
|
|
|
+ /// price data in the given VAAs.
|
|
|
///
|
|
|
/// The vaas argument is a vector of VAAs encoded as bytes.
|
|
|
///
|
|
|
@@ -158,6 +161,8 @@ module pyth::pyth {
|
|
|
fee: Coin<SUI>,
|
|
|
clock: &Clock
|
|
|
){
|
|
|
+ // Version control.
|
|
|
+ state::check_minimum_requirement<UpdatePriceFeeds>(pyth_state);
|
|
|
// Charge the message update fee
|
|
|
assert!(get_total_update_fee(pyth_state, &vaas) <= coin::value(&fee), E_INSUFFICIENT_FEE);
|
|
|
|
|
|
@@ -176,9 +181,11 @@ module pyth::pyth {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
- /// Precondition: A Sui object of type PriceInfoObject must exist for each update
|
|
|
+ /// Make sure that a Sui object of type PriceInfoObject exists for each update
|
|
|
/// encoded in the worm_vaa (batch_attestation_vaa). These should be passed in
|
|
|
- /// via the price_info_objects argument.
|
|
|
+ /// via the price_info_objects argument. If for any price feed update, a
|
|
|
+ /// a PriceInfoObject with a matching price identifier is not found, the update_cache
|
|
|
+ /// function will revert, causing this function to revert.
|
|
|
fun update_price_feed_from_single_vaa(
|
|
|
worm_state: &WormState,
|
|
|
pyth_state: &PythState,
|
|
|
@@ -216,10 +223,9 @@ module pyth::pyth {
|
|
|
let update = vector::pop_back(&mut updates);
|
|
|
let i = 0;
|
|
|
let found = false;
|
|
|
- // Find PriceInfoObjects corresponding to the current update (PriceInfo).
|
|
|
- // TODO - Construct an in-memory table to make look-ups faster?
|
|
|
- // This loop might be expensive if there are a large number
|
|
|
- // of updates and/or price_info_objects we are updating.
|
|
|
+ // Note - Would it be worth it to construct an in-memory hash-map to make look-ups faster?
|
|
|
+ // This loop might be expensive if there are a large number of price_info_objects
|
|
|
+ // passed in.
|
|
|
while (i < vector::length<PriceInfoObject>(price_info_objects) && found == false){
|
|
|
// Check if the current price info object corresponds to the price feed that
|
|
|
// the update is meant for.
|
|
|
@@ -386,10 +392,10 @@ module pyth::pyth_tests{
|
|
|
|
|
|
use sui::sui::SUI;
|
|
|
use sui::coin::{Self, Coin};
|
|
|
- use sui::clock::{Self, Clock};
|
|
|
use sui::test_scenario::{Self, Scenario, ctx, take_shared, return_shared};
|
|
|
use sui::package::Self;
|
|
|
use sui::object::{Self, ID};
|
|
|
+ use sui::clock::{Self, Clock};
|
|
|
|
|
|
use pyth::state::{Self, State as PythState};
|
|
|
use pyth::price_identifier::{Self};
|
|
|
@@ -426,7 +432,7 @@ module pyth::pyth_tests{
|
|
|
data_sources: vector<DataSource>,
|
|
|
base_update_fee: u64,
|
|
|
to_mint: u64
|
|
|
- ): (Scenario, Coin<SUI>) {
|
|
|
+ ): (Scenario, Coin<SUI>, Clock) {
|
|
|
|
|
|
let scenario = test_scenario::begin(DEPLOYER);
|
|
|
|
|
|
@@ -470,9 +476,6 @@ module pyth::pyth_tests{
|
|
|
test_scenario::ctx(&mut scenario)
|
|
|
);
|
|
|
|
|
|
- // Create and share a global clock object for timekeeping.
|
|
|
- clock::create_for_testing(ctx(&mut scenario));
|
|
|
-
|
|
|
// Initialize Pyth state.
|
|
|
let pyth_upgrade_cap=
|
|
|
package::test_publish(
|
|
|
@@ -498,7 +501,8 @@ module pyth::pyth_tests{
|
|
|
);
|
|
|
|
|
|
let coins = coin::mint_for_testing<SUI>(to_mint, ctx(&mut scenario));
|
|
|
- (scenario, coins)
|
|
|
+ let clock = clock::create_for_testing(ctx(&mut scenario));
|
|
|
+ (scenario, coins, clock)
|
|
|
}
|
|
|
|
|
|
#[test_only]
|
|
|
@@ -571,7 +575,7 @@ module pyth::pyth_tests{
|
|
|
#[test]
|
|
|
fun test_get_update_fee() {
|
|
|
let single_update_fee = 50;
|
|
|
- let (scenario, test_coins) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", vector[], single_update_fee, 0);
|
|
|
+ let (scenario, test_coins, _clock) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", vector[], single_update_fee, 0);
|
|
|
test_scenario::next_tx(&mut scenario, DEPLOYER, );
|
|
|
let pyth_state = take_shared<PythState>(&scenario);
|
|
|
// Pass in a single VAA
|
|
|
@@ -590,17 +594,17 @@ module pyth::pyth_tests{
|
|
|
|
|
|
return_shared(pyth_state);
|
|
|
coin::burn_for_testing<SUI>(test_coins);
|
|
|
+ clock::destroy_for_testing(_clock);
|
|
|
test_scenario::end(scenario);
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
#[expected_failure(abort_code = wormhole::vaa::E_WRONG_VERSION)]
|
|
|
fun test_create_price_feeds_corrupt_vaa() {
|
|
|
- let (scenario, test_coins) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", vector[], 50, 0);
|
|
|
+ let (scenario, test_coins, clock) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", vector[], 50, 0);
|
|
|
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
|
|
let pyth_state = take_shared<PythState>(&scenario);
|
|
|
let worm_state = take_shared<WormState>(&scenario);
|
|
|
- let clock = take_shared<Clock>(&scenario);
|
|
|
|
|
|
// Pass in a corrupt VAA, which should fail deseriaizing
|
|
|
let corrupt_vaa = x"90F8bf6A479f320ead074411a4B0e7944Ea8c9C1";
|
|
|
@@ -616,7 +620,7 @@ module pyth::pyth_tests{
|
|
|
|
|
|
return_shared(pyth_state);
|
|
|
return_shared(worm_state);
|
|
|
- return_shared(clock);
|
|
|
+ clock::destroy_for_testing(clock);
|
|
|
coin::burn_for_testing<SUI>(test_coins);
|
|
|
test_scenario::end(scenario);
|
|
|
}
|
|
|
@@ -634,12 +638,11 @@ module pyth::pyth_tests{
|
|
|
)
|
|
|
];
|
|
|
|
|
|
- let (scenario, test_coins) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, 50, 0);
|
|
|
+ let (scenario, test_coins, clock) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, 50, 0);
|
|
|
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
|
|
|
|
|
let pyth_state = take_shared<PythState>(&scenario);
|
|
|
let worm_state = take_shared<WormState>(&scenario);
|
|
|
- let clock = take_shared<Clock>(&scenario);
|
|
|
|
|
|
pyth::create_price_feeds(
|
|
|
&mut worm_state,
|
|
|
@@ -651,7 +654,7 @@ module pyth::pyth_tests{
|
|
|
|
|
|
return_shared(pyth_state);
|
|
|
return_shared(worm_state);
|
|
|
- return_shared(clock);
|
|
|
+ clock::destroy_for_testing(clock);
|
|
|
coin::burn_for_testing<SUI>(test_coins);
|
|
|
test_scenario::end(scenario);
|
|
|
}
|
|
|
@@ -675,12 +678,11 @@ module pyth::pyth_tests{
|
|
|
let base_update_fee = 50;
|
|
|
let coins_to_mint = 5000;
|
|
|
|
|
|
- let (scenario, test_coins) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, base_update_fee, coins_to_mint);
|
|
|
+ let (scenario, test_coins, clock) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, base_update_fee, coins_to_mint);
|
|
|
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
|
|
|
|
|
let pyth_state = take_shared<PythState>(&scenario);
|
|
|
let worm_state = take_shared<WormState>(&scenario);
|
|
|
- let clock = take_shared<Clock>(&scenario);
|
|
|
|
|
|
pyth::create_price_feeds(
|
|
|
&mut worm_state,
|
|
|
@@ -730,7 +732,7 @@ module pyth::pyth_tests{
|
|
|
return_shared(price_info_object_3);
|
|
|
return_shared(price_info_object_4);
|
|
|
|
|
|
- return_shared(clock);
|
|
|
+ clock::destroy_for_testing(clock);
|
|
|
test_scenario::end(scenario);
|
|
|
}
|
|
|
|
|
|
@@ -741,12 +743,11 @@ module pyth::pyth_tests{
|
|
|
let base_update_fee = 50;
|
|
|
let coins_to_mint = 5000;
|
|
|
|
|
|
- let (scenario, test_coins) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, base_update_fee, coins_to_mint);
|
|
|
+ let (scenario, test_coins, clock) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, base_update_fee, coins_to_mint);
|
|
|
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
|
|
|
|
|
let pyth_state = take_shared<PythState>(&scenario);
|
|
|
let worm_state = take_shared<WormState>(&scenario);
|
|
|
- let clock = take_shared<Clock>(&scenario);
|
|
|
|
|
|
pyth::create_price_feeds(
|
|
|
&mut worm_state,
|
|
|
@@ -805,12 +806,11 @@ module pyth::pyth_tests{
|
|
|
let base_update_fee = 50;
|
|
|
let coins_to_mint = 5;
|
|
|
|
|
|
- let (scenario, test_coins) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, base_update_fee, coins_to_mint);
|
|
|
+ let (scenario, test_coins, clock) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, base_update_fee, coins_to_mint);
|
|
|
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
|
|
|
|
|
let pyth_state = take_shared<PythState>(&scenario);
|
|
|
let worm_state = take_shared<WormState>(&scenario);
|
|
|
- let clock = take_shared<Clock>(&scenario);
|
|
|
|
|
|
pyth::create_price_feeds(
|
|
|
&mut worm_state,
|
|
|
@@ -849,13 +849,13 @@ module pyth::pyth_tests{
|
|
|
let base_update_fee = 50;
|
|
|
let coins_to_mint = 5000;
|
|
|
|
|
|
- let (scenario, test_coins) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, base_update_fee, coins_to_mint);
|
|
|
+ let (scenario, test_coins, clock) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, base_update_fee, coins_to_mint);
|
|
|
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
|
|
|
|
|
let pyth_state = take_shared<PythState>(&scenario);
|
|
|
let worm_state = take_shared<WormState>(&scenario);
|
|
|
- let clock = take_shared<Clock>(&scenario);
|
|
|
|
|
|
+ // Update cache is called by create_price_feeds.
|
|
|
pyth::create_price_feeds(
|
|
|
&mut worm_state,
|
|
|
&mut pyth_state,
|
|
|
@@ -898,7 +898,7 @@ module pyth::pyth_tests{
|
|
|
return_shared(price_info_object_4);
|
|
|
coin::burn_for_testing<SUI>(test_coins);
|
|
|
|
|
|
- return_shared(clock);
|
|
|
+ clock::destroy_for_testing(clock);
|
|
|
test_scenario::end(scenario);
|
|
|
}
|
|
|
|
|
|
@@ -908,12 +908,11 @@ module pyth::pyth_tests{
|
|
|
let base_update_fee = 50;
|
|
|
let coins_to_mint = 5000;
|
|
|
|
|
|
- let (scenario, test_coins) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, base_update_fee, coins_to_mint);
|
|
|
+ let (scenario, test_coins, clock) = setup_test(500, 23, x"5d1f252d5de865279b00c84bce362774c2804294ed53299bc4a0389a5defef92", data_sources, base_update_fee, coins_to_mint);
|
|
|
test_scenario::next_tx(&mut scenario, DEPLOYER);
|
|
|
|
|
|
let pyth_state = take_shared<PythState>(&scenario);
|
|
|
let worm_state = take_shared<WormState>(&scenario);
|
|
|
- let clock = take_shared<Clock>(&scenario);
|
|
|
|
|
|
pyth::create_price_feeds(
|
|
|
&mut worm_state,
|
|
|
@@ -964,8 +963,7 @@ module pyth::pyth_tests{
|
|
|
price_info_object_1 = vector::pop_back(&mut price_info_object_vec);
|
|
|
|
|
|
vector::destroy_empty(price_info_object_vec);
|
|
|
-
|
|
|
- // Confirm that the current price and ema price didn't change
|
|
|
+
|
|
|
let current_price_info = price_info::get_price_info_from_price_info_object(&price_info_object_1);
|
|
|
let current_price_feed = price_info::get_price_feed(¤t_price_info);
|
|
|
let current_price = price_feed::get_price(current_price_feed);
|
|
|
@@ -1007,7 +1005,7 @@ module pyth::pyth_tests{
|
|
|
|
|
|
vector::destroy_empty(price_info_object_vec);
|
|
|
|
|
|
- // Confirm that the Pyth cached price got updated to fresh_price
|
|
|
+ // Confirm that the Pyth cached price got updated to fresh_price.
|
|
|
let current_price_info = price_info::get_price_info_from_price_info_object(&price_info_object_1);
|
|
|
let current_price_feed = price_info::get_price_feed(¤t_price_info);
|
|
|
let current_price = price_feed::get_price(current_price_feed);
|
|
|
@@ -1024,7 +1022,7 @@ module pyth::pyth_tests{
|
|
|
return_shared(price_info_object_4);
|
|
|
coin::burn_for_testing<SUI>(test_coins);
|
|
|
|
|
|
- return_shared(clock);
|
|
|
+ clock::destroy_for_testing(clock);
|
|
|
test_scenario::end(scenario);
|
|
|
}
|
|
|
}
|