Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unified syntax migration #114

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 22 additions & 86 deletions contracts/price-aggregator/tests/price_aggregator_blackbox_test.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use multiversx_price_aggregator_sc::{
price_aggregator_data::{OracleStatus, TimestampedPrice, TokenPair},
ContractObj, PriceAggregator, MAX_ROUND_DURATION_SECONDS,
PriceAggregator, MAX_ROUND_DURATION_SECONDS,
};

use multiversx_sc_scenario::imports::*;

mod price_aggregator_proxy;

const DECIMALS: u8 = 0;
const EGLD_TICKER: &[u8] = b"EGLD";
const NR_ORACLES: usize = 4;
Expand All @@ -15,68 +12,45 @@ const SLASH_QUORUM: usize = 3;
const STAKE_AMOUNT: u64 = 20;
const SUBMISSION_COUNT: usize = 3;
const USD_TICKER: &[u8] = b"USDC";

const PRICE_AGGREGATOR_ADDRESS: TestSCAddress = TestSCAddress::new("price-aggregator");
const OWNER_ADDRESS: TestAddress = TestAddress::new("owner");
const PRICE_AGGREGATOR_PATH: MxscPath =
MxscPath::new("output/multiversx-price-aggregator-sc.mxsc.json");

fn world() -> ScenarioWorld {
let mut blockchain = ScenarioWorld::new();

blockchain.register_contract(
PRICE_AGGREGATOR_PATH,
multiversx_price_aggregator_sc::ContractBuilder,
);

blockchain
}

struct PriceAggregatorTestState {
world: ScenarioWorld,
oracles: Vec<AddressValue>,
price_aggregator_whitebox: WhiteboxContract<ContractObj<DebugApi>>,
}

