diff --git a/contracts/core/price-aggregator/sc-config.toml b/contracts/core/price-aggregator/sc-config.toml new file mode 100644 index 0000000000..56b3e816a6 --- /dev/null +++ b/contracts/core/price-aggregator/sc-config.toml @@ -0,0 +1,2 @@ +[[proxy]] +path = "tests/price_aggregator_proxy.rs" \ No newline at end of file diff --git a/contracts/core/price-aggregator/tests/price_aggregator_blackbox_test.rs b/contracts/core/price-aggregator/tests/price_aggregator_blackbox_test.rs index cc2dc7b994..db64b7749c 100644 --- a/contracts/core/price-aggregator/tests/price_aggregator_blackbox_test.rs +++ b/contracts/core/price-aggregator/tests/price_aggregator_blackbox_test.rs @@ -1,11 +1,13 @@ use multiversx_price_aggregator_sc::{ price_aggregator_data::{OracleStatus, TimestampedPrice, TokenPair}, - ContractObj, PriceAggregator, ProxyTrait as _, MAX_ROUND_DURATION_SECONDS, + ContractObj, PriceAggregator, MAX_ROUND_DURATION_SECONDS, }; -use multiversx_sc_modules::{pause::ProxyTrait, staking::ProxyTrait as _}; +use multiversx_sc_modules::staking::ProxyTrait as _; use multiversx_sc_scenario::imports::*; +mod price_aggregator_proxy; + const DECIMALS: u8 = 0; const EGLD_TICKER: &[u8] = b"EGLD"; const NR_ORACLES: usize = 4; @@ -18,6 +20,9 @@ const STAKE_AMOUNT: u64 = 20; const SUBMISSION_COUNT: usize = 3; const USD_TICKER: &[u8] = b"USDC"; +const PRICE_AGGREGATOR: ScExpr = ScExpr("price-aggregator"); +const OWNER: AddressExpr = AddressExpr("owner"); + type PriceAggregatorContract = ContractInfo>; fn world() -> ScenarioWorld { @@ -44,7 +49,7 @@ impl PriceAggregatorTestState { let mut world = world(); let mut set_state_step = SetStateStep::new() - .put_account(OWNER_ADDRESS_EXPR, Account::new().nonce(1)) + .put_account(OWNER, Account::new().nonce(1)) .new_address(OWNER_ADDRESS_EXPR, 1, PRICE_AGGREGATOR_ADDRESS_EXPR) .block_timestamp(100); @@ -86,59 +91,69 @@ impl PriceAggregatorTestState { .collect::>(), ); - self.world.sc_deploy( - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(price_aggregator_code) - .call(self.price_aggregator_contract.init( - EgldOrEsdtTokenIdentifier::egld(), - STAKE_AMOUNT, - SLASH_AMOUNT, - SLASH_QUORUM, - SUBMISSION_COUNT, - oracles, - )), - ); + self.world + .tx() + .from(OWNER) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .init( + EgldOrEsdtTokenIdentifier::egld(), + STAKE_AMOUNT, + SLASH_AMOUNT, + SLASH_QUORUM, + SUBMISSION_COUNT, + oracles, + ) + .code(price_aggregator_code) + .run(); for address in self.oracles.iter() { - self.world.sc_call( - ScCallStep::new() - .from(address) - .egld_value(STAKE_AMOUNT) - .call(self.price_aggregator_contract.stake()), - ); + self.world + .tx() + .from(&address.to_address()) + .to(PRICE_AGGREGATOR) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .stake() + .egld(STAKE_AMOUNT) + .run(); } self } fn set_pair_decimals(&mut self) { - self.world.sc_call( - ScCallStep::new().from(OWNER_ADDRESS_EXPR).call( - self.price_aggregator_contract - .set_pair_decimals(EGLD_TICKER, USD_TICKER, DECIMALS), - ), - ); + self.world + .tx() + .from(OWNER) + .to(PRICE_AGGREGATOR) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .set_pair_decimals(EGLD_TICKER, USD_TICKER, DECIMALS) + .run(); } fn unpause_endpoint(&mut self) { - self.world.sc_call( - ScCallStep::new() - .from(OWNER_ADDRESS_EXPR) - .call(self.price_aggregator_contract.unpause_endpoint()), - ); + self.world + .tx() + .from(OWNER) + .to(PRICE_AGGREGATOR) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .unpause_endpoint() + .run(); } fn submit(&mut self, from: &AddressValue, submission_timestamp: u64, price: u64) { - self.world.sc_call(ScCallStep::new().from(from).call( - self.price_aggregator_contract.submit( + self.world + .tx() + .from(&from.to_address()) + .to(PRICE_AGGREGATOR) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .submit( EGLD_TICKER, USD_TICKER, submission_timestamp, price, DECIMALS, - ), - )); + ) + .run(); } fn submit_and_expect_err( @@ -148,27 +163,31 @@ impl PriceAggregatorTestState { price: u64, err_message: &str, ) { - self.world.sc_call( - ScCallStep::new() - .from(from) - .call(self.price_aggregator_contract.submit( - EGLD_TICKER, - USD_TICKER, - submission_timestamp, - price, - DECIMALS, - )) - .expect(TxExpect::user_error("str:".to_string() + err_message)), - ); + self.world + .tx() + .from(&from.to_address()) + .to(PRICE_AGGREGATOR) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .submit( + EGLD_TICKER, + USD_TICKER, + submission_timestamp, + price, + DECIMALS, + ) + .with_result(ExpectStatus(4)) + .with_result(ExpectMessage(err_message)) + .run(); } fn vote_slash_member(&mut self, from: &AddressValue, member_to_slash: Address) { - self.world.sc_call( - ScCallStep::new().from(from).call( - self.price_aggregator_contract - .vote_slash_member(member_to_slash), - ), - ); + self.world + .tx() + .from(&from.to_address()) + .to(PRICE_AGGREGATOR) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .vote_slash_member(member_to_slash) + .run(); } } diff --git a/contracts/core/price-aggregator/tests/price_aggregator_proxy.rs b/contracts/core/price-aggregator/tests/price_aggregator_proxy.rs new file mode 100644 index 0000000000..c7b05acaf5 --- /dev/null +++ b/contracts/core/price-aggregator/tests/price_aggregator_proxy.rs @@ -0,0 +1,366 @@ +// Code generated by the multiversx-sc proxy generator. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +#![allow(dead_code)] +#![allow(clippy::all)] + +use multiversx_sc::proxy_imports::*; + +pub struct PriceAggregatorProxy; + +impl TxProxyTrait for PriceAggregatorProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = PriceAggregatorProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + PriceAggregatorProxyMethods { wrapped_tx: tx } + } +} + +pub struct PriceAggregatorProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl PriceAggregatorProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: CodecInto>, + Arg1: CodecInto>, + Arg2: CodecInto>, + Arg3: CodecInto, + Arg4: CodecInto, + Arg5: CodecInto>>, + >( + self, + staking_token: Arg0, + staking_amount: Arg1, + slash_amount: Arg2, + slash_quorum: Arg3, + submission_count: Arg4, + oracles: Arg5, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&staking_token) + .argument(&staking_amount) + .argument(&slash_amount) + .argument(&slash_quorum) + .argument(&submission_count) + .argument(&oracles) + .original_result() + } +} + +#[rustfmt::skip] +impl PriceAggregatorProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn change_amounts< + Arg0: CodecInto>, + Arg1: CodecInto>, + >( + self, + staking_amount: Arg0, + slash_amount: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("changeAmounts") + .argument(&staking_amount) + .argument(&slash_amount) + .original_result() + } + + pub fn add_oracles< + Arg0: CodecInto>>, + >( + self, + oracles: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("addOracles") + .argument(&oracles) + .original_result() + } + + /// Also receives submission count, + /// so the owner does not have to update it manually with setSubmissionCount before this call + pub fn remove_oracles< + Arg0: CodecInto, + Arg1: CodecInto>>, + >( + self, + submission_count: Arg0, + oracles: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("removeOracles") + .argument(&submission_count) + .argument(&oracles) + .original_result() + } + + pub fn submit< + Arg0: CodecInto>, + Arg1: CodecInto>, + Arg2: CodecInto, + Arg3: CodecInto>, + Arg4: CodecInto, + >( + self, + from: Arg0, + to: Arg1, + submission_timestamp: Arg2, + price: Arg3, + decimals: Arg4, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("submit") + .argument(&from) + .argument(&to) + .argument(&submission_timestamp) + .argument(&price) + .argument(&decimals) + .original_result() + } + + pub fn submit_batch< + Arg0: CodecInto, ManagedBuffer, u64, BigUint, u8>>>, + >( + self, + submissions: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("submitBatch") + .argument(&submissions) + .original_result() + } + + pub fn latest_round_data( + self, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("latestRoundData") + .original_result() + } + + pub fn latest_price_feed< + Arg0: CodecInto>, + Arg1: CodecInto>, + >( + self, + from: Arg0, + to: Arg1, + ) -> TxProxyCall, ManagedBuffer, u64, BigUint, u8>> { + self.wrapped_tx + .raw_call("latestPriceFeed") + .argument(&from) + .argument(&to) + .original_result() + } + + pub fn latest_price_feed_optional< + Arg0: CodecInto>, + Arg1: CodecInto>, + >( + self, + from: Arg0, + to: Arg1, + ) -> TxProxyCall, ManagedBuffer, u64, BigUint, u8>>> { + self.wrapped_tx + .raw_call("latestPriceFeedOptional") + .argument(&from) + .argument(&to) + .original_result() + } + + pub fn set_submission_count< + Arg0: CodecInto, + >( + self, + submission_count: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("setSubmissionCount") + .argument(&submission_count) + .original_result() + } + + pub fn get_oracles( + self, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("getOracles") + .original_result() + } + + pub fn set_pair_decimals< + Arg0: CodecInto>, + Arg1: CodecInto>, + Arg2: CodecInto, + >( + self, + from: Arg0, + to: Arg1, + decimals: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("setPairDecimals") + .argument(&from) + .argument(&to) + .argument(&decimals) + .original_result() + } + + pub fn get_pair_decimals< + Arg0: CodecInto>, + Arg1: CodecInto>, + >( + self, + from: Arg0, + to: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getPairDecimals") + .argument(&from) + .argument(&to) + .original_result() + } + + pub fn submission_count( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("submission_count") + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("isPaused") + .original_result() + } + + pub fn stake( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("stake") + .original_result() + } + + pub fn unstake< + Arg0: CodecInto>, + >( + self, + unstake_amount: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("unstake") + .argument(&unstake_amount) + .original_result() + } + + pub fn vote_slash_member< + Arg0: CodecInto>, + >( + self, + member_to_slash: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("voteSlashMember") + .argument(&member_to_slash) + .original_result() + } + + pub fn cancel_vote_slash_member< + Arg0: CodecInto>, + >( + self, + member_to_slash: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("cancelVoteSlashMember") + .argument(&member_to_slash) + .original_result() + } + + pub fn slash_member< + Arg0: CodecInto>, + >( + self, + member_to_slash: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("slashMember") + .argument(&member_to_slash) + .original_result() + } +} + +#[derive(TopEncode, TopDecode)] +pub struct PriceFeed +where + Api: ManagedTypeApi, +{ + pub round_id: u32, + pub from: ManagedBuffer, + pub to: ManagedBuffer, + pub timestamp: u64, + pub price: BigUint, + pub decimals: u8, +} + +#[derive(TopEncode, TopDecode)] +pub struct NewRoundEvent +where + Api: ManagedTypeApi, +{ + pub price: BigUint, + pub timestamp: u64, + pub decimals: u8, + pub block: u64, + pub epoch: u64, +} diff --git a/contracts/core/price-aggregator/tests/price_aggregator_stress_blackbox.rs b/contracts/core/price-aggregator/tests/price_aggregator_stress_blackbox.rs index 44650679d3..4c01ab175f 100644 --- a/contracts/core/price-aggregator/tests/price_aggregator_stress_blackbox.rs +++ b/contracts/core/price-aggregator/tests/price_aggregator_stress_blackbox.rs @@ -1,8 +1,7 @@ use multiversx_price_aggregator_sc::{ price_aggregator_data::{OracleStatus, TokenPair}, - ContractObj, PriceAggregator, ProxyTrait as _, + ContractObj, PriceAggregator, }; -use multiversx_sc_modules::{pause::ProxyTrait, staking::ProxyTrait as _}; use multiversx_sc_scenario::imports::*; @@ -18,6 +17,8 @@ const STAKE_AMOUNT: u64 = 20; const SUBMISSION_COUNT: usize = 50; const USD_TICKER: &[u8] = b"USDC"; +mod price_aggregator_proxy; + type PriceAggregatorContract = ContractInfo>; fn world() -> ScenarioWorld { @@ -86,65 +87,73 @@ impl PriceAggregatorTestState { .collect::>(), ); - self.world.sc_deploy( - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(price_aggregator_code) - .call(self.price_aggregator_contract.init( - EgldOrEsdtTokenIdentifier::egld(), - STAKE_AMOUNT, - SLASH_AMOUNT, - SLASH_QUORUM, - SUBMISSION_COUNT, - oracles, - )) - .gas_limit("120,000,000"), - ); + self.world + .tx() + .from(AddressExpr("owner")) + .gas(120_000_000u64) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .init( + EgldOrEsdtTokenIdentifier::egld(), + STAKE_AMOUNT, + SLASH_AMOUNT, + SLASH_QUORUM, + SUBMISSION_COUNT, + oracles, + ) + .code(price_aggregator_code) + .run(); for address in self.oracles.iter() { - self.world.sc_call( - ScCallStep::new() - .from(address) - .egld_value(STAKE_AMOUNT) - .call(self.price_aggregator_contract.stake()) - .gas_limit("5,000,000"), - ); + self.world + .tx() + .from(&address.to_address()) + .to(&self.price_aggregator_contract.to_address()) + .gas(5_000_000u64) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .stake() + .egld(STAKE_AMOUNT) + .run(); } self } fn set_pair_decimals(&mut self) { - self.world.sc_call( - ScCallStep::new().from(OWNER_ADDRESS_EXPR).call( - self.price_aggregator_contract - .set_pair_decimals(EGLD_TICKER, USD_TICKER, DECIMALS), - ), - ); + self.world + .tx() + .from(AddressExpr("owner")) + .to(&self.price_aggregator_contract.to_address()) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .set_pair_decimals(EGLD_TICKER, USD_TICKER, DECIMALS) + .run(); } fn unpause_endpoint(&mut self) { - self.world.sc_call( - ScCallStep::new() - .from(OWNER_ADDRESS_EXPR) - .call(self.price_aggregator_contract.unpause_endpoint()) - .gas_limit("5,000,000"), - ); + self.world + .tx() + .from(AddressExpr("owner")) + .to(&self.price_aggregator_contract.to_address()) + .gas(5_000_000u64) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .unpause_endpoint() + .run(); } fn submit(&mut self, from: &AddressValue, submission_timestamp: u64, price: u64) { - self.world.sc_call( - ScCallStep::new() - .from(from) - .call(self.price_aggregator_contract.submit( - EGLD_TICKER, - USD_TICKER, - submission_timestamp, - price, - DECIMALS, - )) - .gas_limit("7,000,000"), - ); + self.world + .tx() + .from(&from.to_address()) + .to(&self.price_aggregator_contract.to_address()) + .gas(7_000_000u64) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .submit( + EGLD_TICKER, + USD_TICKER, + submission_timestamp, + price, + DECIMALS, + ) + .run(); } }