From 8d1041beeba2f85f741894956b8865dcb41fd040 Mon Sep 17 00:00:00 2001 From: oanamariasilivastru Date: Wed, 18 Sep 2024 15:09:47 +0300 Subject: [PATCH 1/2] errors --- fee-market/interactor/.gitignore | 2 + fee-market/interactor/Cargo.toml | 27 ++ fee-market/interactor/src/interactor_main.rs | 364 +++++++++++++++++++ fee-market/interactor/src/proxy.rs | 294 +++++++++++++++ fee-market/sc-config.toml | 4 + 5 files changed, 691 insertions(+) create mode 100644 fee-market/interactor/.gitignore create mode 100644 fee-market/interactor/Cargo.toml create mode 100644 fee-market/interactor/src/interactor_main.rs create mode 100644 fee-market/interactor/src/proxy.rs diff --git a/fee-market/interactor/.gitignore b/fee-market/interactor/.gitignore new file mode 100644 index 00000000..5a64d09a --- /dev/null +++ b/fee-market/interactor/.gitignore @@ -0,0 +1,2 @@ +# Pem files are used for interactions, but shouldn't be committed +*.pem diff --git a/fee-market/interactor/Cargo.toml b/fee-market/interactor/Cargo.toml new file mode 100644 index 00000000..f7858963 --- /dev/null +++ b/fee-market/interactor/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "rust-interactor" +version = "0.0.0" +authors = ["you"] +edition = "2021" +publish = false + +[[bin]] +name = "rust-interact" +path = "src/interactor_main.rs" + +[dependencies.fee-market] +path = ".." + +[dependencies.multiversx-sc-snippets] +version = "0.53.0" + +[dependencies.multiversx-sc] +version = "0.53.0" + +[dependencies] +clap = { version = "4.4.7", features = ["derive"] } +serde = { version = "1.0", features = ["derive"] } +toml = "0.8.6" + +# [workspace] + diff --git a/fee-market/interactor/src/interactor_main.rs b/fee-market/interactor/src/interactor_main.rs new file mode 100644 index 00000000..8067247e --- /dev/null +++ b/fee-market/interactor/src/interactor_main.rs @@ -0,0 +1,364 @@ +#![allow(non_snake_case)] + +mod proxy; + +use multiversx_sc_snippets::imports::*; +use multiversx_sc_snippets::sdk; +use proxy::FeeStruct; +use serde::{Deserialize, Serialize}; +use std::{ + io::{Read, Write}, + path::Path, +}; + + +const GATEWAY: &str = sdk::gateway::DEVNET_GATEWAY; +const STATE_FILE: &str = "state.toml"; + + +#[tokio::main] +async fn main() { + env_logger::init(); + + let mut args = std::env::args(); + let _ = args.next(); + let cmd = args.next().expect("at least one argument required"); + let mut interact = ContractInteract::new().await; + match cmd.as_str() { + "deploy" => interact.deploy().await, + "upgrade" => interact.upgrade().await, + "addFee" => interact.set_fee().await, + "removeFee" => interact.disable_fee().await, + "getTokenFee" => interact.token_fee().await, + "addUsersToWhitelist" => interact.add_users_to_whitelist().await, + "removeUsersFromWhitelist" => interact.remove_users_from_whitelist().await, + "distributeFees" => interact.distribute_fees().await, + "subtractFee" => interact.subtract_fee().await, + "getUsersWhitelist" => interact.users_whitelist().await, + "setMinValidSigners" => interact.set_min_valid_signers().await, + "addSigners" => interact.add_signers().await, + "removeSigners" => interact.remove_signers().await, + _ => panic!("unknown command: {}", &cmd), + } +} + + +#[derive(Debug, Default, Serialize, Deserialize)] +struct State { + contract_address: Option +} + +impl State { + // Deserializes state from file + pub fn load_state() -> Self { + if Path::new(STATE_FILE).exists() { + let mut file = std::fs::File::open(STATE_FILE).unwrap(); + let mut content = String::new(); + file.read_to_string(&mut content).unwrap(); + toml::from_str(&content).unwrap() + } else { + Self::default() + } + } + + /// Sets the contract address + pub fn set_address(&mut self, address: Bech32Address) { + self.contract_address = Some(address); + } + + /// Returns the contract address + pub fn current_address(&self) -> &Bech32Address { + self.contract_address + .as_ref() + .expect("no known contract, deploy first") + } + } + + impl Drop for State { + // Serializes state to file + fn drop(&mut self) { + let mut file = std::fs::File::create(STATE_FILE).unwrap(); + file.write_all(toml::to_string(self).unwrap().as_bytes()) + .unwrap(); + } + } + +struct ContractInteract { + interactor: Interactor, + wallet_address: Address, + contract_code: BytesValue, + state: State +} + +impl ContractInteract { + async fn new() -> Self { + let mut interactor = Interactor::new(GATEWAY).await; + let wallet_address = interactor.register_wallet(test_wallets::alice()); + + let contract_code = BytesValue::interpret_from( + "mxsc:../output/fee-market.mxsc.json", + &InterpreterContext::default(), + ); + + ContractInteract { + interactor, + wallet_address, + contract_code, + state: State::load_state() + } + } + + async fn deploy(&mut self) { + let esdt_safe_address = bech32::decode(""); + let price_aggregator_address = bech32::decode(""); + let fee = Option::Some(FeeStruct::::default()); + let new_address = self + .interactor + .tx() + .from(&self.wallet_address) + .gas(30_000_000u64) + .typed(proxy::FeeMarketProxy) + .init(esdt_safe_address, price_aggregator_address, fee) + .code(&self.contract_code) + .returns(ReturnsNewAddress) + .prepare_async() + .run() + .await; + let new_address_bech32 = bech32::encode(&new_address); + self.state + .set_address(Bech32Address::from_bech32_string(new_address_bech32.clone())); + + println!("new address: {new_address_bech32}"); + } + + async fn upgrade(&mut self) { + let response = self + .interactor + .tx() + .to(self.state.current_address()) + .from(&self.wallet_address) + .gas(30_000_000u64) + .typed(proxy::FeeMarketProxy) + .upgrade() + .code(&self.contract_code) + .code_metadata(CodeMetadata::UPGRADEABLE) + .returns(ReturnsNewAddress) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn set_fee(&mut self) { + let base_token = TokenIdentifier::from_esdt_bytes(&b""[..]); + let fee_type = FeeType::::default(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::FeeMarketProxy) + .set_fee(base_token, fee_type) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn disable_fee(&mut self) { + let base_token = TokenIdentifier::from_esdt_bytes(&b""[..]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::FeeMarketProxy) + .disable_fee(base_token) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn token_fee(&mut self) { + let token_id = TokenIdentifier::from_esdt_bytes(&b""[..]); + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::FeeMarketProxy) + .token_fee(token_id) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {result_value:?}"); + } + + async fn add_users_to_whitelist(&mut self) { + let users = MultiValueVec::from(vec![bech32::decode("")]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::FeeMarketProxy) + .add_users_to_whitelist(users) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn remove_users_from_whitelist(&mut self) { + let users = MultiValueVec::from(vec![bech32::decode("")]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::FeeMarketProxy) + .remove_users_from_whitelist(users) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn distribute_fees(&mut self) { + let address_percentage_pairs = MultiValueVec::from(vec![MultiValue2::, u32>::from((bech32::decode(""), 0u32))]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::FeeMarketProxy) + .distribute_fees(address_percentage_pairs) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn subtract_fee(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let original_caller = bech32::decode(""); + let total_transfers = 0u32; + let opt_gas_limit = OptionalValue::Some(0u64); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::FeeMarketProxy) + .subtract_fee(original_caller, total_transfers, opt_gas_limit) + .payment((TokenIdentifier::from(token_id.as_str()), token_nonce, token_amount)) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn users_whitelist(&mut self) { + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::FeeMarketProxy) + .users_whitelist() + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {result_value:?}"); + } + + async fn set_min_valid_signers(&mut self) { + let new_value = 0u32; + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::FeeMarketProxy) + .set_min_valid_signers(new_value) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn add_signers(&mut self) { + let signers = MultiValueVec::from(vec![bech32::decode("")]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::FeeMarketProxy) + .add_signers(signers) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn remove_signers(&mut self) { + let signers = MultiValueVec::from(vec![bech32::decode("")]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::FeeMarketProxy) + .remove_signers(signers) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + +} diff --git a/fee-market/interactor/src/proxy.rs b/fee-market/interactor/src/proxy.rs new file mode 100644 index 00000000..db0a2cf8 --- /dev/null +++ b/fee-market/interactor/src/proxy.rs @@ -0,0 +1,294 @@ +// 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 FeeMarketProxy; + +impl TxProxyTrait for FeeMarketProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = FeeMarketProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + FeeMarketProxyMethods { wrapped_tx: tx } + } +} + +pub struct FeeMarketProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl FeeMarketProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>>, + >( + self, + esdt_safe_address: Arg0, + price_aggregator_address: Arg1, + fee: Arg2, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .argument(&esdt_safe_address) + .argument(&price_aggregator_address) + .argument(&fee) + .original_result() + } +} + +#[rustfmt::skip] +impl FeeMarketProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl FeeMarketProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn set_fee< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + base_token: Arg0, + fee_type: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("addFee") + .argument(&base_token) + .argument(&fee_type) + .original_result() + } + + pub fn disable_fee< + Arg0: ProxyArg>, + >( + self, + base_token: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeFee") + .argument(&base_token) + .original_result() + } + + pub fn token_fee< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTokenFee") + .argument(&token_id) + .original_result() + } + + pub fn add_users_to_whitelist< + Arg0: ProxyArg>>, + >( + self, + users: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("addUsersToWhitelist") + .argument(&users) + .original_result() + } + + pub fn remove_users_from_whitelist< + Arg0: ProxyArg>>, + >( + self, + users: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeUsersFromWhitelist") + .argument(&users) + .original_result() + } + + /// Percentages have to be between 0 and 10_000, and must all add up to 100% (i.e. 10_000) + pub fn distribute_fees< + Arg0: ProxyArg, usize>>>, + >( + self, + address_percentage_pairs: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("distributeFees") + .argument(&address_percentage_pairs) + .original_result() + } + + pub fn subtract_fee< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + original_caller: Arg0, + total_transfers: Arg1, + opt_gas_limit: Arg2, + ) -> TxTypedCall> { + self.wrapped_tx + .raw_call("subtractFee") + .argument(&original_caller) + .argument(&total_transfers) + .argument(&opt_gas_limit) + .original_result() + } + + pub fn users_whitelist( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getUsersWhitelist") + .original_result() + } + + pub fn set_min_valid_signers< + Arg0: ProxyArg, + >( + self, + new_value: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMinValidSigners") + .argument(&new_value) + .original_result() + } + + pub fn add_signers< + Arg0: ProxyArg>>, + >( + self, + signers: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("addSigners") + .argument(&signers) + .original_result() + } + + pub fn remove_signers< + Arg0: ProxyArg>>, + >( + self, + signers: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeSigners") + .argument(&signers) + .original_result() + } +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode)] +pub struct FeeStruct +where + Api: ManagedTypeApi, +{ + pub base_token: TokenIdentifier, + pub fee_type: FeeType, +} + +impl Default for FeeStruct +where + Api: ManagedTypeApi, + TokenIdentifier: Default, // Asigură-te că TokenIdentifier implementează Default + FeeType: Default, // Asigură-te că FeeType implementează Default +{ + fn default() -> Self { + FeeStruct { + base_token: TokenIdentifier::default(), // Valoare implicită pentru TokenIdentifier + fee_type: FeeType::default(), // Valoare implicită pentru FeeType + } + } +} +#[rustfmt::skip] +#[type_abi] +#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode)] +pub enum FeeType +where + Api: ManagedTypeApi, +{ + None, + Fixed { + token: TokenIdentifier, + per_transfer: BigUint, + per_gas: BigUint, + }, + AnyToken { + base_fee_token: TokenIdentifier, + per_transfer: BigUint, + per_gas: BigUint, + }, +} + +#[type_abi] +#[derive(TopEncode, TopDecode)] +pub struct FinalPayment +where + Api: ManagedTypeApi, +{ + pub fee: EsdtTokenPayment, + pub remaining_tokens: EsdtTokenPayment, +} diff --git a/fee-market/sc-config.toml b/fee-market/sc-config.toml index 78a84c24..3cfbbfdf 100644 --- a/fee-market/sc-config.toml +++ b/fee-market/sc-config.toml @@ -17,3 +17,7 @@ add-labels = ["fee-market-external-view"] [[proxy]] path = "src/fee_market_proxy.rs" + +[[proxy]] +path = "interactor/src/proxy.rs" + From 95ca457b234ca70a307dcd7cccc940254891208a Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Wed, 18 Sep 2024 16:24:05 +0300 Subject: [PATCH 2/2] fix interactor error - MultiValueEncoded init --- fee-market/interactor/src/interactor_main.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fee-market/interactor/src/interactor_main.rs b/fee-market/interactor/src/interactor_main.rs index 8067247e..87aeed1a 100644 --- a/fee-market/interactor/src/interactor_main.rs +++ b/fee-market/interactor/src/interactor_main.rs @@ -245,7 +245,11 @@ impl ContractInteract { } async fn distribute_fees(&mut self) { - let address_percentage_pairs = MultiValueVec::from(vec![MultiValue2::, u32>::from((bech32::decode(""), 0u32))]); + let mut address_percentage_pairs: MultiValueEncoded< + StaticApi, + MultiValue2, usize>, + > = MultiValueEncoded::new(); + address_percentage_pairs.push(MultiValue2((ManagedAddress::zero(), 0usize))); let response = self .interactor @@ -360,5 +364,4 @@ impl ContractInteract { println!("Result: {response:?}"); } - }