impl PriceAggregatorTestState {
fn new() -> Self {
let mut world = world();

world.account(OWNER_ADDRESS).nonce(1);
world.current_block().block_timestamp(100);

world.new_address(OWNER_ADDRESS, 1, PRICE_AGGREGATOR_ADDRESS);

let mut oracles = Vec::new();
for i in 1..=NR_ORACLES {
let address_name = format!("oracle{i}");
let address = TestAddress::new(&address_name);
let address_value = AddressValue::from(address);

world.account(address).nonce(1).balance(STAKE_AMOUNT);
oracles.push(address_value);
}

let price_aggregator_whitebox = WhiteboxContract::new(
PRICE_AGGREGATOR_ADDRESS,
multiversx_price_aggregator_sc::contract_obj,
);

Self {
world,
oracles,
price_aggregator_whitebox,
}
Self { world, oracles }
}

fn deploy(&mut self) -> &mut Self {
let oracles = MultiValueVec::from(
self.oracles
.iter()
.map(|oracle| oracle.to_address())
.collect::<Vec<_>>(),
);

self.world
.tx()
.from(OWNER_ADDRESS)
Expand All @@ -91,7 +65,6 @@ impl PriceAggregatorTestState {
)
.code(PRICE_AGGREGATOR_PATH)
.run();

for address in self.oracles.iter() {
self.world
.tx()
Expand All @@ -102,10 +75,8 @@ impl PriceAggregatorTestState {
.egld(STAKE_AMOUNT)
.run();
}

self
}

fn set_pair_decimals(&mut self) {
self.world
.tx()
Expand All @@ -115,7 +86,6 @@ impl PriceAggregatorTestState {
.set_pair_decimals(EGLD_TICKER, USD_TICKER, DECIMALS)
.run();
}

fn unpause_endpoint(&mut self) {
self.world
.tx()
Expand All @@ -125,7 +95,6 @@ impl PriceAggregatorTestState {
.unpause_endpoint()
.run();
}

fn pause_endpoint(&mut self) {
self.world
.tx()
Expand All @@ -135,7 +104,6 @@ impl PriceAggregatorTestState {
.pause_endpoint()
.run();
}

fn submit(&mut self, from: &AddressValue, submission_timestamp: u64, price: u64) {
self.world
.tx()
Expand All @@ -151,7 +119,6 @@ impl PriceAggregatorTestState {
)
.run();
}

fn submit_and_expect_err(
&mut self,
from: &AddressValue,
Expand All @@ -175,7 +142,6 @@ impl PriceAggregatorTestState {
.with_result(ExpectMessage(err_message))
.run();
}

fn vote_slash_member(&mut self, from: &AddressValue, member_to_slash: Address) {
self.world
.tx()
Expand All @@ -186,36 +152,29 @@ impl PriceAggregatorTestState {
.run();
}
}

#[test]
fn test_price_aggregator_submit() {
let mut state = PriceAggregatorTestState::new();
state.deploy();

// configure the number of decimals
state.set_pair_decimals();

// try submit while paused
state.submit_and_expect_err(&state.oracles[0].clone(), 99, 100, "Contract is paused");

// unpause
state.unpause_endpoint();

// submit first timestamp too old
state.submit_and_expect_err(
&state.oracles[0].clone(),
10,
100,
"First submission too old",
);

// submit ok
state.submit(&state.oracles[0].clone(), 95, 100);

let current_timestamp = 100;
state
.world
.whitebox_query(&state.price_aggregator_whitebox, |sc| {
state.world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox(
multiversx_price_aggregator_sc::contract_obj,
|sc| {
let token_pair = TokenPair {
from: managed_buffer!(EGLD_TICKER),
to: managed_buffer!(USD_TICKER),
Expand All @@ -228,7 +187,6 @@ fn test_price_aggregator_submit() {
sc.last_submission_timestamp(&token_pair).get(),
current_timestamp
);

let submissions = sc.submissions().get(&token_pair).unwrap();
assert_eq!(submissions.len(), 1);
assert_eq!(
Expand All @@ -237,7 +195,6 @@ fn test_price_aggregator_submit() {
.unwrap(),
managed_biguint!(100)
);

assert_eq!(
sc.oracle_status()
.get(&managed_address!(&state.oracles[0].to_address()))
Expand All @@ -247,14 +204,13 @@ fn test_price_aggregator_submit() {
accepted_submissions: 1
}
);
});

},
);
// first oracle submit again - submission not accepted
state.submit(&state.oracles[0].clone(), 95, 100);

state
.world
.whitebox_query(&state.price_aggregator_whitebox, |sc| {
state.world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox(
multiversx_price_aggregator_sc::contract_obj,
|sc| {
assert_eq!(
sc.oracle_status()
.get(&managed_address!(&state.oracles[0].to_address()))
Expand All @@ -264,54 +220,44 @@ fn test_price_aggregator_submit() {
accepted_submissions: 1
}
);
});
},
);
}

#[test]
fn test_price_aggregator_submit_round_ok() {
let mut state = PriceAggregatorTestState::new();
state.deploy();

// configure the number of decimals
state.set_pair_decimals();

// unpause
state.unpause_endpoint();

// submit first
state.submit(&state.oracles[0].clone(), 95, 10_000);

let current_timestamp = 110;
state
.world
.current_block()
.block_timestamp(current_timestamp);

// submit second
state.submit(&state.oracles[1].clone(), 101, 11_000);

// submit third
state.submit(&state.oracles[2].clone(), 105, 12_000);

state
.world
.whitebox_query(&state.price_aggregator_whitebox, |sc| {
state.world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox(
multiversx_price_aggregator_sc::contract_obj,
|sc| {
let result =
sc.latest_price_feed(managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER));

let (round_id, from, to, timestamp, price, decimals) = result.into_tuple();
assert_eq!(round_id, 1);
assert_eq!(from, managed_buffer!(EGLD_TICKER));
assert_eq!(to, managed_buffer!(USD_TICKER));
assert_eq!(timestamp, current_timestamp);
assert_eq!(price, managed_biguint!(11_000));
assert_eq!(decimals, DECIMALS);

// submissions are deleted after round is created
let token_pair = TokenPair { from, to };
let submissions = sc.submissions().get(&token_pair).unwrap();
assert_eq!(submissions.len(), 0);

let rounds = sc.rounds().get(&token_pair).unwrap();
assert_eq!(rounds.len(), 1);
assert_eq!(
Expand All @@ -322,35 +268,29 @@ fn test_price_aggregator_submit_round_ok() {
decimals
}
);
});
},
);
}

#[test]
fn test_price_aggregator_discarded_round() {
let mut state = PriceAggregatorTestState::new();
state.deploy();

// configure the number of decimals
state.set_pair_decimals();

// unpause
state.unpause_endpoint();

// submit first
state.submit(&state.oracles[0].clone(), 95, 10_000);

let current_timestamp = 100 + MAX_ROUND_DURATION_SECONDS + 1;
state
.world
.current_block()
.block_timestamp(current_timestamp);

// submit second - this will discard the previous submission
state.submit(&state.oracles[1].clone(), current_timestamp - 1, 11_000);

state
.world
.whitebox_query(&state.price_aggregator_whitebox, |sc| {
state.world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox(
multiversx_price_aggregator_sc::contract_obj,
|sc| {
let token_pair = TokenPair {
from: managed_buffer!(EGLD_TICKER),
to: managed_buffer!(USD_TICKER),
Expand All @@ -363,21 +303,18 @@ fn test_price_aggregator_discarded_round() {
.unwrap(),
managed_biguint!(11_000)
);
});
},
);
}

#[test]
fn test_price_aggregator_slashing() {
let mut state = PriceAggregatorTestState::new();
state.deploy();

// unpause
state.unpause_endpoint();

state.vote_slash_member(&state.oracles[0].clone(), state.oracles[1].to_address());
state.vote_slash_member(&state.oracles[2].clone(), state.oracles[1].to_address());
state.vote_slash_member(&state.oracles[3].clone(), state.oracles[1].to_address());

state
.world
.tx()
Expand All @@ -386,7 +323,6 @@ fn test_price_aggregator_slashing() {
.typed(price_aggregator_proxy::PriceAggregatorProxy)
.slash_member(state.oracles[1].to_address())
.run();

// oracle 1 try submit after slashing
state.submit_and_expect_err(
&state.oracles[1].clone(),
Expand Down
Loading
Loading