From e409053bdd32a5ae454552793c6c74648419df57 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Wed, 8 Jan 2025 09:42:32 +0200 Subject: [PATCH 1/3] esdt transfer raw tests --- .../src/builtin_func_features.rs | 11 ++- .../src/esdt_features.rs | 28 ++++++ .../tests/esdt_transfer_promise_tests.rs | 88 +++++++++++++++++++ .../builtin-func-features/wasm/src/lib.rs | 5 +- 4 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 contracts/feature-tests/composability/builtin-func-features/src/esdt_features.rs create mode 100644 contracts/feature-tests/composability/builtin-func-features/tests/esdt_transfer_promise_tests.rs diff --git a/contracts/feature-tests/composability/builtin-func-features/src/builtin_func_features.rs b/contracts/feature-tests/composability/builtin-func-features/src/builtin_func_features.rs index de33932a9e..1a62d3f575 100644 --- a/contracts/feature-tests/composability/builtin-func-features/src/builtin_func_features.rs +++ b/contracts/feature-tests/composability/builtin-func-features/src/builtin_func_features.rs @@ -2,11 +2,18 @@ multiversx_sc::imports!(); +pub mod esdt_features; + /// Test contract for investigating async calls. #[multiversx_sc::contract] -pub trait BuiltinFuncFeatures { +pub trait BuiltinFuncFeatures: esdt_features::EsdtFeaturesModule { #[init] - fn init(&self) {} + fn init(&self, fungible_token_id: TokenIdentifier, non_fungible_token_id: TokenIdentifier) { + self.fungible_esdt_token_id() + .set_token_id(fungible_token_id); + self.non_fungible_esdt_token_id() + .set_token_id(non_fungible_token_id); + } #[endpoint] fn call_set_user_name(&self, address: ManagedAddress, name: ManagedBuffer) { diff --git a/contracts/feature-tests/composability/builtin-func-features/src/esdt_features.rs b/contracts/feature-tests/composability/builtin-func-features/src/esdt_features.rs new file mode 100644 index 0000000000..cd79237e9a --- /dev/null +++ b/contracts/feature-tests/composability/builtin-func-features/src/esdt_features.rs @@ -0,0 +1,28 @@ +multiversx_sc::imports!(); + +static ESDT_TRANSFER_FUNC_NAME: &[u8] = b"ESDTTransfer"; +// static ESDT_NFT_TRANSFER_FUNC_NAME: &[u8] = b"ESDTNFTTransfer"; + +const GAS_LIMIT_ESDT_TRANSFER: u64 = 50_0000; +// const CALLBACK_ESDT_TRANSFER_GAS_LIMIT: u64 = 100_000; // TODO: Change if needed + +#[multiversx_sc::module] +pub trait EsdtFeaturesModule { + #[endpoint(transferFungiblePromiseNoCallback)] + fn transfer_fungible_promise_no_callback(&self, to: ManagedAddress, amount: BigUint) { + let token_id = self.fungible_esdt_token_id().get_token_id(); + self.tx() + .to(to) + .raw_call(ESDT_TRANSFER_FUNC_NAME) + .argument(&token_id) + .argument(&amount) + .gas(GAS_LIMIT_ESDT_TRANSFER) + .register_promise(); + } + + #[storage_mapper("fungibleEsdtTokenId")] + fn fungible_esdt_token_id(&self) -> FungibleTokenMapper; + + #[storage_mapper("nonFungibleEsdtTokenId")] + fn non_fungible_esdt_token_id(&self) -> NonFungibleTokenMapper; +} diff --git a/contracts/feature-tests/composability/builtin-func-features/tests/esdt_transfer_promise_tests.rs b/contracts/feature-tests/composability/builtin-func-features/tests/esdt_transfer_promise_tests.rs new file mode 100644 index 0000000000..3086a55605 --- /dev/null +++ b/contracts/feature-tests/composability/builtin-func-features/tests/esdt_transfer_promise_tests.rs @@ -0,0 +1,88 @@ +use builtin_func_features::{esdt_features::EsdtFeaturesModule, BuiltinFuncFeatures}; +use multiversx_sc::{codec::Empty, types::Address}; +use multiversx_sc_scenario::{ + imports::{BlockchainStateWrapper, ContractObjWrapper}, + managed_address, managed_biguint, managed_token_id, rust_biguint, DebugApi, +}; + +pub static FUNGIBLE_TOKEN_ID: &[u8] = b"FUNG-123456"; +pub static NON_FUNGIBLE_TOKEN_ID: &[u8] = b"NONFUNG-123456"; +pub const INIT_BALANCE: u64 = 100_000; +pub const INIT_NONCE: u64 = 1; + +pub struct BuiltInFuncFeaturesSetup +where + BuiltInFuncBuilder: 'static + Copy + Fn() -> builtin_func_features::ContractObj, +{ + pub b_mock: BlockchainStateWrapper, + pub user: Address, + pub sc_wrapper: + ContractObjWrapper, BuiltInFuncBuilder>, +} + +impl BuiltInFuncFeaturesSetup +where + BuiltInFuncBuilder: 'static + Copy + Fn() -> builtin_func_features::ContractObj, +{ + pub fn new(built_in_func_builder: BuiltInFuncBuilder) -> Self { + let mut b_mock = BlockchainStateWrapper::new(); + let user = b_mock.create_user_account(&rust_biguint!(0)); + let sc_wrapper = b_mock.create_sc_account( + &rust_biguint!(0), + Some(&user), + built_in_func_builder, + "built in func features", + ); + b_mock + .execute_tx(&user, &sc_wrapper, &rust_biguint!(0), |sc| { + sc.init( + managed_token_id!(FUNGIBLE_TOKEN_ID), + managed_token_id!(NON_FUNGIBLE_TOKEN_ID), + ); + }) + .assert_ok(); + + b_mock.set_esdt_balance( + sc_wrapper.address_ref(), + FUNGIBLE_TOKEN_ID, + &rust_biguint!(INIT_BALANCE), + ); + b_mock.set_nft_balance( + sc_wrapper.address_ref(), + NON_FUNGIBLE_TOKEN_ID, + INIT_NONCE, + &rust_biguint!(INIT_BALANCE), + &Empty, + ); + + BuiltInFuncFeaturesSetup { + b_mock, + user, + sc_wrapper, + } + } +} + +#[test] +fn transfer_fungible_promise_no_callback_test() { + let mut setup = BuiltInFuncFeaturesSetup::new(builtin_func_features::contract_obj); + let user_addr = setup.user.clone(); + setup + .b_mock + .execute_tx(&setup.user, &setup.sc_wrapper, &rust_biguint!(0), |sc| { + sc.transfer_fungible_promise_no_callback( + managed_address!(&user_addr), + managed_biguint!(INIT_BALANCE), + ); + }) + .assert_ok(); + + setup + .b_mock + .check_esdt_balance(&setup.user, FUNGIBLE_TOKEN_ID, &rust_biguint!(INIT_BALANCE)); + setup.b_mock.check_esdt_balance( + setup.sc_wrapper.address_ref(), + FUNGIBLE_TOKEN_ID, + &rust_biguint!(0), + ); +} diff --git a/contracts/feature-tests/composability/builtin-func-features/wasm/src/lib.rs b/contracts/feature-tests/composability/builtin-func-features/wasm/src/lib.rs index 832df1781b..0c28faa4cb 100644 --- a/contracts/feature-tests/composability/builtin-func-features/wasm/src/lib.rs +++ b/contracts/feature-tests/composability/builtin-func-features/wasm/src/lib.rs @@ -5,9 +5,9 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 2 +// Endpoints: 3 // Async Callback (empty): 1 -// Total number of exported functions: 4 +// Total number of exported functions: 5 #![no_std] @@ -20,6 +20,7 @@ multiversx_sc_wasm_adapter::endpoints! { init => init call_set_user_name => call_set_user_name call_delete_user_name => call_delete_user_name + transferFungiblePromiseNoCallback => transfer_fungible_promise_no_callback ) } From fe41565f6b05f99088e927d453263eac5841f483 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Wed, 8 Jan 2025 09:51:15 +0200 Subject: [PATCH 2/3] transfer with callback test --- .../src/esdt_features.rs | 40 ++++++++++++++++++- .../tests/esdt_transfer_promise_tests.rs | 39 +++++++++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/contracts/feature-tests/composability/builtin-func-features/src/esdt_features.rs b/contracts/feature-tests/composability/builtin-func-features/src/esdt_features.rs index cd79237e9a..817d53b1db 100644 --- a/contracts/feature-tests/composability/builtin-func-features/src/esdt_features.rs +++ b/contracts/feature-tests/composability/builtin-func-features/src/esdt_features.rs @@ -1,10 +1,17 @@ multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); static ESDT_TRANSFER_FUNC_NAME: &[u8] = b"ESDTTransfer"; -// static ESDT_NFT_TRANSFER_FUNC_NAME: &[u8] = b"ESDTNFTTransfer"; const GAS_LIMIT_ESDT_TRANSFER: u64 = 50_0000; -// const CALLBACK_ESDT_TRANSFER_GAS_LIMIT: u64 = 100_000; // TODO: Change if needed +const CALLBACK_ESDT_TRANSFER_GAS_LIMIT: u64 = 100_000; + +#[derive(TopEncode, TopDecode)] +pub enum TransferResult { + None, + Success, + Fail, +} #[multiversx_sc::module] pub trait EsdtFeaturesModule { @@ -20,9 +27,38 @@ pub trait EsdtFeaturesModule { .register_promise(); } + #[endpoint(transferFungiblePromiseWithCallback)] + fn transfer_fungible_promise_with_callback(&self, to: ManagedAddress, amount: BigUint) { + let token_id = self.fungible_esdt_token_id().get_token_id(); + self.tx() + .to(to) + .raw_call(ESDT_TRANSFER_FUNC_NAME) + .argument(&token_id) + .argument(&amount) + .gas(GAS_LIMIT_ESDT_TRANSFER) + .callback(self.callbacks().transfer_callback()) + .gas_for_callback(CALLBACK_ESDT_TRANSFER_GAS_LIMIT) + .register_promise(); + } + + #[promises_callback] + fn transfer_callback(&self, #[call_result] result: ManagedAsyncCallResult<()>) { + match result { + ManagedAsyncCallResult::Ok(()) => { + self.latest_transfer_result().set(TransferResult::Success); + }, + ManagedAsyncCallResult::Err(_) => { + self.latest_transfer_result().set(TransferResult::Fail); + }, + } + } + #[storage_mapper("fungibleEsdtTokenId")] fn fungible_esdt_token_id(&self) -> FungibleTokenMapper; #[storage_mapper("nonFungibleEsdtTokenId")] fn non_fungible_esdt_token_id(&self) -> NonFungibleTokenMapper; + + #[storage_mapper("latestTransferResult")] + fn latest_transfer_result(&self) -> SingleValueMapper; } diff --git a/contracts/feature-tests/composability/builtin-func-features/tests/esdt_transfer_promise_tests.rs b/contracts/feature-tests/composability/builtin-func-features/tests/esdt_transfer_promise_tests.rs index 3086a55605..67ebf02c01 100644 --- a/contracts/feature-tests/composability/builtin-func-features/tests/esdt_transfer_promise_tests.rs +++ b/contracts/feature-tests/composability/builtin-func-features/tests/esdt_transfer_promise_tests.rs @@ -1,4 +1,7 @@ -use builtin_func_features::{esdt_features::EsdtFeaturesModule, BuiltinFuncFeatures}; +use builtin_func_features::{ + esdt_features::{EsdtFeaturesModule, TransferResult}, + BuiltinFuncFeatures, +}; use multiversx_sc::{codec::Empty, types::Address}; use multiversx_sc_scenario::{ imports::{BlockchainStateWrapper, ContractObjWrapper}, @@ -86,3 +89,37 @@ fn transfer_fungible_promise_no_callback_test() { &rust_biguint!(0), ); } + +#[test] +fn transfer_fungible_promise_with_callback_test() { + let mut setup = BuiltInFuncFeaturesSetup::new(builtin_func_features::contract_obj); + let user_addr = setup.user.clone(); + setup + .b_mock + .execute_tx(&setup.user, &setup.sc_wrapper, &rust_biguint!(0), |sc| { + sc.transfer_fungible_promise_with_callback( + managed_address!(&user_addr), + managed_biguint!(INIT_BALANCE), + ); + }) + .assert_ok(); + + setup + .b_mock + .check_esdt_balance(&setup.user, FUNGIBLE_TOKEN_ID, &rust_biguint!(INIT_BALANCE)); + setup.b_mock.check_esdt_balance( + setup.sc_wrapper.address_ref(), + FUNGIBLE_TOKEN_ID, + &rust_biguint!(0), + ); + + setup + .b_mock + .execute_query(&setup.sc_wrapper, |sc| { + assert!(matches!( + sc.latest_transfer_result().get(), + TransferResult::Success + )); + }) + .assert_ok(); +} From 6fe9d6eb8374a1612287d3b91912fbee466e0417 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 13 Jan 2025 08:35:25 +0200 Subject: [PATCH 3/3] fix wrong format --- .../composability/builtin-func-features/src/esdt_features.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/feature-tests/composability/builtin-func-features/src/esdt_features.rs b/contracts/feature-tests/composability/builtin-func-features/src/esdt_features.rs index 817d53b1db..bcdca0ceca 100644 --- a/contracts/feature-tests/composability/builtin-func-features/src/esdt_features.rs +++ b/contracts/feature-tests/composability/builtin-func-features/src/esdt_features.rs @@ -3,7 +3,7 @@ multiversx_sc::derive_imports!(); static ESDT_TRANSFER_FUNC_NAME: &[u8] = b"ESDTTransfer"; -const GAS_LIMIT_ESDT_TRANSFER: u64 = 50_0000; +const GAS_LIMIT_ESDT_TRANSFER: u64 = 500_000; const CALLBACK_ESDT_TRANSFER_GAS_LIMIT: u64 = 100_000; #[derive(TopEncode, TopDecode)]