From 9831902322555e9bd7bb538a0b4d339be8129f59 Mon Sep 17 00:00:00 2001 From: Mihai Calin Luca Date: Mon, 2 Dec 2024 18:30:54 +0100 Subject: [PATCH] system interactor chain simulator setup --- tools/interactor-system-func-calls/Cargo.toml | 6 + .../src/system_sc_interact.rs | 230 ++++++++++++------ .../src/system_sc_interact_config.rs | 9 +- .../src/system_sc_main.rs | 6 + .../tests/chain_simulator_token_tests.rs | 54 ++++ 5 files changed, 229 insertions(+), 76 deletions(-) create mode 100644 tools/interactor-system-func-calls/src/system_sc_main.rs create mode 100644 tools/interactor-system-func-calls/tests/chain_simulator_token_tests.rs diff --git a/tools/interactor-system-func-calls/Cargo.toml b/tools/interactor-system-func-calls/Cargo.toml index a92170f220..28921639df 100644 --- a/tools/interactor-system-func-calls/Cargo.toml +++ b/tools/interactor-system-func-calls/Cargo.toml @@ -1,5 +1,8 @@ [[bin]] name = "system-sc-interact" +path = "src/system_sc_main.rs" + +[lib] path = "src/system_sc_interact.rs" [package] @@ -24,3 +27,6 @@ features = ["derive"] [dependencies.multiversx-sc-snippets] version = "=0.54.5" path = "../../framework/snippets" + +[features] +chain-simulator-tests = [] diff --git a/tools/interactor-system-func-calls/src/system_sc_interact.rs b/tools/interactor-system-func-calls/src/system_sc_interact.rs index 97d3005c97..a10e7caaec 100644 --- a/tools/interactor-system-func-calls/src/system_sc_interact.rs +++ b/tools/interactor-system-func-calls/src/system_sc_interact.rs @@ -1,21 +1,18 @@ -#![allow(deprecated)] // TODO: move prepare_async calls to a test for backwards compatibility and delete from here - mod system_sc_interact_cli; mod system_sc_interact_config; mod system_sc_interact_state; use clap::Parser; -use system_sc_interact_cli::NftDummyAttributes; -use system_sc_interact_config::Config; +pub use system_sc_interact_cli::NftDummyAttributes; +pub use system_sc_interact_config::Config; use system_sc_interact_state::State; use multiversx_sc_snippets::imports::*; -#[tokio::main] -async fn main() { +pub async fn system_sc_interact_cli() { env_logger::init(); - let mut basic_interact = SysFuncCallsInteract::init().await; + let mut basic_interact = SysFuncCallsInteract::init(Config::load_config()).await; let cli = system_sc_interact_cli::InteractCli::parse(); match &cli.command { @@ -130,6 +127,11 @@ async fn main() { args.name.as_bytes(), args.royalties, args.hash.as_bytes(), + &NftDummyAttributes { + creation_epoch: 2u64, + cool_factor: 3u8, + }, + Vec::new(), ) .await; }, @@ -219,19 +221,18 @@ async fn main() { } } -#[allow(unused)] -struct SysFuncCallsInteract { +pub struct SysFuncCallsInteract { interactor: Interactor, wallet_address: Bech32Address, + #[allow(unused)] state: State, } impl SysFuncCallsInteract { - async fn init() -> Self { - let config = Config::load_config(); + pub async fn init(config: Config) -> Self { let mut interactor = Interactor::new(config.gateway_uri()) .await - .use_chain_simulator(config.use_chain_simulator()); + .use_chain_simulator(config.is_chain_simulator()); interactor.set_current_dir_from_workspace("tools/interactor-system-func-calls"); let wallet_address = interactor.register_wallet(test_wallets::alice()).await; @@ -246,7 +247,7 @@ impl SysFuncCallsInteract { } } - async fn issue_fungible_token( + pub async fn issue_fungible_token( &mut self, issue_cost: RustBigUint, token_display_name: &[u8], @@ -281,14 +282,13 @@ impl SysFuncCallsInteract { }, ) .returns(ReturnsNewTokenIdentifier) - .prepare_async() .run() .await; println!("TOKEN ID: {:?}", res); } - async fn issue_non_fungible_collection( + pub async fn issue_non_fungible_collection( &mut self, issue_cost: RustBigUint, token_display_name: &[u8], @@ -318,14 +318,13 @@ impl SysFuncCallsInteract { }, ) .returns(ReturnsNewTokenIdentifier) - .prepare_async() .run() .await; println!("NFT Collection ID: {:?}", nft_collection_id); } - async fn issue_semi_fungible_collection( + pub async fn issue_semi_fungible_collection( &mut self, issue_cost: RustBigUint, token_display_name: &[u8], @@ -355,22 +354,21 @@ impl SysFuncCallsInteract { }, ) .returns(ReturnsNewTokenIdentifier) - .prepare_async() .run() .await; println!("SFT Collection ID: {:?}", sft_collection_id); } - async fn issue_token( + pub async fn issue_token( &mut self, issue_cost: RustBigUint, token_display_name: &[u8], token_ticker: &[u8], num_decimals: usize, token_type: EsdtTokenType, - ) { - println!("Registering token..."); + ) -> String { + println!("Registering and setting all roles for token {token_ticker:?} of type {token_type:?}..."); let token_id = self .interactor @@ -387,16 +385,17 @@ impl SysFuncCallsInteract { num_decimals, ) .returns(ReturnsNewTokenIdentifier) - .prepare_async() .run() .await; println!("TOKEN ID: {:?}", token_id); + + token_id } - async fn set_roles(&mut self, token_id: &[u8], roles: Vec) { + pub async fn set_roles(&mut self, token_id: &[u8], roles: Vec) { let wallet_address = &self.wallet_address.clone().into_address(); - println!("Setting the following roles: {:?}", roles); + println!("Setting the following roles: {roles:?} for {token_id:?}"); self.interactor .tx() @@ -409,12 +408,11 @@ impl SysFuncCallsInteract { TokenIdentifier::from(token_id), roles.into_iter(), ) - .prepare_async() .run() .await; } - async fn mint_sft( + pub async fn mint_sft( &mut self, token_id: &[u8], amount: RustBigUint, @@ -442,12 +440,11 @@ impl SysFuncCallsInteract { }, &ManagedVec::new(), ) - .prepare_async() .run() .await; } - async fn register_meta_esdt( + pub async fn register_meta_esdt( &mut self, issue_cost: RustBigUint, token_display_name: &[u8], @@ -479,14 +476,13 @@ impl SysFuncCallsInteract { }, ) .returns(ReturnsNewTokenIdentifier) - .prepare_async() .run() .await; println!("Meta-ESDT ID: {:?}", meta_esdt); } - async fn change_sft_meta_esdt(&mut self, token_id: &[u8], num_decimals: usize) { + pub async fn change_sft_meta_esdt(&mut self, token_id: &[u8], num_decimals: usize) { println!("Changing SFT to Meta-ESDT..."); self.interactor @@ -496,12 +492,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(ESDTSystemSCProxy) .change_sft_to_meta_esdt(token_id, num_decimals) - .prepare_async() .run() .await; } - async fn mint_token(&mut self, token_id: &[u8], nonce: u64, amount: RustBigUint) { + pub async fn mint_token(&mut self, token_id: &[u8], nonce: u64, amount: RustBigUint) { println!("Minting tokens..."); self.interactor @@ -511,12 +506,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(UserBuiltinProxy) .esdt_local_mint(token_id, nonce, amount) - .prepare_async() .run() .await; } - async fn burn_token(&mut self, token_id: &[u8], nonce: u64, amount: RustBigUint) { + pub async fn burn_token(&mut self, token_id: &[u8], nonce: u64, amount: RustBigUint) { println!("Burning tokens..."); self.interactor @@ -526,12 +520,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(UserBuiltinProxy) .esdt_local_burn(token_id, nonce, amount) - .prepare_async() .run() .await; } - async fn pause_token(&mut self, token_id: &[u8]) { + pub async fn pause_token(&mut self, token_id: &[u8]) { println!("Pausing token..."); self.interactor @@ -541,12 +534,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(ESDTSystemSCProxy) .pause(token_id) - .prepare_async() .run() .await; } - async fn unpause_token(&mut self, token_id: &[u8]) { + pub async fn unpause_token(&mut self, token_id: &[u8]) { println!("Unpausing token..."); self.interactor @@ -556,12 +548,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(ESDTSystemSCProxy) .unpause(token_id) - .prepare_async() .run() .await; } - async fn freeze_token(&mut self, token_id: &[u8], address: &Bech32Address) { + pub async fn freeze_token(&mut self, token_id: &[u8], address: &Bech32Address) { println!("Freezing token..."); self.interactor @@ -571,12 +562,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(ESDTSystemSCProxy) .freeze(token_id, address) - .prepare_async() .run() .await; } - async fn unfreeze_token(&mut self, token_id: &[u8], address: &Bech32Address) { + pub async fn unfreeze_token(&mut self, token_id: &[u8], address: &Bech32Address) { println!("Unfreezing token..."); self.interactor @@ -586,12 +576,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(ESDTSystemSCProxy) .unfreeze(token_id, address) - .prepare_async() .run() .await; } - async fn freeze_nft(&mut self, token_id: &[u8], nonce: u64, address: &Bech32Address) { + pub async fn freeze_nft(&mut self, token_id: &[u8], nonce: u64, address: &Bech32Address) { println!("Freezing NFT/SFT/Meta-ESDT..."); self.interactor @@ -601,12 +590,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(ESDTSystemSCProxy) .freeze_nft(token_id, nonce, address) - .prepare_async() .run() .await; } - async fn unfreeze_nft(&mut self, token_id: &[u8], nonce: u64, address: &Bech32Address) { + pub async fn unfreeze_nft(&mut self, token_id: &[u8], nonce: u64, address: &Bech32Address) { println!("Unfreezing NFT/SFT/Meta-ESDT..."); self.interactor @@ -616,12 +604,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(ESDTSystemSCProxy) .unfreeze_nft(token_id, nonce, address) - .prepare_async() .run() .await; } - async fn wipe_token(&mut self, token_id: &[u8], address: &Bech32Address) { + pub async fn wipe_token(&mut self, token_id: &[u8], address: &Bech32Address) { println!("Wiping token..."); self.interactor @@ -631,12 +618,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(ESDTSystemSCProxy) .wipe(token_id, address) - .prepare_async() .run() .await; } - async fn wipe_nft(&mut self, token_id: &[u8], nonce: u64, address: &Bech32Address) { + pub async fn wipe_nft(&mut self, token_id: &[u8], nonce: u64, address: &Bech32Address) { println!("Wiping NFT/SFT/Meta-ESDT..."); self.interactor @@ -646,45 +632,41 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(ESDTSystemSCProxy) .wipe_nft(token_id, nonce, address) - .prepare_async() .run() .await; } - async fn mint_nft( + #[allow(clippy::too_many_arguments)] + pub async fn mint_nft( &mut self, token_id: &[u8], amount: RustBigUint, name: &[u8], royalties: u64, hash: &[u8], - ) { + attributes: &T, + uris: Vec, + ) -> u64 { println!("Minting NFT..."); + let uris = uris + .into_iter() + .map(ManagedBuffer::from) + .collect::>>(); + self.interactor .tx() .from(&self.wallet_address) .to(&self.wallet_address) .gas(100_000_000u64) .typed(UserBuiltinProxy) - .esdt_nft_create( - token_id, - amount, - name, - royalties, - hash, - &NftDummyAttributes { - creation_epoch: 2104, - cool_factor: 5, - }, - &ManagedVec::new(), - ) - .prepare_async() + .esdt_nft_create(token_id, amount, name, royalties, hash, attributes, &uris) + .returns(ReturnsResult) .run() - .await; + .await } - async fn unset_roles( + pub async fn unset_roles( &mut self, address: &Bech32Address, token_id: &[u8], @@ -699,12 +681,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(ESDTSystemSCProxy) .unset_special_roles(address, token_id, roles.into_iter()) - .prepare_async() .run() .await; } - async fn transfer_ownership(&mut self, token_id: &[u8], new_owner: &Bech32Address) { + pub async fn transfer_ownership(&mut self, token_id: &[u8], new_owner: &Bech32Address) { println!("Transferring token ownership..."); self.interactor @@ -714,12 +695,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(ESDTSystemSCProxy) .transfer_ownership(token_id, new_owner) - .prepare_async() .run() .await; } - async fn transfer_nft_create_role( + pub async fn transfer_nft_create_role( &mut self, token_id: &[u8], old_owner: &Bech32Address, @@ -734,12 +714,11 @@ impl SysFuncCallsInteract { .gas(100_000_000u64) .typed(ESDTSystemSCProxy) .transfer_nft_create_role(token_id, old_owner, new_owner) - .prepare_async() .run() .await; } - async fn control_changes(&mut self, token_id: &[u8]) { + pub async fn control_changes(&mut self, token_id: &[u8]) { println!("Control changes"); self.interactor @@ -762,7 +741,108 @@ impl SysFuncCallsInteract { can_add_special_roles: Some(true), }, ) - .prepare_async() + .run() + .await; + } + + pub async fn set_token_type(&mut self, token_id: &[u8], token_type: EsdtTokenType) { + println!("Setting token type to {token_type:?} for token {token_id:?}..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(&self.wallet_address) + .gas(100_000_000u64) + .typed(UserBuiltinProxy) + .esdt_set_token_type(token_id, token_type) + .run() + .await; + } + + pub async fn modify_royalties(&mut self, token_id: &[u8], nonce: u64, new_royalty: u64) { + println!("Modifying royalties for token {token_id:?} into {new_royalty:?}..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(&self.wallet_address) + .gas(100_000_000u64) + .typed(UserBuiltinProxy) + .esdt_modify_royalties(token_id, nonce, new_royalty) + .run() + .await; + } + + pub async fn set_new_uris(&mut self, token_id: &[u8], nonce: u64, new_uris: Vec) { + println!("Setting new uris for token {token_id:?} with nonce {nonce:?}..."); + + let uris = new_uris + .into_iter() + .map(ManagedBuffer::from) + .collect::>>(); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(&self.wallet_address) + .gas(100_000_000u64) + .typed(UserBuiltinProxy) + .esdt_nft_set_new_uris(token_id, nonce, &uris) + .run() + .await; + } + + // changes creator into caller + pub async fn modify_creator(&mut self, token_id: &[u8], nonce: u64) { + println!( + "Modifying the creator (into caller) for token {token_id:?} with nonce {nonce:?}..." + ); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(&self.wallet_address) + .gas(100_000_000u64) + .typed(UserBuiltinProxy) + .esdt_nft_modify_creator(token_id, nonce) + .run() + .await; + } + + pub async fn metadata_recreate( + &mut self, + token_id: &[u8], + nonce: u64, + new_attributes: T, + ) { + println!("Recreating the token {token_id:?} with nonce {nonce:?} with new attributes..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(&self.wallet_address) + .gas(100_000_000u64) + .typed(UserBuiltinProxy) + .esdt_metadata_recreate(token_id, nonce, &new_attributes) + .run() + .await; + } + + pub async fn metadata_update( + &mut self, + token_id: &[u8], + nonce: u64, + new_attributes: T, + ) { + println!("Updating the token {token_id:?} with nonce {nonce:?} with new attributes..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(&self.wallet_address) + .gas(100_000_000u64) + .typed(UserBuiltinProxy) + .esdt_metadata_update(token_id, nonce, &new_attributes) .run() .await; } diff --git a/tools/interactor-system-func-calls/src/system_sc_interact_config.rs b/tools/interactor-system-func-calls/src/system_sc_interact_config.rs index c61059d57e..f2a23a0da5 100644 --- a/tools/interactor-system-func-calls/src/system_sc_interact_config.rs +++ b/tools/interactor-system-func-calls/src/system_sc_interact_config.rs @@ -27,13 +27,20 @@ impl Config { toml::from_str(&content).unwrap() } + pub fn chain_simulator_config() -> Self { + Config { + gateway_uri: "http://localhost:8085".to_owned(), + chain_type: ChainType::Simulator, + } + } + // Returns the gateway URI pub fn gateway_uri(&self) -> &str { &self.gateway_uri } // Returns if chain type is chain simulator - pub fn use_chain_simulator(&self) -> bool { + pub fn is_chain_simulator(&self) -> bool { match self.chain_type { ChainType::Real => false, ChainType::Simulator => true, diff --git a/tools/interactor-system-func-calls/src/system_sc_main.rs b/tools/interactor-system-func-calls/src/system_sc_main.rs new file mode 100644 index 0000000000..89a4ca0a28 --- /dev/null +++ b/tools/interactor-system-func-calls/src/system_sc_main.rs @@ -0,0 +1,6 @@ +extern crate system_sc_interact; + +#[tokio::main] +pub async fn main() { + system_sc_interact::system_sc_interact_cli().await; +} diff --git a/tools/interactor-system-func-calls/tests/chain_simulator_token_tests.rs b/tools/interactor-system-func-calls/tests/chain_simulator_token_tests.rs new file mode 100644 index 0000000000..00db309334 --- /dev/null +++ b/tools/interactor-system-func-calls/tests/chain_simulator_token_tests.rs @@ -0,0 +1,54 @@ +use multiversx_sc_snippets::imports::{EsdtTokenType, RustBigUint}; +use system_sc_interact::{Config, NftDummyAttributes, SysFuncCallsInteract}; + +#[tokio::test] +#[ignore = "fixes needed"] +async fn cs_builtin_func_tokens_test() { + let mut interact = SysFuncCallsInteract::init(Config::chain_simulator_config()).await; + + // issue dynamic NFT + let dynamic_nft_token_id = interact + .issue_token( + RustBigUint::from(50000000000000000u64), + b"TESTNFT", + b"TEST", + 0usize, + EsdtTokenType::DynamicNFT, + ) + .await; + + println!("Dynamic NFT token id issued: {dynamic_nft_token_id:?}"); + + // mint NFT + let nonce = interact + .mint_nft( + dynamic_nft_token_id.as_bytes(), + RustBigUint::from(1u64), + b"myNFT", + 30u64, + b"", + &NftDummyAttributes { + creation_epoch: 2u64, + cool_factor: 3u8, + }, + Vec::new(), + ) + .await; + + println!("Dynamic NFT minted at nonce {nonce:?}"); + + // modify royalties + interact + .modify_royalties(dynamic_nft_token_id.as_bytes(), nonce, 20u64) + .await; + + println!("Royalties changed for {dynamic_nft_token_id:?} with nonce {nonce:?}"); + + // set new uris + let uris = vec!["thisianuri.com".to_string()]; + interact + .set_new_uris(dynamic_nft_token_id.as_bytes(), nonce, uris) + .await; + + println!("New uris set for {dynamic_nft_token_id:?} with nonce {nonce:?}"); +}