// The purpose of this test is to directly showcase how the various // API traits are being used, without the aid of macros. // All this code is of course always macro-generated. // // Since it is more difficult to debug macros directly, // it is helpful to keep this test as a reference for macro development // and maintenance. #![allow(unused)] use multiversx_sc::{ contract_base::ProxyObjNew, types::{BigInt, ManagedAddress}, }; use multiversx_sc_scenario::api::{SingleTxApi, StaticApi}; use crate::module_1::VersionModule; mod module_1 { multiversx_sc::imports!(); ///////////////////////////////////////////////////////////////////////////////////////////////// //////// CONTRACT TRAIT ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// pub trait VersionModule: multiversx_sc::contract_base::ContractBase + Sized { fn version(&self) -> BigInt; fn some_async(&self); fn callback(&self); } ///////////////////////////////////////////////////////////////////////////////////////////////// //////// AUTO-IMPLEMENTED METHODS /////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// pub trait AutoImpl: multiversx_sc::contract_base::ContractBase {} impl VersionModule for C where C: AutoImpl, { fn version(&self) -> BigInt { BigInt::from(100) } fn some_async(&self) { panic!("wooo") } fn callback(&self) {} } impl AutoImpl for multiversx_sc::contract_base::UniversalContractObj where A: multiversx_sc::api::VMApi { } pub trait EndpointWrappers: VersionModule + multiversx_sc::contract_base::ContractBase { #[inline] fn call_version(&self) { multiversx_sc::io::call_value_init::not_payable::(); let result = self.version(); multiversx_sc::io::finish_multi::(&result) } fn call_some_async(&self) { self.some_async(); multiversx_sc::io::finish_multi::(&()) } fn call(&self, fn_name: &str) -> bool { if match fn_name { "callBack" => { self.callback(); return true; }, "version" => { self.call_version(); true }, _other => false, } { return true; } false } } impl EndpointWrappers for multiversx_sc::contract_base::UniversalContractObj where A: multiversx_sc::api::VMApi { } pub struct AbiProvider {} impl multiversx_sc::contract_base::ContractAbiProvider for AbiProvider { type Api = multiversx_sc::api::uncallable::UncallableApi; fn abi() -> multiversx_sc::abi::ContractAbi { multiversx_sc::abi::ContractAbi::default() } } pub trait ProxyTrait: multiversx_sc::contract_base::ProxyObjBase + Sized { #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] fn version( &mut self, ) -> multiversx_sc::types::Tx< multiversx_sc::types::TxScEnv, (), Self::To, (), (), multiversx_sc::types::FunctionCall, multiversx_sc::types::OriginalResultMarker>, > { multiversx_sc::types::TxBaseWithEnv::new_tx_from_sc() .to(self.extract_proxy_to()) .original_result() .raw_call("version") } } } mod sampler_adder_proxy { #![allow(dead_code)] #![allow(clippy::all)] use multiversx_sc::proxy_imports::*; pub struct AdderProxy; impl TxProxyTrait for AdderProxy where Env: TxEnv, From: TxFrom, To: TxTo, Gas: TxGas, { type TxProxyMethods = AdderProxyMethods; fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { AdderProxyMethods { wrapped_tx: tx } } } pub struct AdderProxyMethods where Env: TxEnv, From: TxFrom, To: TxTo, Gas: TxGas, { wrapped_tx: Tx, } #[rustfmt::skip] impl AdderProxyMethods where Env: TxEnv, Env::Api: VMApi, From: TxFrom, Gas: TxGas, { pub fn init>>( self, initial_value: Arg0, ) -> TxTypedDeploy { self.wrapped_tx .payment(NotPayable) .raw_deploy() .argument(&initial_value) .original_result() } } #[rustfmt::skip] impl AdderProxyMethods where Env: TxEnv, Env::Api: VMApi, From: TxFrom, To: TxTo, Gas: TxGas, { pub fn upgrade>>( self, initial_value: Arg0, ) -> TxTypedUpgrade { self.wrapped_tx .payment(NotPayable) .raw_upgrade() .argument(&initial_value) .original_result() } } #[rustfmt::skip] impl AdderProxyMethods where Env: TxEnv, Env::Api: VMApi, From: TxFrom, To: TxTo, Gas: TxGas, { pub fn sum( self, ) -> TxTypedCall> { self.wrapped_tx.payment(NotPayable).raw_call("getSum").original_result() } /// Add desired amount to the storage variable. pub fn add>>( self, value: Arg0, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) .raw_call("add") .argument(&value) .original_result() } } } mod sample_adder { multiversx_sc::imports!(); ///////////////////////////////////////////////////////////////////////////////////////////////// //////// CONTRACT TRAIT ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// pub trait Adder: super::module_1::VersionModule + multiversx_sc::contract_base::ContractBase + Sized { #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] fn init(&self, initial_value: multiversx_sc::types::BigUint) { self.sum().set(initial_value); } #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] fn upgrade(&self, initial_value: multiversx_sc::types::BigUint) { self.init(initial_value); } /// Add desired amount to the storage variable. #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] fn add(&self, value: multiversx_sc::types::BigUint) { self.sum().update(|sum| *sum += value); } #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] fn sum(&self) -> SingleValueMapper>; } ///////////////////////////////////////////////////////////////////////////////////////////////// //////// AUTO-IMPLEMENTED METHODS /////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// pub trait AutoImpl: multiversx_sc::contract_base::ContractBase {} // impl super::module_1::AutoImpl for C where C: AutoImpl {} impl Adder for C where C: AutoImpl + super::module_1::AutoImpl, { #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] fn sum(&self) -> SingleValueMapper> { let mut ___key___ = multiversx_sc::storage::StorageKey::::new(&b"sum"[..]); , > as multiversx_sc::storage::mappers::StorageMapper>::new(___key___) } } impl AutoImpl for multiversx_sc::contract_base::UniversalContractObj where A: multiversx_sc::api::VMApi { } pub trait EndpointWrappers: Adder + multiversx_sc::contract_base::ContractBase + super::module_1::EndpointWrappers { #[inline] fn call_sum(&self) { ::init_static(); multiversx_sc::io::call_value_init::not_payable::(); let () = multiversx_sc::io::load_endpoint_args::(()); let result = self.sum(); multiversx_sc::io::finish_multi::(&result); } #[inline] fn call_init(&self) { ::init_static(); multiversx_sc::io::call_value_init::not_payable::(); let (initial_value, ()) = multiversx_sc::io::load_endpoint_args::< Self::Api, (multiversx_sc::types::BigUint, ()), >(("initial_value", ())); self.init(initial_value); } #[inline] fn call_upgrade(&self) { ::init_static(); multiversx_sc::io::call_value_init::not_payable::(); let (initial_value, ()) = multiversx_sc::io::load_endpoint_args::< Self::Api, (multiversx_sc::types::BigUint, ()), >(("initial_value", ())); self.upgrade(initial_value); } #[inline] fn call_add(&self) { ::init_static(); multiversx_sc::io::call_value_init::not_payable::(); let (value, ()) = multiversx_sc::io::load_endpoint_args::< Self::Api, (multiversx_sc::types::BigUint, ()), >(("value", ())); self.add(value); } fn call(&self, fn_name: &str) -> bool { if match fn_name { "callBack" => { self::EndpointWrappers::callback(self); return true; }, "init" if ::external_view_init_override() => { multiversx_sc::external_view_contract::external_view_contract_constructor::< Self::Api, >(); return true; }, "getSum" => { self.call_sum(); true }, "init" if !::external_view_init_override() => { self.call_init(); true }, "upgrade" => { self.call_upgrade(); true }, "add" => { self.call_add(); true }, other => false, } { return true; } false } fn callback_selector( &self, mut ___cb_closure___: multiversx_sc::types::CallbackClosureForDeser, ) -> multiversx_sc::types::CallbackSelectorResult { multiversx_sc::types::CallbackSelectorResult::NotProcessed(___cb_closure___) } fn callback(&self) {} } impl EndpointWrappers for multiversx_sc::contract_base::UniversalContractObj where A: multiversx_sc::api::VMApi { } pub struct AbiProvider {} impl multiversx_sc::contract_base::ContractAbiProvider for AbiProvider { type Api = multiversx_sc::api::uncallable::UncallableApi; fn abi() -> multiversx_sc::abi::ContractAbi { let mut contract_abi = multiversx_sc::abi::ContractAbi::new( multiversx_sc::abi::BuildInfoAbi { contract_crate: multiversx_sc::abi::ContractCrateBuildAbi { name: "adder", version: "0.0.0", git_version: "", }, framework: multiversx_sc::abi::FrameworkBuildAbi::create(), }, &[ "One of the simplest smart contracts possible,", "it holds a single variable in storage, which anyone can increment.", ], "Adder", false, ); let mut endpoint_abi = multiversx_sc::abi::EndpointAbi::new( "getSum", "sum", multiversx_sc::abi::EndpointMutabilityAbi::Readonly, multiversx_sc::abi::EndpointTypeAbi::Endpoint, ); endpoint_abi .add_output::< SingleValueMapper>, >(&[]); contract_abi .add_type_descriptions::< SingleValueMapper>, >(); contract_abi.endpoints.push(endpoint_abi); let mut endpoint_abi = multiversx_sc::abi::EndpointAbi::new( "init", "init", multiversx_sc::abi::EndpointMutabilityAbi::Mutable, multiversx_sc::abi::EndpointTypeAbi::Init, ); endpoint_abi.add_input::>("initial_value"); contract_abi.add_type_descriptions::>(); contract_abi.constructors.push(endpoint_abi); let mut endpoint_abi = multiversx_sc::abi::EndpointAbi::new( "upgrade", "upgrade", multiversx_sc::abi::EndpointMutabilityAbi::Mutable, multiversx_sc::abi::EndpointTypeAbi::Upgrade, ); endpoint_abi.add_input::>("initial_value"); contract_abi.add_type_descriptions::>(); contract_abi.upgrade_constructors.push(endpoint_abi); let mut endpoint_abi = multiversx_sc::abi::EndpointAbi::new( "add", "add", multiversx_sc::abi::EndpointMutabilityAbi::Mutable, multiversx_sc::abi::EndpointTypeAbi::Endpoint, ) .with_docs("Add desired amount to the storage variable."); endpoint_abi.add_input::>("value"); contract_abi.add_type_descriptions::>(); contract_abi.endpoints.push(endpoint_abi); contract_abi } } #[allow(non_snake_case)] pub mod __wasm__endpoints__ { use super::EndpointWrappers; pub fn sum() where A: multiversx_sc::api::VMApi, { super::EndpointWrappers::call_sum( &multiversx_sc::contract_base::UniversalContractObj::::new(), ); } pub fn init() where A: multiversx_sc::api::VMApi, { super::EndpointWrappers::call_init( &multiversx_sc::contract_base::UniversalContractObj::::new(), ); } pub fn upgrade() where A: multiversx_sc::api::VMApi, { super::EndpointWrappers::call_upgrade( &multiversx_sc::contract_base::UniversalContractObj::::new(), ); } pub fn add() where A: multiversx_sc::api::VMApi, { super::EndpointWrappers::call_add( &multiversx_sc::contract_base::UniversalContractObj::::new(), ); } pub fn callBack() where A: multiversx_sc::api::VMApi, { super::EndpointWrappers::callback( &multiversx_sc::contract_base::UniversalContractObj::::new(), ); } } pub trait ProxyTrait: multiversx_sc::contract_base::ProxyObjBase + super::module_1::ProxyTrait { #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] fn sum( &mut self, ) -> multiversx_sc::types::Tx< multiversx_sc::types::TxScEnv, (), Self::To, (), (), multiversx_sc::types::FunctionCall, multiversx_sc::types::OriginalResultMarker< SingleValueMapper>, >, > { multiversx_sc::types::TxBaseWithEnv::new_tx_from_sc() .to(self.extract_proxy_to()) .original_result() .raw_call("getSum") } #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] fn init>>( &mut self, initial_value: Arg0, ) -> multiversx_sc::types::Tx< multiversx_sc::types::TxScEnv, (), Self::To, (), (), multiversx_sc::types::DeployCall, ()>, multiversx_sc::types::OriginalResultMarker<()>, > { multiversx_sc::types::TxBaseWithEnv::new_tx_from_sc() .raw_deploy() .argument(&initial_value) .original_result() .to(self.extract_proxy_to()) } #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] fn upgrade< Arg0: multiversx_sc::types::ProxyArg>, >( &mut self, initial_value: Arg0, ) -> multiversx_sc::types::Tx< multiversx_sc::types::TxScEnv, (), Self::To, (), (), multiversx_sc::types::FunctionCall, multiversx_sc::types::OriginalResultMarker<()>, > { multiversx_sc::types::TxBaseWithEnv::new_tx_from_sc() .to(self.extract_proxy_to()) .original_result() .raw_call("upgrade") .argument(&initial_value) } #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] fn add>>( &mut self, value: Arg0, ) -> multiversx_sc::types::Tx< multiversx_sc::types::TxScEnv, (), Self::To, (), (), multiversx_sc::types::FunctionCall, multiversx_sc::types::OriginalResultMarker<()>, > { multiversx_sc::types::TxBaseWithEnv::new_tx_from_sc() .to(self.extract_proxy_to()) .original_result() .raw_call("add") .argument(&value) } } ///////////////////////////////////////////////////////////////////////////////////////////////// //////// CONTRACT OBJECT //////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// pub struct ContractObj where A: multiversx_sc::api::VMApi, { _phantom: core::marker::PhantomData, } ///////////////////////////////////////////////////////////////////////////////////////////////// //////// CONTRACT OBJECT as CONTRACT BASE /////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// impl multiversx_sc::contract_base::ContractBase for ContractObj where A: multiversx_sc::api::VMApi, { type Api = A; } impl super::module_1::AutoImpl for ContractObj where A: multiversx_sc::api::VMApi {} impl AutoImpl for ContractObj where A: multiversx_sc::api::VMApi {} impl super::module_1::EndpointWrappers for ContractObj where A: multiversx_sc::api::VMApi {} impl EndpointWrappers for ContractObj where A: multiversx_sc::api::VMApi {} impl multiversx_sc::contract_base::CallableContract for ContractObj where A: multiversx_sc::api::VMApi, { fn call(&self, fn_name: &str) -> bool { EndpointWrappers::call(self, fn_name) } } pub fn contract_obj() -> ContractObj where A: multiversx_sc::api::VMApi, { ContractObj { _phantom: core::marker::PhantomData, } } pub struct ContractBuilder; impl multiversx_sc::contract_base::CallableContractBuilder for self::ContractBuilder { fn new_contract_obj( &self, ) -> multiversx_sc::types::heap::Box { multiversx_sc::types::heap::Box::new(ContractObj:: { _phantom: core::marker::PhantomData, }) } } pub struct Proxy where A: multiversx_sc::api::VMApi + 'static, { _phantom: core::marker::PhantomData, } impl multiversx_sc::contract_base::ProxyObjBase for Proxy where A: multiversx_sc::api::VMApi + 'static, { type Api = A; type To = (); fn extract_opt_address( &mut self, ) -> multiversx_sc::types::ManagedOption< Self::Api, multiversx_sc::types::ManagedAddress, > { multiversx_sc::types::ManagedOption::none() } fn extract_address(&mut self) -> multiversx_sc::types::ManagedAddress { multiversx_sc::api::ErrorApiImpl::signal_error( &::error_api_impl(), multiversx_sc::err_msg::RECIPIENT_ADDRESS_NOT_SET.as_bytes(), ) } fn extract_proxy_to(&mut self) -> Self::To {} } impl multiversx_sc::contract_base::ProxyObjNew for Proxy where A: multiversx_sc::api::VMApi + 'static, { type ProxyTo = ProxyTo; fn new_proxy_obj() -> Self { Proxy { _phantom: core::marker::PhantomData, } } fn contract( mut self, address: multiversx_sc::types::ManagedAddress, ) -> Self::ProxyTo { ProxyTo { address: multiversx_sc::types::ManagedOption::some(address), } } } pub struct ProxyTo where A: multiversx_sc::api::VMApi + 'static, { pub address: multiversx_sc::types::ManagedOption>, } impl multiversx_sc::contract_base::ProxyObjBase for ProxyTo where A: multiversx_sc::api::VMApi + 'static, { type Api = A; type To = multiversx_sc::types::ManagedAddress; fn extract_opt_address( &mut self, ) -> multiversx_sc::types::ManagedOption< Self::Api, multiversx_sc::types::ManagedAddress, > { core::mem::replace( &mut self.address, multiversx_sc::types::ManagedOption::none(), ) } fn extract_address(&mut self) -> multiversx_sc::types::ManagedAddress { let address = core::mem::replace( &mut self.address, multiversx_sc::types::ManagedOption::none(), ); address.unwrap_or_sc_panic(multiversx_sc::err_msg::RECIPIENT_ADDRESS_NOT_SET) } fn extract_proxy_to(&mut self) -> Self::To { self.extract_address() } } impl super::module_1::ProxyTrait for Proxy where A: multiversx_sc::api::VMApi {} impl super::module_1::ProxyTrait for ProxyTo where A: multiversx_sc::api::VMApi {} impl ProxyTrait for Proxy where A: multiversx_sc::api::VMApi {} impl ProxyTrait for ProxyTo where A: multiversx_sc::api::VMApi {} pub struct CallbackProxyObj where A: multiversx_sc::api::VMApi + 'static, { _phantom: core::marker::PhantomData, } impl multiversx_sc::contract_base::CallbackProxyObjBase for CallbackProxyObj where A: multiversx_sc::api::VMApi + 'static, { type Api = A; fn new_cb_proxy_obj() -> Self { CallbackProxyObj { _phantom: core::marker::PhantomData, } } } pub trait CallbackProxy: multiversx_sc::contract_base::CallbackProxyObjBase + Sized { fn my_callback(self, caller: &Address) -> multiversx_sc::types::CallbackClosure { let mut ___callback_call___ = multiversx_sc::types::new_callback_call::("my_callback"); ___callback_call___.push_endpoint_arg(caller); ___callback_call___ } } impl self::CallbackProxy for CallbackProxyObj where A: multiversx_sc::api::VMApi + 'static {} } #[test] fn contract_without_macros_basic() { use sample_adder::{Adder, EndpointWrappers, ProxyTrait}; let adder = sample_adder::contract_obj::(); adder.init(multiversx_sc::types::BigUint::from(5u32)); assert_eq!(multiversx_sc::types::BigUint::from(5u32), adder.sum().get()); adder.add(multiversx_sc::types::BigUint::from(7u32)); assert_eq!( multiversx_sc::types::BigUint::from(12u32), adder.sum().get() ); assert_eq!(BigInt::from(100), adder.version()); assert!(!adder.call("invalid_endpoint")); assert!(adder.call("getSum")); let mut own_proxy = sample_adder::Proxy::::new_proxy_obj().contract(ManagedAddress::zero()); let _ = own_proxy.sum(); let _ = multiversx_sc_meta_lib::abi_json::contract_abi::(); } fn world() -> multiversx_sc_scenario::ScenarioWorld { let mut blockchain = multiversx_sc_scenario::ScenarioWorld::new(); blockchain.set_current_dir_from_workspace("framework/scenario"); blockchain.register_contract( "mxsc:../../contracts/examples/adder/output/adder.mxsc.json", sample_adder::ContractBuilder, ); blockchain } #[test] fn contract_without_macros_scenario() { world().run("../../contracts/examples/adder/scenarios/adder.scen.json"); }