diff --git a/Cargo.toml b/Cargo.toml index 3cc34e3bd4..43a83719f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -133,6 +133,7 @@ members = [ "contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child", "contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/meta", "contracts/feature-tests/composability/forwarder", + "contracts/feature-tests/composability/forwarder-interactor", "contracts/feature-tests/composability/forwarder/meta", "contracts/feature-tests/composability/forwarder-legacy", "contracts/feature-tests/composability/forwarder-legacy/meta", diff --git a/chain/core/src/builtin_func_names.rs b/chain/core/src/builtin_func_names.rs index 108ed29016..9ab2b202ed 100644 --- a/chain/core/src/builtin_func_names.rs +++ b/chain/core/src/builtin_func_names.rs @@ -14,3 +14,8 @@ pub const SET_USERNAME_FUNC_NAME: &str = "SetUserName"; pub const MIGRATE_USERNAME_FUNC_NAME: &str = "migrateUserName"; pub const DELETE_USERNAME_FUNC_NAME: &str = "DeleteUserName"; pub const UPGRADE_CONTRACT_FUNC_NAME: &str = "upgradeContract"; +pub const ESDT_MODIFY_ROYALTIES_FUNC_NAME: &str = "ESDTModifyRoyalties"; +pub const ESDT_SET_NEW_URIS_FUNC_NAME: &str = "ESDTSetNewURIs"; +pub const ESDT_MODIFY_CREATOR_FUNC_NAME: &str = "ESDTModifyCreator"; +pub const ESDT_METADATA_RECREATE_FUNC_NAME: &str = "ESDTMetaDataRecreate"; +pub const ESDT_METADATA_UPDATE_FUNC_NAME: &str = "ESDTMetaDataUpdate"; diff --git a/chain/core/src/types/flags/esdt_local_role.rs b/chain/core/src/types/flags/esdt_local_role.rs index 048d3876ce..3634e5d891 100644 --- a/chain/core/src/types/flags/esdt_local_role.rs +++ b/chain/core/src/types/flags/esdt_local_role.rs @@ -13,6 +13,11 @@ const ESDT_ROLE_NFT_BURN: &str = "ESDTRoleNFTBurn"; const ESDT_ROLE_NFT_ADD_URI: &str = "ESDTRoleNFTAddURI"; const ESDT_ROLE_NFT_UPDATE_ATTRIBUTES: &str = "ESDTRoleNFTUpdateAttributes"; const ESDT_ROLE_TRANSFER: &str = "ESDTTransferRole"; +const ESDT_ROLE_SET_NEW_URI: &str = "ESDTRoleSetNewURI"; +const ESDT_ROLE_MODIFY_ROYALTIES: &str = "ESDTRoleModifyRoyalties"; +const ESDT_ROLE_MODIFY_CREATOR: &str = "ESDTRoleModifyCreator"; +const ESDT_ROLE_NFT_RECREATE: &str = "ESDTRoleNFTRecreate"; +const ESDT_ROLE_NFT_UPDATE: &str = "ESDTRoleNFTUpdate"; #[derive(TopDecode, TopEncode, NestedDecode, NestedEncode, Clone, PartialEq, Eq, Debug, Copy)] pub enum EsdtLocalRole { @@ -25,6 +30,11 @@ pub enum EsdtLocalRole { NftAddUri, NftUpdateAttributes, Transfer, + SetNewUri, + ModifyRoyalties, + ModifyCreator, + NftRecreate, + NftUpdate, } impl EsdtLocalRole { @@ -39,6 +49,11 @@ impl EsdtLocalRole { Self::NftAddUri => 6, Self::NftUpdateAttributes => 7, Self::Transfer => 8, + Self::SetNewUri => 9, + Self::ModifyRoyalties => 10, + Self::ModifyCreator => 11, + Self::NftRecreate => 12, + Self::NftUpdate => 13, } } @@ -57,6 +72,11 @@ impl EsdtLocalRole { Self::NftAddUri => ESDT_ROLE_NFT_ADD_URI, Self::NftUpdateAttributes => ESDT_ROLE_NFT_UPDATE_ATTRIBUTES, Self::Transfer => ESDT_ROLE_TRANSFER, + Self::SetNewUri => ESDT_ROLE_SET_NEW_URI, + Self::ModifyRoyalties => ESDT_ROLE_MODIFY_ROYALTIES, + Self::ModifyCreator => ESDT_ROLE_MODIFY_CREATOR, + Self::NftRecreate => ESDT_ROLE_NFT_RECREATE, + Self::NftUpdate => ESDT_ROLE_NFT_UPDATE, } } @@ -71,13 +91,18 @@ impl EsdtLocalRole { Self::NftAddUri => EsdtLocalRoleFlags::NFT_ADD_URI, Self::NftUpdateAttributes => EsdtLocalRoleFlags::NFT_UPDATE_ATTRIBUTES, Self::Transfer => EsdtLocalRoleFlags::TRANSFER, + Self::SetNewUri => EsdtLocalRoleFlags::SET_NEW_URI, + Self::ModifyRoyalties => EsdtLocalRoleFlags::MODIFY_ROYALTIES, + Self::ModifyCreator => EsdtLocalRoleFlags::MODIFY_CREATOR, + Self::NftRecreate => EsdtLocalRoleFlags::NFT_RECREATE, + Self::NftUpdate => EsdtLocalRoleFlags::NFT_UPDATE, } } } // TODO: can be done with macros, but I didn't find a public library that does it and is no_std // we can implement it, it's easy -const ALL_ROLES: [EsdtLocalRole; 8] = [ +const ALL_ROLES: [EsdtLocalRole; 13] = [ EsdtLocalRole::Mint, EsdtLocalRole::Burn, EsdtLocalRole::NftCreate, @@ -86,6 +111,11 @@ const ALL_ROLES: [EsdtLocalRole; 8] = [ EsdtLocalRole::NftAddUri, EsdtLocalRole::NftUpdateAttributes, EsdtLocalRole::Transfer, + EsdtLocalRole::SetNewUri, + EsdtLocalRole::ModifyRoyalties, + EsdtLocalRole::ModifyCreator, + EsdtLocalRole::NftRecreate, + EsdtLocalRole::NftUpdate, ]; impl EsdtLocalRole { @@ -106,6 +136,11 @@ impl From for EsdtLocalRole { 6 => Self::NftAddUri, 7 => Self::NftUpdateAttributes, 8 => Self::Transfer, + 9 => Self::SetNewUri, + 10 => Self::ModifyRoyalties, + 11 => Self::ModifyCreator, + 12 => Self::NftRecreate, + 13 => Self::NftUpdate, _ => Self::None, } } @@ -130,6 +165,16 @@ impl<'a> From<&'a [u8]> for EsdtLocalRole { Self::NftUpdateAttributes } else if byte_slice == ESDT_ROLE_TRANSFER.as_bytes() { Self::Transfer + } else if byte_slice == ESDT_ROLE_SET_NEW_URI.as_bytes() { + Self::SetNewUri + } else if byte_slice == ESDT_ROLE_MODIFY_ROYALTIES.as_bytes() { + Self::ModifyRoyalties + } else if byte_slice == ESDT_ROLE_MODIFY_CREATOR.as_bytes() { + Self::ModifyCreator + } else if byte_slice == ESDT_ROLE_NFT_RECREATE.as_bytes() { + Self::NftRecreate + } else if byte_slice == ESDT_ROLE_NFT_UPDATE.as_bytes() { + Self::NftUpdate } else { Self::None } diff --git a/chain/core/src/types/flags/esdt_local_role_flags.rs b/chain/core/src/types/flags/esdt_local_role_flags.rs index 29be64aba2..cac9aa6795 100644 --- a/chain/core/src/types/flags/esdt_local_role_flags.rs +++ b/chain/core/src/types/flags/esdt_local_role_flags.rs @@ -15,6 +15,11 @@ bitflags! { const NFT_ADD_URI = 0b00100000; const NFT_UPDATE_ATTRIBUTES = 0b01000000; const TRANSFER = 0b10000000; + const SET_NEW_URI = 0b00000001_00000000; + const MODIFY_ROYALTIES = 0b00000010_00000000; + const MODIFY_CREATOR = 0b00000100_00000000; + const NFT_RECREATE = 0b00001000_00000000; + const NFT_UPDATE = 0b00010000_00000000; } } diff --git a/chain/core/src/types/flags/esdt_token_type.rs b/chain/core/src/types/flags/esdt_token_type.rs index 74db07c9a6..bfa65f604a 100644 --- a/chain/core/src/types/flags/esdt_token_type.rs +++ b/chain/core/src/types/flags/esdt_token_type.rs @@ -9,6 +9,9 @@ const ESDT_TYPE_FUNGIBLE: &[u8] = b"FungibleESDT"; const ESDT_TYPE_NON_FUNGIBLE: &[u8] = b"NonFungibleESDT"; const ESDT_TYPE_SEMI_FUNGIBLE: &[u8] = b"SemiFungibleESDT"; const ESDT_TYPE_META: &[u8] = b"MetaESDT"; +const ESDT_TYPE_DYNAMIC_NON_FUNGIBLE: &[u8] = b"DynamicNonFungibleESDT"; +const ESDT_TYPE_DYNAMIC_SEMI_FUNGIBLE: &[u8] = b"DynamicSemiFungibleESDT"; +const ESDT_TYPE_DYNAMIC_META: &[u8] = b"DynamicMetaESDT"; const ESDT_TYPE_INVALID: &[u8] = &[]; // Note: In the current implementation, SemiFungible is never returned @@ -19,6 +22,9 @@ pub enum EsdtTokenType { NonFungible, SemiFungible, Meta, + DynamicNFT, + DynamicSFT, + DynamicMeta, Invalid, } @@ -37,7 +43,10 @@ impl EsdtTokenType { Self::NonFungible => 1, Self::SemiFungible => 2, Self::Meta => 3, - Self::Invalid => 4, + Self::DynamicNFT => 4, + Self::DynamicSFT => 5, + Self::DynamicMeta => 6, + Self::Invalid => 7, } } @@ -47,6 +56,9 @@ impl EsdtTokenType { Self::NonFungible => ESDT_TYPE_NON_FUNGIBLE, Self::SemiFungible => ESDT_TYPE_SEMI_FUNGIBLE, Self::Meta => ESDT_TYPE_META, + Self::DynamicNFT => ESDT_TYPE_DYNAMIC_NON_FUNGIBLE, + Self::DynamicSFT => ESDT_TYPE_DYNAMIC_SEMI_FUNGIBLE, + Self::DynamicMeta => ESDT_TYPE_DYNAMIC_META, Self::Invalid => ESDT_TYPE_INVALID, } } @@ -60,6 +72,9 @@ impl From for EsdtTokenType { 1 => Self::NonFungible, 2 => Self::SemiFungible, 3 => Self::Meta, + 4 => Self::DynamicNFT, + 5 => Self::DynamicSFT, + 6 => Self::DynamicMeta, _ => Self::Invalid, } } @@ -76,6 +91,12 @@ impl<'a> From<&'a [u8]> for EsdtTokenType { Self::SemiFungible } else if byte_slice == ESDT_TYPE_META { Self::Meta + } else if byte_slice == ESDT_TYPE_DYNAMIC_NON_FUNGIBLE { + Self::DynamicNFT + } else if byte_slice == ESDT_TYPE_DYNAMIC_SEMI_FUNGIBLE { + Self::DynamicSFT + } else if byte_slice == ESDT_TYPE_DYNAMIC_META { + Self::DynamicMeta } else { Self::Invalid } diff --git a/contracts/feature-tests/composability/forwarder-interactor/.gitignore b/contracts/feature-tests/composability/forwarder-interactor/.gitignore new file mode 100644 index 0000000000..5a64d09a70 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/.gitignore @@ -0,0 +1,2 @@ +# Pem files are used for interactions, but shouldn't be committed +*.pem diff --git a/contracts/feature-tests/composability/forwarder-interactor/Cargo.toml b/contracts/feature-tests/composability/forwarder-interactor/Cargo.toml new file mode 100644 index 0000000000..b8dce626fc --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "forwarder-interact" +version = "0.0.0" +authors = ["you"] +edition = "2021" +publish = false + +[[bin]] +name = "forwarder-interact" +path = "src/interactor_main.rs" + +[lib] +path = "src/interact.rs" + +[dependencies.forwarder] +path = "../forwarder" + +[dependencies.multiversx-sc-snippets] +version = "0.54.5" +path = "../../../../framework/snippets" + +[dependencies.multiversx-sc] +version = "0.54.5" +path = "../../../../framework/base" + +[dependencies] +clap = { version = "4.4.7", features = ["derive"] } +serde = { version = "1.0", features = ["derive"] } +toml = "0.8.6" + +[features] +chain-simulator-tests = [] diff --git a/contracts/feature-tests/composability/forwarder-interactor/config.toml b/contracts/feature-tests/composability/forwarder-interactor/config.toml new file mode 100644 index 0000000000..97acd5a5c6 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/config.toml @@ -0,0 +1,7 @@ + +# chain_type = 'simulator' +# gateway_uri = 'http://localhost:8085' + +chain_type = 'real' +gateway_uri = 'https://devnet-gateway.multiversx.com' + diff --git a/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_builtin_scenario.scen.json b/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_builtin_scenario.scen.json new file mode 100644 index 0000000000..29820bc45e --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_builtin_scenario.scen.json @@ -0,0 +1,318 @@ +{ + "steps": [ + { + "step": "setState", + "accounts": { + "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1": { + "nonce": "11899", + "balance": "100" + } + }, + "newAddresses": [ + { + "creatorAddress": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "creatorNonce": "11899", + "newAddress": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "contractCode": "mxsc:../../forwarder/output/forwarder.mxsc.json", + "arguments": [], + "gasLimit": "300000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newTokenIdentifiers": [ + "TEST-d49726" + ] + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv", + "egldValue": "50000000000000000", + "function": "issue_dynamic_token", + "arguments": [ + "0x544553544e4654", + "0x54455354", + "0x04", + "0x" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newTokenIdentifiers": [ + "TEST-38e345" + ] + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv", + "egldValue": "50000000000000000", + "function": "issue_dynamic_token", + "arguments": [ + "0x544553544e4654", + "0x54455354", + "0x05", + "0x" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newTokenIdentifiers": [ + "TEST-f781d6" + ] + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv", + "egldValue": "50000000000000000", + "function": "issue_dynamic_token", + "arguments": [ + "0x544553544e4654", + "0x54455354", + "0x06", + "0x12" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newTokenIdentifiers": [ + "TEST-2b25f7" + ] + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv", + "egldValue": "50000000000000000", + "function": "issue_token_all_roles", + "arguments": [ + "0x544553544e4654", + "0x54455354", + "0x06", + "0x" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newTokenIdentifiers": [ + "TEST-d0c358" + ] + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv", + "egldValue": "50000000000000000", + "function": "issue_token_all_roles", + "arguments": [ + "0x544553544e4654", + "0x54455354", + "0x05", + "0x" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newTokenIdentifiers": [ + "TEST-712a3f" + ] + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv", + "egldValue": "50000000000000000", + "function": "issue_token_all_roles", + "arguments": [ + "0x544553544e4654", + "0x54455354", + "0x04", + "0x" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv", + "function": "lastIssuedToken", + "arguments": [] + }, + "expect": { + "out": [ + "0x544553542d373132613366" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv", + "function": "nft_create", + "arguments": [ + "0x544553542d373132613366", + "0x01", + "0x6d794e4654", + "0x1e", + "0x", + "0x010205", + "0x73616d706c655f757269" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [ + "0x01" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv", + "function": "modify_royalties", + "arguments": [ + "0x544553542d373132613366", + "0x01", + "0x14" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv", + "function": "set_new_uris", + "arguments": [ + "0x544553542d373132613366", + "0x01", + "0x7468697369616e7572692e636f6d" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv", + "function": "metadata_update", + "arguments": [ + "0x544553542d373132613366", + "0x01", + "0x544553544e4654", + "0x1e", + "0x6e65775f68617368", + "0x060708" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqwzty5wrdva7ymtwfrkj23ysdaauxx6j4d8sskh9qsv", + "function": "metadata_recreate", + "arguments": [ + "0x544553542d373132613366", + "0x01", + "0x544553544e4654", + "0x1e", + "0x6e65775f686173685f726563726561746564", + "0x080808" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + } + ] +} \ No newline at end of file diff --git a/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_change_to_dynamic_scenario.scen.json b/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_change_to_dynamic_scenario.scen.json new file mode 100644 index 0000000000..5833c698a2 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_change_to_dynamic_scenario.scen.json @@ -0,0 +1,179 @@ +{ + "steps": [ + { + "step": "setState", + "accounts": { + "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1": { + "nonce": "11911", + "balance": "100" + } + }, + "newAddresses": [ + { + "creatorAddress": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "creatorNonce": "11911", + "newAddress": "bech32:erd1qqqqqqqqqqqqqpgqkwwmszeln3cjlxewv0a3uwgxf2ver22rd8ssdgezus" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "contractCode": "mxsc:../../forwarder/output/forwarder.mxsc.json", + "arguments": [], + "gasLimit": "300000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newTokenIdentifiers": [ + "TEST-34ddd9" + ] + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqkwwmszeln3cjlxewv0a3uwgxf2ver22rd8ssdgezus", + "egldValue": "50000000000000000", + "function": "issue_token_all_roles", + "arguments": [ + "0x544553544e4654", + "0x54455354", + "0x01", + "0x" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newTokenIdentifiers": [ + "TEST-a0503d" + ] + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqkwwmszeln3cjlxewv0a3uwgxf2ver22rd8ssdgezus", + "egldValue": "50000000000000000", + "function": "issue_token_all_roles", + "arguments": [ + "0x544553544e4654", + "0x54455354", + "0x03", + "0x12" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "bech32:erd1qqqqqqqqqqqqqpgqkwwmszeln3cjlxewv0a3uwgxf2ver22rd8ssdgezus", + "function": "lastIssuedToken", + "arguments": [] + }, + "expect": { + "out": [ + "0x544553542d613035303364" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqkwwmszeln3cjlxewv0a3uwgxf2ver22rd8ssdgezus", + "function": "change_to_dynamic", + "arguments": [ + "0x544553542d613035303364" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newTokenIdentifiers": [ + "TEST-45f8e0" + ] + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqkwwmszeln3cjlxewv0a3uwgxf2ver22rd8ssdgezus", + "egldValue": "50000000000000000", + "function": "issue_token_all_roles", + "arguments": [ + "0x544553544e4654", + "0x54455354", + "0x02", + "0x12" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "bech32:erd1qqqqqqqqqqqqqpgqkwwmszeln3cjlxewv0a3uwgxf2ver22rd8ssdgezus", + "function": "lastIssuedToken", + "arguments": [] + }, + "expect": { + "out": [ + "0x544553542d343566386530" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqkwwmszeln3cjlxewv0a3uwgxf2ver22rd8ssdgezus", + "function": "change_to_dynamic", + "arguments": [ + "0x544553542d343566386530" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + } + ] +} \ No newline at end of file diff --git a/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_deploy_scenario.scen.json b/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_deploy_scenario.scen.json new file mode 100644 index 0000000000..d105846d4f --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_deploy_scenario.scen.json @@ -0,0 +1,34 @@ +{ + "steps": [ + { + "step": "setState", + "accounts": { + "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1": { + "nonce": "11920", + "balance": "100" + } + }, + "newAddresses": [ + { + "creatorAddress": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "creatorNonce": "11920", + "newAddress": "bech32:erd1qqqqqqqqqqqqqpgq3tjap9t5nnat46nwdz6mtyy60na7vptnd8ss7r0jp8" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "contractCode": "mxsc:../../forwarder/output/forwarder.mxsc.json", + "arguments": [], + "gasLimit": "300000000" + }, + "expect": { + "out": [], + "status": "0" + } + } + ] +} \ No newline at end of file diff --git a/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_modify_creator_scenario.scen.json b/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_modify_creator_scenario.scen.json new file mode 100644 index 0000000000..2319138ca6 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_modify_creator_scenario.scen.json @@ -0,0 +1,159 @@ +{ + "steps": [ + { + "step": "setState", + "accounts": { + "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1": { + "nonce": "11928", + "balance": "100" + } + }, + "newAddresses": [ + { + "creatorAddress": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "creatorNonce": "11928", + "newAddress": "bech32:erd1qqqqqqqqqqqqqpgqm6d7cp70y7ft6xe78f7np9agdm7vpce6d8sskuuxnu" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "contractCode": "mxsc:../../forwarder/output/forwarder.mxsc.json", + "arguments": [], + "gasLimit": "300000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newTokenIdentifiers": [ + "TEST-d3c4e5" + ] + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "egldValue": "50000000000000000", + "function": "registerDynamic", + "arguments": [ + "0x544553544e4654", + "0x54455354", + "0x4e4654" + ], + "gasLimit": "100000000" + }, + "expect": { + "out": [ + "0x544553542d643363346535" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "function": "setSpecialRole", + "arguments": [ + "0x544553542d643363346535", + "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "0x45534454526f6c654e4654437265617465" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "function": "ESDTNFTCreate", + "arguments": [ + "0x544553542d643363346535", + "0x01", + "0x6d794e4654", + "0x1e", + "0x", + "0x010203", + "0x" + ], + "gasLimit": "100000000" + }, + "expect": { + "out": [ + "0x01" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "function": "setSpecialRole", + "arguments": [ + "0x544553542d643363346535", + "0x00000000000000000500de9bec07cf2792bd1b3e3a7d3097a86efcc0e33a69e1", + "0x45534454526f6c654d6f6469667943726561746f72" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "transfer", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqm6d7cp70y7ft6xe78f7np9agdm7vpce6d8sskuuxnu", + "esdtValue": [ + { + "tokenIdentifier": "0x544553542d643363346535", + "nonce": "1", + "value": "1" + } + ], + "gasLimit": "5,000,000" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqm6d7cp70y7ft6xe78f7np9agdm7vpce6d8sskuuxnu", + "function": "modify_creator", + "arguments": [ + "0x544553542d643363346535", + "0x01" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + } + ] +} \ No newline at end of file diff --git a/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_update_token_scenario.scen.json b/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_update_token_scenario.scen.json new file mode 100644 index 0000000000..9724dab7d0 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/scenarios/forwarder_update_token_scenario.scen.json @@ -0,0 +1,93 @@ +{ + "steps": [ + { + "step": "setState", + "accounts": { + "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1": { + "nonce": "11917", + "balance": "100" + } + }, + "newAddresses": [ + { + "creatorAddress": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "creatorNonce": "11917", + "newAddress": "bech32:erd1qqqqqqqqqqqqqpgqyjhk2jz7rmv7hrdcnlzwtr3pcd69hw7nd8ssjv0ryz" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "contractCode": "mxsc:../../forwarder/output/forwarder.mxsc.json", + "arguments": [], + "gasLimit": "300000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newTokenIdentifiers": [ + "TEST-4ec598" + ] + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqyjhk2jz7rmv7hrdcnlzwtr3pcd69hw7nd8ssjv0ryz", + "egldValue": "50000000000000000", + "function": "issue_token_all_roles", + "arguments": [ + "0x544553544e4654", + "0x54455354", + "0x01", + "0x" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "bech32:erd1qqqqqqqqqqqqqpgqyjhk2jz7rmv7hrdcnlzwtr3pcd69hw7nd8ssjv0ryz", + "function": "lastIssuedToken", + "arguments": [] + }, + "expect": { + "out": [ + "0x544553542d346563353938" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "to": "bech32:erd1qqqqqqqqqqqqqpgqyjhk2jz7rmv7hrdcnlzwtr3pcd69hw7nd8ssjv0ryz", + "function": "update_token", + "arguments": [ + "0x544553542d346563353938" + ], + "gasLimit": "80000000" + }, + "expect": { + "out": [], + "status": "0" + } + } + ] +} \ No newline at end of file diff --git a/contracts/feature-tests/composability/forwarder-interactor/src/config.rs b/contracts/feature-tests/composability/forwarder-interactor/src/config.rs new file mode 100644 index 0000000000..4c4f034bb4 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/src/config.rs @@ -0,0 +1,57 @@ +#![allow(unused)] + +use serde::Deserialize; +use std::io::Read; + +/// Config file +const CONFIG_FILE: &str = "config.toml"; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum ChainType { + Real, + Simulator, +} + +/// Contract Interact configuration +#[derive(Debug, Deserialize)] +pub struct Config { + pub gateway_uri: String, + pub chain_type: ChainType, +} + +impl Default for Config { + fn default() -> Self { + Self::new() + } +} + +impl Config { + // Deserializes config from file + pub fn new() -> Self { + let mut file = std::fs::File::open(CONFIG_FILE).unwrap(); + let mut content = String::new(); + file.read_to_string(&mut content).unwrap(); + 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 { + match self.chain_type { + ChainType::Real => false, + ChainType::Simulator => true, + } + } +} diff --git a/contracts/feature-tests/composability/forwarder-interactor/src/interact.rs b/contracts/feature-tests/composability/forwarder-interactor/src/interact.rs new file mode 100644 index 0000000000..83921f981a --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/src/interact.rs @@ -0,0 +1,2105 @@ +#![allow(non_snake_case)] + +mod config; +mod proxy; + +pub use config::Config; +use multiversx_sc_snippets::imports::*; +pub use proxy::Color; +use serde::{Deserialize, Serialize}; +use std::{ + io::{Read, Write}, + path::Path, +}; + +const STATE_FILE: &str = "state.toml"; +pub const FORWARDER_DEPLOY_INTERACTOR_TRACE_PATH: &str = + "scenarios/forwarder_deploy_scenario.scen.json"; +pub const FORWARDER_BUILTIN_INTERACTOR_TRACE_PATH: &str = + "scenarios/forwarder_builtin_scenario.scen.json"; +pub const FORWARDER_CHANGE_TO_DYNAMIC_INTERACTOR_TRACE_PATH: &str = + "scenarios/forwarder_change_to_dynamic_scenario.scen.json"; +pub const FORWARDER_UPDATE_TOKEN_INTERACTOR_TRACE_PATH: &str = + "scenarios/forwarder_update_token_scenario.scen.json"; +pub const FORWARDER_MODIFY_CREATOR_INTERACTOR_TRACE_PATH: &str = + "scenarios/forwarder_modify_creator_scenario.scen.json"; + +pub async fn forwarder_cli() { + 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(Config::new(), None).await; + match cmd.as_str() { + "deploy" => interact.deploy().await, + "send_egld" => interact.send_egld().await, + "echo_arguments_sync" => interact.echo_arguments_sync().await, + "echo_arguments_sync_twice" => interact.echo_arguments_sync_twice().await, + "forward_sync_accept_funds" => interact.forward_sync_accept_funds().await, + "forward_sync_accept_funds_rh_egld" => interact.forward_sync_accept_funds_rh_egld().await, + "forward_sync_accept_funds_rh_single_esdt" => { + interact.forward_sync_accept_funds_rh_single_esdt().await + }, + "forward_sync_accept_funds_rh_multi_esdt" => { + interact.forward_sync_accept_funds_rh_multi_esdt().await + }, + "forward_sync_accept_funds_with_fees" => { + interact.forward_sync_accept_funds_with_fees().await + }, + "forward_sync_accept_funds_then_read" => { + interact.forward_sync_accept_funds_then_read().await + }, + "forward_sync_retrieve_funds" => interact.forward_sync_retrieve_funds().await, + "forward_sync_retrieve_funds_with_accept_func" => { + interact + .forward_sync_retrieve_funds_with_accept_func() + .await + }, + "accept_funds_func" => interact.accept_funds_func().await, + "forward_sync_accept_funds_multi_transfer" => { + interact.forward_sync_accept_funds_multi_transfer().await + }, + "echo_args_async" => interact.echo_args_async().await, + "forward_async_accept_funds" => interact.forward_async_accept_funds().await, + "forward_async_accept_funds_half_payment" => { + interact.forward_async_accept_funds_half_payment().await + }, + "forward_async_accept_funds_with_fees" => { + interact.forward_async_accept_funds_with_fees().await + }, + "forward_async_retrieve_funds" => interact.forward_async_retrieve_funds().await, + "send_funds_twice" => interact.send_funds_twice().await, + "send_async_accept_multi_transfer" => interact.send_async_accept_multi_transfer().await, + "callback_data" => interact.callback_data().await, + "callback_data_at_index" => interact.callback_data_at_index().await, + "clear_callback_data" => interact.clear_callback_data().await, + "forward_transf_exec_accept_funds" => interact.forward_transf_exec_accept_funds().await, + "forward_transf_execu_accept_funds_with_fees" => { + interact.forward_transf_execu_accept_funds_with_fees().await + }, + "forward_transf_exec_accept_funds_twice" => { + interact.forward_transf_exec_accept_funds_twice().await + }, + "forward_transf_exec_accept_funds_return_values" => { + interact + .forward_transf_exec_accept_funds_return_values() + .await + }, + "transf_exec_multi_accept_funds" => interact.transf_exec_multi_accept_funds().await, + "forward_transf_exec_reject_funds_multi_transfer" => { + interact + .forward_transf_exec_reject_funds_multi_transfer() + .await + }, + "transf_exec_multi_reject_funds" => interact.transf_exec_multi_reject_funds().await, + "changeOwnerAddress" => interact.change_owner().await, + "deploy_contract" => interact.deploy_contract().await, + "deploy_two_contracts" => interact.deploy_two_contracts().await, + "deploy_vault_from_source" => interact.deploy_vault_from_source().await, + "upgradeVault" => interact.upgrade_vault().await, + "upgrade_vault_from_source" => interact.upgrade_vault_from_source().await, + "getFungibleEsdtBalance" => interact.get_fungible_esdt_balance().await, + "getCurrentNftNonce" => interact.get_current_nft_nonce().await, + "send_esdt" => interact.send_esdt().await, + "send_esdt_with_fees" => interact.send_esdt_with_fees().await, + "send_esdt_twice" => interact.send_esdt_twice().await, + "send_esdt_direct_multi_transfer" => interact.send_esdt_direct_multi_transfer().await, + "issue_fungible_token" => interact.issue_fungible_token().await, + "local_mint" => interact.local_mint().await, + "local_burn" => interact.local_burn().await, + "get_esdt_local_roles" => interact.get_esdt_local_roles().await, + "get_esdt_token_data" => interact.get_esdt_token_data().await, + "is_esdt_frozen" => interact.is_esdt_frozen().await, + "is_esdt_paused" => interact.is_esdt_paused().await, + "is_esdt_limited_transfer" => interact.is_esdt_limited_transfer().await, + "validate_token_identifier" => interact.validate_token_identifier().await, + "sft_issue" => interact.sft_issue().await, + "get_nft_balance" => interact.get_nft_balance().await, + "buy_nft" => interact.buy_nft().await, + "nft_issue" => interact.nft_issue().await, + "nft_create_compact" => interact.nft_create_compact().await, + "nft_add_uris" => interact.nft_add_uris().await, + "nft_update_attributes" => interact.nft_update_attributes().await, + "nft_decode_complex_attributes" => interact.nft_decode_complex_attributes().await, + "nft_add_quantity" => interact.nft_add_quantity().await, + "nft_burn" => interact.nft_burn().await, + "transfer_nft_via_async_call" => interact.transfer_nft_via_async_call().await, + "transfer_nft_and_execute" => interact.transfer_nft_and_execute().await, + "create_and_send" => interact.create_and_send().await, + "setLocalRoles" => interact.set_local_roles().await, + "unsetLocalRoles" => interact.unset_local_roles().await, + "lastErrorMessage" => interact.last_error_message().await, + _ => panic!("unknown command: {}", &cmd), + } +} + +#[derive(Debug, Default, Serialize, Deserialize)] +pub 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(); + } +} + +pub struct ContractInteract { + interactor: Interactor, + pub wallet_address: Address, + contract_code: BytesValue, + pub state: State, +} + +impl ContractInteract { + pub async fn new(config: Config, trace_path: Option<&str>) -> Self { + let mut interactor = Interactor::new(config.gateway_uri()) + .await + .use_chain_simulator(config.use_chain_simulator()); + + if let Some(path) = trace_path { + interactor = interactor.with_tracer(path).await; + } + + interactor.set_current_dir_from_workspace("forwarder-interactor"); + let wallet_address = interactor.register_wallet(test_wallets::alice()).await; + + // Useful in the chain simulator setting + // generate blocks until ESDTSystemSCAddress is enabled + interactor.generate_blocks_until_epoch(1).await.unwrap(); + + let contract_code = BytesValue::interpret_from( + "mxsc:../forwarder/output/forwarder.mxsc.json", + &InterpreterContext::default(), + ); + + ContractInteract { + interactor, + wallet_address, + contract_code, + state: State::load_state(), + } + } + + pub async fn deploy(&mut self) { + let new_address = self + .interactor + .tx() + .from(&self.wallet_address) + .gas(300_000_000u64) + .typed(proxy::ForwarderProxy) + .init() + .code(&self.contract_code) + .returns(ReturnsNewAddress) + .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}"); + } + + pub async fn send_egld(&mut self) { + let to = Address::zero(); + let amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .send_egld(to, amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn echo_arguments_sync(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + let args = MultiValueVec::from(vec![ManagedBuffer::new_from_bytes(&b""[..])]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .echo_arguments_sync(to, args) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn echo_arguments_sync_twice(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + let args = MultiValueVec::from(vec![ManagedBuffer::new_from_bytes(&b""[..])]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .echo_arguments_sync_twice(to, args) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_sync_accept_funds(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_sync_accept_funds(to) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_sync_accept_funds_rh_egld(&mut self) { + let egld_amount = BigUint::::from(0u128); + + let to = Address::zero(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_sync_accept_funds_rh_egld(to) + .egld(egld_amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_sync_accept_funds_rh_single_esdt(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_sync_accept_funds_rh_single_esdt(to) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_sync_accept_funds_rh_multi_esdt(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_sync_accept_funds_rh_multi_esdt(to) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_sync_accept_funds_with_fees(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + let percentage_fees = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_sync_accept_funds_with_fees(to, percentage_fees) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_sync_accept_funds_then_read(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_sync_accept_funds_then_read(to) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_sync_retrieve_funds(&mut self) { + let to = Address::zero(); + let token = EgldOrEsdtTokenIdentifier::esdt(&b""[..]); + let token_nonce = 0u64; + let amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_sync_retrieve_funds(to, token, token_nonce, amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_sync_retrieve_funds_with_accept_func(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + let token = TokenIdentifier::from_esdt_bytes(&b""[..]); + let amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_sync_retrieve_funds_with_accept_func(to, token, amount) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn accept_funds_func(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .accept_funds_func() + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_sync_accept_funds_multi_transfer(&mut self) { + let to = Address::zero(); + let token_payments = MultiValueVec::from(vec![MultiValue3::< + TokenIdentifier, + u64, + BigUint, + >::from(( + TokenIdentifier::from_esdt_bytes(&b""[..]), + 0u64, + BigUint::::from(0u128), + ))]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_sync_accept_funds_multi_transfer(to, token_payments) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn echo_args_async(&mut self) { + let to = Address::zero(); + let args = MultiValueVec::from(vec![ManagedBuffer::new_from_bytes(&b""[..])]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .echo_args_async(to, args) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_async_accept_funds(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_async_accept_funds(to) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_async_accept_funds_half_payment(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_async_accept_funds_half_payment(to) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_async_accept_funds_with_fees(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + let percentage_fees = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_async_accept_funds_with_fees(to, percentage_fees) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_async_retrieve_funds(&mut self) { + let to = Address::zero(); + let token = EgldOrEsdtTokenIdentifier::esdt(&b""[..]); + let token_nonce = 0u64; + let amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_async_retrieve_funds(to, token, token_nonce, amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn send_funds_twice(&mut self) { + let to = Address::zero(); + let token_identifier = EgldOrEsdtTokenIdentifier::esdt(&b""[..]); + let amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .send_funds_twice(to, token_identifier, amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn send_async_accept_multi_transfer(&mut self) { + let to = Address::zero(); + let token_payments = MultiValueVec::from(vec![MultiValue3::< + TokenIdentifier, + u64, + BigUint, + >::from(( + TokenIdentifier::from_esdt_bytes(&b""[..]), + 0u64, + BigUint::::from(0u128), + ))]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .send_async_accept_multi_transfer(to, token_payments) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn callback_data(&mut self) { + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .callback_data() + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {:?}", result_value.0); + } + + pub async fn callback_data_at_index(&mut self) { + let index = 0u32; + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .callback_data_at_index(index) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result_value:?}"); + } + + pub async fn clear_callback_data(&mut self) { + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .clear_callback_data() + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_transf_exec_accept_funds(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_transf_exec_accept_funds(to) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_transf_execu_accept_funds_with_fees(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + let percentage_fees = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_transf_execu_accept_funds_with_fees(to, percentage_fees) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_transf_exec_accept_funds_twice(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_transf_exec_accept_funds_twice(to) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_transf_exec_accept_funds_return_values(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_transf_exec_accept_funds_return_values(to) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn transf_exec_multi_accept_funds(&mut self) { + let to = Address::zero(); + let token_payments = MultiValueVec::from(vec![MultiValue3::< + TokenIdentifier, + u64, + BigUint, + >::from(( + TokenIdentifier::from_esdt_bytes(&b""[..]), + 0u64, + BigUint::::from(0u128), + ))]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .transf_exec_multi_accept_funds(to, token_payments) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn forward_transf_exec_reject_funds_multi_transfer(&mut self) { + let to = Address::zero(); + let token_payments = MultiValueVec::from(vec![MultiValue3::< + TokenIdentifier, + u64, + BigUint, + >::from(( + TokenIdentifier::from_esdt_bytes(&b""[..]), + 0u64, + BigUint::::from(0u128), + ))]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .forward_transf_exec_reject_funds_multi_transfer(to, token_payments) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn transf_exec_multi_reject_funds(&mut self) { + let to = Address::zero(); + let token_payments = MultiValueVec::from(vec![MultiValue3::< + TokenIdentifier, + u64, + BigUint, + >::from(( + TokenIdentifier::from_esdt_bytes(&b""[..]), + 0u64, + BigUint::::from(0u128), + ))]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .transf_exec_multi_reject_funds(to, token_payments) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn change_owner(&mut self) { + let child_sc_address = Address::zero(); + let new_owner = Address::zero(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .change_owner(child_sc_address, new_owner) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn deploy_contract(&mut self) { + let code = ManagedBuffer::new_from_bytes(&b""[..]); + let opt_arg = OptionalValue::Some(ManagedBuffer::new_from_bytes(&b""[..])); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .deploy_contract(code, opt_arg) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn deploy_two_contracts(&mut self) { + let code = ManagedBuffer::new_from_bytes(&b""[..]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .deploy_two_contracts(code) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn deploy_vault_from_source(&mut self) { + let source_address = Address::zero(); + let opt_arg = OptionalValue::Some(ManagedBuffer::new_from_bytes(&b""[..])); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .deploy_vault_from_source(source_address, opt_arg) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn upgrade_vault(&mut self) { + let child_sc_address = Address::zero(); + let new_code = ManagedBuffer::new_from_bytes(&b""[..]); + let opt_arg = OptionalValue::Some(ManagedBuffer::new_from_bytes(&b""[..])); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .upgrade_vault(child_sc_address, new_code, opt_arg) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn upgrade_vault_from_source(&mut self) { + let child_sc_address = Address::zero(); + let source_address = Address::zero(); + let opt_arg = OptionalValue::Some(ManagedBuffer::new_from_bytes(&b""[..])); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .upgrade_vault_from_source(child_sc_address, source_address, opt_arg) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn get_fungible_esdt_balance(&mut self) { + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .get_fungible_esdt_balance(token_identifier) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result_value:?}"); + } + + pub async fn get_current_nft_nonce(&mut self) { + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .get_current_nft_nonce(token_identifier) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result_value:?}"); + } + + pub async fn send_esdt(&mut self) { + let to = Address::zero(); + let token_id = TokenIdentifier::from_esdt_bytes(&b""[..]); + let amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .send_esdt(to, token_id, amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn send_esdt_with_fees(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let to = Address::zero(); + let percentage_fees = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .send_esdt_with_fees(to, percentage_fees) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn send_esdt_twice(&mut self) { + let to = Address::zero(); + let token_id = TokenIdentifier::from_esdt_bytes(&b""[..]); + let amount_first_time = BigUint::::from(0u128); + let amount_second_time = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .send_esdt_twice(to, token_id, amount_first_time, amount_second_time) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn send_esdt_direct_multi_transfer(&mut self) { + let to = Address::zero(); + let token_payments = MultiValueVec::from(vec![MultiValue3::< + TokenIdentifier, + u64, + BigUint, + >::from(( + TokenIdentifier::from_esdt_bytes(&b""[..]), + 0u64, + BigUint::::from(0u128), + ))]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .send_esdt_direct_multi_transfer(to, token_payments) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn issue_fungible_token(&mut self) { + let egld_amount = BigUint::::from(0u128); + + let token_display_name = ManagedBuffer::new_from_bytes(&b""[..]); + let token_ticker = ManagedBuffer::new_from_bytes(&b""[..]); + let initial_supply = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .issue_fungible_token(token_display_name, token_ticker, initial_supply) + .egld(egld_amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn local_mint(&mut self) { + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .local_mint(token_identifier, amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn local_burn(&mut self) { + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .local_burn(token_identifier, amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn get_esdt_local_roles(&mut self) { + let token_id = TokenIdentifier::from_esdt_bytes(&b""[..]); + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .get_esdt_local_roles(token_id) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result_value:?}"); + } + + pub async fn get_esdt_token_data(&mut self) { + let address = Address::zero(); + let token_id = TokenIdentifier::from_esdt_bytes(&b""[..]); + let nonce = 0u64; + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .get_esdt_token_data(address, token_id, nonce) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result_value:?}"); + } + + pub async fn is_esdt_frozen(&mut self) { + let address = Address::zero(); + let token_id = TokenIdentifier::from_esdt_bytes(&b""[..]); + let nonce = 0u64; + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .is_esdt_frozen(address, token_id, nonce) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result_value:?}"); + } + + pub async fn is_esdt_paused(&mut self) { + let token_id = TokenIdentifier::from_esdt_bytes(&b""[..]); + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .is_esdt_paused(token_id) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result_value:?}"); + } + + pub async fn is_esdt_limited_transfer(&mut self) { + let token_id = TokenIdentifier::from_esdt_bytes(&b""[..]); + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .is_esdt_limited_transfer(token_id) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result_value:?}"); + } + + pub async fn validate_token_identifier(&mut self) { + let token_id = TokenIdentifier::from_esdt_bytes(&b""[..]); + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .validate_token_identifier(token_id) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result_value:?}"); + } + + pub async fn sft_issue(&mut self) { + let egld_amount = BigUint::::from(0u128); + + let token_display_name = ManagedBuffer::new_from_bytes(&b""[..]); + let token_ticker = ManagedBuffer::new_from_bytes(&b""[..]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .sft_issue(token_display_name, token_ticker) + .egld(egld_amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn get_nft_balance(&mut self) { + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let nonce = 0u64; + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .get_nft_balance(token_identifier, nonce) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result_value:?}"); + } + + pub async fn buy_nft(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let nft_id = TokenIdentifier::from_esdt_bytes(&b""[..]); + let nft_nonce = 0u64; + let nft_amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .buy_nft(nft_id, nft_nonce, nft_amount) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn nft_issue(&mut self) { + let egld_amount = BigUint::::from(0u128); + + let token_display_name = ManagedBuffer::new_from_bytes(&b""[..]); + let token_ticker = ManagedBuffer::new_from_bytes(&b""[..]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .nft_issue(token_display_name, token_ticker) + .egld(egld_amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + #[allow(clippy::too_many_arguments)] + pub async fn nft_create( + &mut self, + token_id: &[u8], + amount: RustBigUint, + name: &[u8], + royalties: u64, + hash: &[u8], + attributes: &Color, + uri: &[u8], + ) { + println!("Minting NFT..."); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .nft_create( + token_id, + amount, + name, + royalties, + hash, + attributes, + &ManagedBuffer::from(uri), + ) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn nft_create_compact(&mut self) { + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let amount = BigUint::::from(0u128); + let color = Color::default(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .nft_create_compact(token_identifier, amount, color) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn nft_add_uris(&mut self) { + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let nonce = 0u64; + let uris = MultiValueVec::from(vec![ManagedBuffer::new_from_bytes(&b""[..])]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .nft_add_uris(token_identifier, nonce, uris) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn nft_update_attributes(&mut self) { + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let nonce = 0u64; + let new_attributes = Color::default(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .nft_update_attributes(token_identifier, nonce, new_attributes) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn nft_decode_complex_attributes(&mut self) { + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let amount = BigUint::::from(0u128); + let name = ManagedBuffer::new_from_bytes(&b""[..]); + let royalties = BigUint::::from(0u128); + let hash = ManagedBuffer::new_from_bytes(&b""[..]); + let uri = ManagedBuffer::new_from_bytes(&b""[..]); + let attrs_arg = MultiValue5::< + BigUint, + ManagedBuffer, + TokenIdentifier, + bool, + ManagedBuffer, + >::from(( + BigUint::::from(0u128), + ManagedBuffer::new_from_bytes(&b""[..]), + TokenIdentifier::from_esdt_bytes(&b""[..]), + false, + ManagedBuffer::new_from_bytes(&b""[..]), + )); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .nft_decode_complex_attributes( + token_identifier, + amount, + name, + royalties, + hash, + uri, + attrs_arg, + ) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn nft_add_quantity(&mut self) { + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let nonce = 0u64; + let amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .nft_add_quantity(token_identifier, nonce, amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn nft_burn(&mut self) { + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let nonce = 0u64; + let amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .nft_burn(token_identifier, nonce, amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn transfer_nft_via_async_call(&mut self) { + let to = Address::zero(); + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let nonce = 0u64; + let amount = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .transfer_nft_via_async_call(to, token_identifier, nonce, amount) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn transfer_nft_and_execute(&mut self) { + let to = Address::zero(); + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let nonce = 0u64; + let amount = BigUint::::from(0u128); + let function = ManagedBuffer::new_from_bytes(&b""[..]); + let arguments = MultiValueVec::from(vec![ManagedBuffer::new_from_bytes(&b""[..])]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .transfer_nft_and_execute(to, token_identifier, nonce, amount, function, arguments) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn create_and_send(&mut self) { + let to = Address::zero(); + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let amount = BigUint::::from(0u128); + let name = ManagedBuffer::new_from_bytes(&b""[..]); + let royalties = BigUint::::from(0u128); + let hash = ManagedBuffer::new_from_bytes(&b""[..]); + let color = Color::default(); + let uri = ManagedBuffer::new_from_bytes(&b""[..]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .create_and_send( + to, + token_identifier, + amount, + name, + royalties, + hash, + color, + uri, + ) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn set_local_roles(&mut self) { + let address = Address::zero(); + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let roles = MultiValueVec::::new(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .set_local_roles(address, token_identifier, roles) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn unset_local_roles(&mut self) { + let address = Address::zero(); + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let roles = MultiValueVec::::new(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .unset_local_roles(address, token_identifier, roles) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn issue_dynamic_token( + &mut self, + issue_cost: RustBigUint, + token_display_name: &[u8], + token_ticker: &[u8], + token_type: EsdtTokenType, + num_decimals: usize, + ) { + println!("Registering dynamic token {token_ticker:?} of type {token_type:?}..."); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .issue_dynamic_token(token_display_name, token_ticker, token_type, num_decimals) + .egld(BigUint::from(issue_cost)) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn issue_token_all_roles( + &mut self, + issue_cost: RustBigUint, + token_display_name: &[u8], + token_ticker: &[u8], + num_decimals: usize, + token_type: EsdtTokenType, + ) { + println!("Registering and setting all roles for token {token_ticker:?} of type {token_type:?}..."); + + let result = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .issue_token_all_roles(token_display_name, token_ticker, token_type, num_decimals) + .egld(BigUint::from(issue_cost)) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result:?}"); + } + + pub async fn change_to_dynamic(&mut self, token_id: &[u8]) { + println!("Changing the following token {token_id:?} to dynamic..."); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .change_to_dynamic(TokenIdentifier::from(token_id)) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn update_token(&mut self, token_id: &[u8]) { + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .update_token(TokenIdentifier::from(token_id)) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + 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:?}..."); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .modify_royalties(TokenIdentifier::from(token_id), nonce, new_royalty) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn set_new_uris(&mut self, token_id: &[u8], nonce: u64, new_uris: Vec) { + let uris = new_uris + .into_iter() + .map(ManagedBuffer::from) + .collect::>>(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .set_new_uris(token_id, nonce, uris) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn modify_creator(&mut self, token_id: &[u8], nonce: u64) { + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .modify_creator(TokenIdentifier::from(token_id), nonce) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + #[allow(clippy::too_many_arguments)] + pub async fn metadata_recreate( + &mut self, + token_id: &[u8], + nonce: u64, + name: &[u8], + royalties: u64, + hash: &[u8], + new_attributes: &Color, + uris: Vec, + ) { + println!("Recreating the token {token_id:?} with nonce {nonce:?} with new attributes..."); + + let uris = uris + .into_iter() + .map(ManagedBuffer::from) + .collect::>>(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .metadata_recreate(token_id, nonce, name, royalties, hash, new_attributes, uris) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + #[allow(clippy::too_many_arguments)] + pub async fn metadata_update( + &mut self, + token_id: &[u8], + nonce: u64, + name: &[u8], + royalties: u64, + hash: &[u8], + new_attributes: &Color, + uris: Vec, + ) { + println!("Updating the token {token_id:?} with nonce {nonce:?} with new attributes..."); + + let uris = uris + .into_iter() + .map(ManagedBuffer::from) + .collect::>>(); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(80_000_000u64) + .typed(proxy::ForwarderProxy) + .metadata_update(token_id, nonce, name, royalties, hash, new_attributes, uris) + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {response:?}"); + } + + pub async fn last_issued_token(&mut self) -> String { + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .last_issued_token() + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result_value:?}"); + + result_value.as_managed_buffer().to_string() + } + + pub async fn last_error_message(&mut self) { + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::ForwarderProxy) + .last_error_message() + .returns(ReturnsResultUnmanaged) + .run() + .await; + + println!("Result: {result_value:?}"); + } + + pub async fn issue_dynamic_token_from_wallet( + &mut self, + issue_cost: RustBigUint, + token_display_name: &[u8], + token_ticker: &[u8], + token_type: EsdtTokenType, + num_decimals: usize, + ) -> String { + println!("Registering dynamic token {token_ticker:?} of type {token_type:?} from the test wallet..."); + + let token_id = self + .interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .issue_dynamic( + issue_cost.into(), + token_display_name, + token_ticker, + token_type, + num_decimals, + ) + .returns(ReturnsNewTokenIdentifier) + .run() + .await; + + println!("TOKEN ID: {:?}", token_id); + + token_id + } + + pub async fn set_roles_from_wallet( + &mut self, + for_address: &Address, + token_id: &[u8], + roles: Vec, + ) { + println!("Setting the following roles: {roles:?} for {token_id:?}"); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(80_000_000u64) + .typed(ESDTSystemSCProxy) + .set_special_roles( + ManagedAddress::from_address(for_address), + TokenIdentifier::from(token_id), + roles.into_iter(), + ) + .run() + .await; + } + + #[allow(clippy::too_many_arguments)] + pub async fn mint_nft_from_wallet( + &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, attributes, &uris) + .returns(ReturnsResult) + .run() + .await + } + + pub async fn send_esdt_from_wallet( + &mut self, + to: &Address, + token_id: &[u8], + nonce: u64, + amount: RustBigUint, + ) { + println!("Sending token {token_id:?} with nonce {nonce:?} to other_wallet_address..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(to) + .single_esdt(&token_id.into(), nonce, &amount.into()) // .transfer() + .run() + .await; + } +} diff --git a/contracts/feature-tests/composability/forwarder-interactor/src/interactor_main.rs b/contracts/feature-tests/composability/forwarder-interactor/src/interactor_main.rs new file mode 100644 index 0000000000..cf6bcaa48f --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/src/interactor_main.rs @@ -0,0 +1,7 @@ +use forwarder_interact::forwarder_cli; +use multiversx_sc_snippets::imports::*; + +#[tokio::main] +async fn main() { + forwarder_cli().await; +} diff --git a/contracts/feature-tests/composability/forwarder-interactor/src/proxy.rs b/contracts/feature-tests/composability/forwarder-interactor/src/proxy.rs new file mode 100644 index 0000000000..efa27be50f --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/src/proxy.rs @@ -0,0 +1,1396 @@ +// 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 ForwarderProxy; + +impl TxProxyTrait for ForwarderProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = ForwarderProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + ForwarderProxyMethods { wrapped_tx: tx } + } +} + +pub struct ForwarderProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl ForwarderProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl ForwarderProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn send_egld< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + to: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("send_egld") + .argument(&to) + .argument(&amount) + .original_result() + } + + pub fn echo_arguments_sync< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + to: Arg0, + args: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("echo_arguments_sync") + .argument(&to) + .argument(&args) + .original_result() + } + + pub fn echo_arguments_sync_twice< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + to: Arg0, + args: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("echo_arguments_sync_twice") + .argument(&to) + .argument(&args) + .original_result() + } + + pub fn forward_sync_accept_funds< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("forward_sync_accept_funds") + .argument(&to) + .original_result() + } + + pub fn forward_sync_accept_funds_rh_egld< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .raw_call("forward_sync_accept_funds_rh_egld") + .argument(&to) + .original_result() + } + + pub fn forward_sync_accept_funds_rh_single_esdt< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .raw_call("forward_sync_accept_funds_rh_single_esdt") + .argument(&to) + .original_result() + } + + pub fn forward_sync_accept_funds_rh_multi_esdt< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxTypedCall>> { + self.wrapped_tx + .raw_call("forward_sync_accept_funds_rh_multi_esdt") + .argument(&to) + .original_result() + } + + pub fn forward_sync_accept_funds_with_fees< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + to: Arg0, + percentage_fees: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("forward_sync_accept_funds_with_fees") + .argument(&to) + .argument(&percentage_fees) + .original_result() + } + + pub fn forward_sync_accept_funds_then_read< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("forward_sync_accept_funds_then_read") + .argument(&to) + .original_result() + } + + pub fn forward_sync_retrieve_funds< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg>, + >( + self, + to: Arg0, + token: Arg1, + token_nonce: Arg2, + amount: Arg3, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("forward_sync_retrieve_funds") + .argument(&to) + .argument(&token) + .argument(&token_nonce) + .argument(&amount) + .original_result() + } + + pub fn forward_sync_retrieve_funds_with_accept_func< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + to: Arg0, + token: Arg1, + amount: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("forward_sync_retrieve_funds_with_accept_func") + .argument(&to) + .argument(&token) + .argument(&amount) + .original_result() + } + + pub fn accept_funds_func( + self, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("accept_funds_func") + .original_result() + } + + pub fn forward_sync_accept_funds_multi_transfer< + Arg0: ProxyArg>, + Arg1: ProxyArg, u64, BigUint>>>, + >( + self, + to: Arg0, + token_payments: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("forward_sync_accept_funds_multi_transfer") + .argument(&to) + .argument(&token_payments) + .original_result() + } + + pub fn echo_args_async< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + to: Arg0, + args: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("echo_args_async") + .argument(&to) + .argument(&args) + .original_result() + } + + pub fn forward_async_accept_funds< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("forward_async_accept_funds") + .argument(&to) + .original_result() + } + + pub fn forward_async_accept_funds_half_payment< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("forward_async_accept_funds_half_payment") + .argument(&to) + .original_result() + } + + pub fn forward_async_accept_funds_with_fees< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + to: Arg0, + percentage_fees: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("forward_async_accept_funds_with_fees") + .argument(&to) + .argument(&percentage_fees) + .original_result() + } + + pub fn forward_async_retrieve_funds< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg>, + >( + self, + to: Arg0, + token: Arg1, + token_nonce: Arg2, + amount: Arg3, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("forward_async_retrieve_funds") + .argument(&to) + .argument(&token) + .argument(&token_nonce) + .argument(&amount) + .original_result() + } + + pub fn send_funds_twice< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + to: Arg0, + token_identifier: Arg1, + amount: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("send_funds_twice") + .argument(&to) + .argument(&token_identifier) + .argument(&amount) + .original_result() + } + + pub fn send_async_accept_multi_transfer< + Arg0: ProxyArg>, + Arg1: ProxyArg, u64, BigUint>>>, + >( + self, + to: Arg0, + token_payments: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("send_async_accept_multi_transfer") + .argument(&to) + .argument(&token_payments) + .original_result() + } + + pub fn callback_data( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("callback_data") + .original_result() + } + + pub fn callback_data_at_index< + Arg0: ProxyArg, + >( + self, + index: Arg0, + ) -> TxTypedCall, EgldOrEsdtTokenIdentifier, u64, BigUint, MultiValueManagedVec>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("callback_data_at_index") + .argument(&index) + .original_result() + } + + pub fn clear_callback_data( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("clear_callback_data") + .original_result() + } + + pub fn forward_transf_exec_accept_funds< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("forward_transf_exec_accept_funds") + .argument(&to) + .original_result() + } + + pub fn forward_transf_execu_accept_funds_with_fees< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + to: Arg0, + percentage_fees: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("forward_transf_execu_accept_funds_with_fees") + .argument(&to) + .argument(&percentage_fees) + .original_result() + } + + pub fn forward_transf_exec_accept_funds_twice< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("forward_transf_exec_accept_funds_twice") + .argument(&to) + .original_result() + } + + /// Test that the default gas provided to the transfer_execute call + /// leaves enough in the transaction for finish to happen. + pub fn forward_transf_exec_accept_funds_return_values< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxTypedCall, EgldOrEsdtTokenIdentifier>> { + self.wrapped_tx + .raw_call("forward_transf_exec_accept_funds_return_values") + .argument(&to) + .original_result() + } + + pub fn transf_exec_multi_accept_funds< + Arg0: ProxyArg>, + Arg1: ProxyArg, u64, BigUint>>>, + >( + self, + to: Arg0, + token_payments: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("transf_exec_multi_accept_funds") + .argument(&to) + .argument(&token_payments) + .original_result() + } + + pub fn forward_transf_exec_reject_funds_multi_transfer< + Arg0: ProxyArg>, + Arg1: ProxyArg, u64, BigUint>>>, + >( + self, + to: Arg0, + token_payments: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("forward_transf_exec_reject_funds_multi_transfer") + .argument(&to) + .argument(&token_payments) + .original_result() + } + + pub fn transf_exec_multi_reject_funds< + Arg0: ProxyArg>, + Arg1: ProxyArg, u64, BigUint>>>, + >( + self, + to: Arg0, + token_payments: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("transf_exec_multi_reject_funds") + .argument(&to) + .argument(&token_payments) + .original_result() + } + + pub fn change_owner< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + child_sc_address: Arg0, + new_owner: Arg1, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("changeOwnerAddress") + .argument(&child_sc_address) + .argument(&new_owner) + .original_result() + } + + pub fn deploy_contract< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + code: Arg0, + opt_arg: Arg1, + ) -> TxTypedCall, OptionalValue>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("deploy_contract") + .argument(&code) + .argument(&opt_arg) + .original_result() + } + + pub fn deploy_two_contracts< + Arg0: ProxyArg>, + >( + self, + code: Arg0, + ) -> TxTypedCall, ManagedAddress>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("deploy_two_contracts") + .argument(&code) + .original_result() + } + + pub fn deploy_vault_from_source< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + source_address: Arg0, + opt_arg: Arg1, + ) -> TxTypedCall, OptionalValue>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("deploy_vault_from_source") + .argument(&source_address) + .argument(&opt_arg) + .original_result() + } + + pub fn upgrade_vault< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>>, + >( + self, + child_sc_address: Arg0, + new_code: Arg1, + opt_arg: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("upgradeVault") + .argument(&child_sc_address) + .argument(&new_code) + .argument(&opt_arg) + .original_result() + } + + pub fn upgrade_vault_from_source< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>>, + >( + self, + child_sc_address: Arg0, + source_address: Arg1, + opt_arg: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("upgrade_vault_from_source") + .argument(&child_sc_address) + .argument(&source_address) + .argument(&opt_arg) + .original_result() + } + + pub fn get_fungible_esdt_balance< + Arg0: ProxyArg>, + >( + self, + token_identifier: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFungibleEsdtBalance") + .argument(&token_identifier) + .original_result() + } + + pub fn get_current_nft_nonce< + Arg0: ProxyArg>, + >( + self, + token_identifier: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getCurrentNftNonce") + .argument(&token_identifier) + .original_result() + } + + pub fn send_esdt< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + to: Arg0, + token_id: Arg1, + amount: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("send_esdt") + .argument(&to) + .argument(&token_id) + .argument(&amount) + .original_result() + } + + pub fn send_esdt_with_fees< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + to: Arg0, + percentage_fees: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("send_esdt_with_fees") + .argument(&to) + .argument(&percentage_fees) + .original_result() + } + + pub fn send_esdt_twice< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + >( + self, + to: Arg0, + token_id: Arg1, + amount_first_time: Arg2, + amount_second_time: Arg3, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("send_esdt_twice") + .argument(&to) + .argument(&token_id) + .argument(&amount_first_time) + .argument(&amount_second_time) + .original_result() + } + + pub fn send_esdt_direct_multi_transfer< + Arg0: ProxyArg>, + Arg1: ProxyArg, u64, BigUint>>>, + >( + self, + to: Arg0, + token_payments: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("send_esdt_direct_multi_transfer") + .argument(&to) + .argument(&token_payments) + .original_result() + } + + pub fn issue_fungible_token< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + token_display_name: Arg0, + token_ticker: Arg1, + initial_supply: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("issue_fungible_token") + .argument(&token_display_name) + .argument(&token_ticker) + .argument(&initial_supply) + .original_result() + } + + pub fn local_mint< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_identifier: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("local_mint") + .argument(&token_identifier) + .argument(&amount) + .original_result() + } + + pub fn local_burn< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_identifier: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("local_burn") + .argument(&token_identifier) + .argument(&amount) + .original_result() + } + + pub fn get_esdt_local_roles< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("get_esdt_local_roles") + .argument(&token_id) + .original_result() + } + + pub fn get_esdt_token_data< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + address: Arg0, + token_id: Arg1, + nonce: Arg2, + ) -> TxTypedCall, bool, ManagedBuffer, ManagedBuffer, ManagedBuffer, ManagedAddress, BigUint, ManagedVec>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("get_esdt_token_data") + .argument(&address) + .argument(&token_id) + .argument(&nonce) + .original_result() + } + + pub fn is_esdt_frozen< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + address: Arg0, + token_id: Arg1, + nonce: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("is_esdt_frozen") + .argument(&address) + .argument(&token_id) + .argument(&nonce) + .original_result() + } + + pub fn is_esdt_paused< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("is_esdt_paused") + .argument(&token_id) + .original_result() + } + + pub fn is_esdt_limited_transfer< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("is_esdt_limited_transfer") + .argument(&token_id) + .original_result() + } + + pub fn validate_token_identifier< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("validate_token_identifier") + .argument(&token_id) + .original_result() + } + + pub fn sft_issue< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_display_name: Arg0, + token_ticker: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("sft_issue") + .argument(&token_display_name) + .argument(&token_ticker) + .original_result() + } + + pub fn get_nft_balance< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + token_identifier: Arg0, + nonce: Arg1, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("get_nft_balance") + .argument(&token_identifier) + .argument(&nonce) + .original_result() + } + + pub fn buy_nft< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + nft_id: Arg0, + nft_nonce: Arg1, + nft_amount: Arg2, + ) -> TxTypedCall> { + self.wrapped_tx + .raw_call("buy_nft") + .argument(&nft_id) + .argument(&nft_nonce) + .argument(&nft_amount) + .original_result() + } + + pub fn nft_issue< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_display_name: Arg0, + token_ticker: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("nft_issue") + .argument(&token_display_name) + .argument(&token_ticker) + .original_result() + } + + pub fn nft_create< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + Arg4: ProxyArg>, + Arg5: ProxyArg, + Arg6: ProxyArg>, + >( + self, + token_identifier: Arg0, + amount: Arg1, + name: Arg2, + royalties: Arg3, + hash: Arg4, + color: Arg5, + uri: Arg6, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("nft_create") + .argument(&token_identifier) + .argument(&amount) + .argument(&name) + .argument(&royalties) + .argument(&hash) + .argument(&color) + .argument(&uri) + .original_result() + } + + pub fn nft_create_compact< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + token_identifier: Arg0, + amount: Arg1, + color: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("nft_create_compact") + .argument(&token_identifier) + .argument(&amount) + .argument(&color) + .original_result() + } + + pub fn nft_add_uris< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>>, + >( + self, + token_identifier: Arg0, + nonce: Arg1, + uris: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("nft_add_uris") + .argument(&token_identifier) + .argument(&nonce) + .argument(&uris) + .original_result() + } + + pub fn nft_update_attributes< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg, + >( + self, + token_identifier: Arg0, + nonce: Arg1, + new_attributes: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("nft_update_attributes") + .argument(&token_identifier) + .argument(&nonce) + .argument(&new_attributes) + .original_result() + } + + pub fn nft_decode_complex_attributes< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + Arg4: ProxyArg>, + Arg5: ProxyArg>, + Arg6: ProxyArg, ManagedBuffer, TokenIdentifier, bool, ManagedBuffer>>, + >( + self, + token_identifier: Arg0, + amount: Arg1, + name: Arg2, + royalties: Arg3, + hash: Arg4, + uri: Arg5, + attrs_arg: Arg6, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("nft_decode_complex_attributes") + .argument(&token_identifier) + .argument(&amount) + .argument(&name) + .argument(&royalties) + .argument(&hash) + .argument(&uri) + .argument(&attrs_arg) + .original_result() + } + + pub fn nft_add_quantity< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + token_identifier: Arg0, + nonce: Arg1, + amount: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("nft_add_quantity") + .argument(&token_identifier) + .argument(&nonce) + .argument(&amount) + .original_result() + } + + pub fn nft_burn< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + token_identifier: Arg0, + nonce: Arg1, + amount: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("nft_burn") + .argument(&token_identifier) + .argument(&nonce) + .argument(&amount) + .original_result() + } + + pub fn transfer_nft_via_async_call< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg>, + >( + self, + to: Arg0, + token_identifier: Arg1, + nonce: Arg2, + amount: Arg3, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("transfer_nft_via_async_call") + .argument(&to) + .argument(&token_identifier) + .argument(&nonce) + .argument(&amount) + .original_result() + } + + pub fn transfer_nft_and_execute< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg>, + Arg4: ProxyArg>, + Arg5: ProxyArg>>, + >( + self, + to: Arg0, + token_identifier: Arg1, + nonce: Arg2, + amount: Arg3, + function: Arg4, + arguments: Arg5, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("transfer_nft_and_execute") + .argument(&to) + .argument(&token_identifier) + .argument(&nonce) + .argument(&amount) + .argument(&function) + .argument(&arguments) + .original_result() + } + + pub fn create_and_send< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + Arg4: ProxyArg>, + Arg5: ProxyArg>, + Arg6: ProxyArg, + Arg7: ProxyArg>, + >( + self, + to: Arg0, + token_identifier: Arg1, + amount: Arg2, + name: Arg3, + royalties: Arg4, + hash: Arg5, + color: Arg6, + uri: Arg7, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("create_and_send") + .argument(&to) + .argument(&token_identifier) + .argument(&amount) + .argument(&name) + .argument(&royalties) + .argument(&hash) + .argument(&color) + .argument(&uri) + .original_result() + } + + pub fn set_local_roles< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + address: Arg0, + token_identifier: Arg1, + roles: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setLocalRoles") + .argument(&address) + .argument(&token_identifier) + .argument(&roles) + .original_result() + } + + pub fn unset_local_roles< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + address: Arg0, + token_identifier: Arg1, + roles: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unsetLocalRoles") + .argument(&address) + .argument(&token_identifier) + .argument(&roles) + .original_result() + } + + pub fn issue_dynamic_token< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg, + >( + self, + token_display_name: Arg0, + token_ticker: Arg1, + token_type: Arg2, + num_decimals: Arg3, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("issue_dynamic_token") + .argument(&token_display_name) + .argument(&token_ticker) + .argument(&token_type) + .argument(&num_decimals) + .original_result() + } + + pub fn issue_token_all_roles< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg, + >( + self, + token_display_name: Arg0, + token_ticker: Arg1, + token_type: Arg2, + num_decimals: Arg3, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("issue_token_all_roles") + .argument(&token_display_name) + .argument(&token_ticker) + .argument(&token_type) + .argument(&num_decimals) + .original_result() + } + + pub fn change_to_dynamic< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("change_to_dynamic") + .argument(&token_id) + .original_result() + } + + pub fn update_token< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("update_token") + .argument(&token_id) + .original_result() + } + + pub fn modify_royalties< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg, + >( + self, + token_id: Arg0, + nonce: Arg1, + new_royalty: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("modify_royalties") + .argument(&token_id) + .argument(&nonce) + .argument(&new_royalty) + .original_result() + } + + pub fn set_new_uris< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>>, + >( + self, + token_id: Arg0, + nonce: Arg1, + new_uris: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("set_new_uris") + .argument(&token_id) + .argument(&nonce) + .argument(&new_uris) + .original_result() + } + + pub fn modify_creator< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + token_id: Arg0, + nonce: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("modify_creator") + .argument(&token_id) + .argument(&nonce) + .original_result() + } + + pub fn metadata_recreate< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + Arg3: ProxyArg, + Arg4: ProxyArg>, + Arg5: ProxyArg, + Arg6: ProxyArg>>, + >( + self, + token_id: Arg0, + nonce: Arg1, + name: Arg2, + royalties: Arg3, + hash: Arg4, + new_attributes: Arg5, + uris: Arg6, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("metadata_recreate") + .argument(&token_id) + .argument(&nonce) + .argument(&name) + .argument(&royalties) + .argument(&hash) + .argument(&new_attributes) + .argument(&uris) + .original_result() + } + + pub fn metadata_update< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + Arg3: ProxyArg, + Arg4: ProxyArg>, + Arg5: ProxyArg, + Arg6: ProxyArg>>, + >( + self, + token_id: Arg0, + nonce: Arg1, + name: Arg2, + royalties: Arg3, + hash: Arg4, + new_attributes: Arg5, + uris: Arg6, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("metadata_update") + .argument(&token_id) + .argument(&nonce) + .argument(&name) + .argument(&royalties) + .argument(&hash) + .argument(&new_attributes) + .argument(&uris) + .original_result() + } + + pub fn last_issued_token( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("lastIssuedToken") + .original_result() + } + + pub fn last_error_message( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("lastErrorMessage") + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode, TopDecode, Debug)] +pub struct CallbackData +where + Api: ManagedTypeApi, +{ + pub callback_name: ManagedBuffer, + pub token_identifier: EgldOrEsdtTokenIdentifier, + pub token_nonce: u64, + pub token_amount: BigUint, + pub args: ManagedVec>, +} + +#[type_abi] +#[derive(TopEncode, TopDecode, Clone, Copy, PartialEq, Debug, Default)] +pub struct Color { + pub r: u8, + pub g: u8, + pub b: u8, +} diff --git a/contracts/feature-tests/composability/forwarder-interactor/state.toml b/contracts/feature-tests/composability/forwarder-interactor/state.toml new file mode 100644 index 0000000000..2db4efcb4e --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/state.toml @@ -0,0 +1 @@ +contract_address = "erd1qqqqqqqqqqqqqpgqm6d7cp70y7ft6xe78f7np9agdm7vpce6d8sskuuxnu" diff --git a/contracts/feature-tests/composability/forwarder-interactor/tests/interact_cs_tests.rs b/contracts/feature-tests/composability/forwarder-interactor/tests/interact_cs_tests.rs new file mode 100644 index 0000000000..62a9c9d1a0 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/tests/interact_cs_tests.rs @@ -0,0 +1,15 @@ +use forwarder_interact::{Config, ContractInteract}; +use multiversx_sc_snippets::imports::*; + +// Simple deploy test that runs using the chain simulator configuration. +// In order for this test to work, make sure that the `config.toml` file contains the chain simulator config (or choose it manually) +// The chain simulator should already be installed and running before attempting to run this test. +// The chain-simulator-tests feature should be present in Cargo.toml. +// Can be run with `sc-meta test -c`. +#[tokio::test] +#[cfg_attr(not(feature = "chain-simulator-tests"), ignore)] +async fn deploy_test_forwarder_cs() { + let mut interactor = ContractInteract::new(Config::chain_simulator_config(), None).await; + + interactor.deploy().await; +} diff --git a/contracts/feature-tests/composability/forwarder-interactor/tests/interact_tests.rs b/contracts/feature-tests/composability/forwarder-interactor/tests/interact_tests.rs new file mode 100644 index 0000000000..59edcbbac0 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/tests/interact_tests.rs @@ -0,0 +1,341 @@ +use forwarder_interact::{ + Color, Config, ContractInteract, FORWARDER_BUILTIN_INTERACTOR_TRACE_PATH, + FORWARDER_CHANGE_TO_DYNAMIC_INTERACTOR_TRACE_PATH, FORWARDER_DEPLOY_INTERACTOR_TRACE_PATH, + FORWARDER_MODIFY_CREATOR_INTERACTOR_TRACE_PATH, FORWARDER_UPDATE_TOKEN_INTERACTOR_TRACE_PATH, +}; +use multiversx_sc_snippets::imports::*; + +const ISSUE_COST: u64 = 50000000000000000u64; + +// Simple deploy test that runs on the real blockchain configuration. +// In order for this test to work, make sure that the `config.toml` file contains the real blockchain config (or choose it manually) +// Can be run with `sc-meta test`. +#[tokio::test] +#[ignore = "run on demand, relies on real blockchain state"] +async fn deploy_test_forwarder() { + let mut interactor = + ContractInteract::new(Config::new(), Some(FORWARDER_DEPLOY_INTERACTOR_TRACE_PATH)).await; + + interactor.deploy().await; +} + +#[tokio::test] +#[ignore = "run on demand"] +async fn builtin_func_tokens_test() { + let mut interact = + ContractInteract::new(Config::new(), Some(FORWARDER_BUILTIN_INTERACTOR_TRACE_PATH)).await; + + // deploy forwarder + interact.deploy().await; + + // issue dynamic NFT + interact + .issue_dynamic_token( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + EsdtTokenType::DynamicNFT, + 0usize, + ) + .await; + + // issue dynamic SFT + interact + .issue_dynamic_token( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + EsdtTokenType::DynamicSFT, + 0usize, + ) + .await; + + // issue dynamic META + interact + .issue_dynamic_token( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + EsdtTokenType::DynamicMeta, + 18usize, + ) + .await; + + // issue dynamic META with all roles + interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 0usize, + EsdtTokenType::DynamicMeta, + ) + .await; + + // issue dynamic SFT with all roles + interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 0usize, + EsdtTokenType::DynamicSFT, + ) + .await; + + // issue dynamic NFT with all roles + interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 0usize, + EsdtTokenType::DynamicNFT, + ) + .await; + + let dynamic_nft_token_id = interact.last_issued_token().await; + + println!("Dynamic NFT token id issued: {dynamic_nft_token_id:?}"); + + // mint NFT + interact + .nft_create( + dynamic_nft_token_id.as_bytes(), + RustBigUint::from(1u64), + b"myNFT", + 30u64, + b"", + &Color { + r: 1u8, + g: 2u8, + b: 5u8, + }, + b"sample_uri", + ) + .await; + + let nonce = 1u64; + + 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:?}"); + + // metadata update + interact + .metadata_update( + dynamic_nft_token_id.as_bytes(), + nonce, + b"TESTNFT", + 30u64, + b"new_hash", + &Color { + r: 6u8, + g: 7u8, + b: 8u8, + }, + Vec::new(), + ) + .await; + + println!("Metadata updated for {dynamic_nft_token_id:?} with nonce {nonce:?}"); + + // metadata recreate + interact + .metadata_recreate( + dynamic_nft_token_id.as_bytes(), + nonce, + b"TESTNFT", + 30u64, + b"new_hash_recreated", + &Color { + r: 8u8, + g: 8u8, + b: 8u8, + }, + Vec::new(), + ) + .await; + + println!("Metadata recreated for {dynamic_nft_token_id:?} with nonce {nonce:?}. A new token has been created."); +} + +#[tokio::test] +#[ignore = "run on demand"] +async fn change_to_dynamic_test() { + let mut interact = ContractInteract::new( + Config::new(), + Some(FORWARDER_CHANGE_TO_DYNAMIC_INTERACTOR_TRACE_PATH), + ) + .await; + + // deploy forwarder + interact.deploy().await; + + // issue NFT with all roles + interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 0usize, + EsdtTokenType::NonFungible, + ) + .await; + + // issue META token with all roles + interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 18usize, + EsdtTokenType::Meta, + ) + .await; + + // get token id from the contract + let meta_token_id = interact.last_issued_token().await; + + // change META to dynamic + interact.change_to_dynamic(meta_token_id.as_bytes()).await; + + // issue SFT token with all roles + interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 18usize, + EsdtTokenType::SemiFungible, + ) + .await; + + // get token id from the contract + let sft_token_id = interact.last_issued_token().await; + + // change SFT to dynamic + interact.change_to_dynamic(sft_token_id.as_bytes()).await; +} + +#[tokio::test] +#[ignore = "run on demand"] +async fn update_token_test() { + let mut interact = ContractInteract::new( + Config::new(), + Some(FORWARDER_UPDATE_TOKEN_INTERACTOR_TRACE_PATH), + ) + .await; + + // deploy forwarder + interact.deploy().await; + + // issue NFT with all roles + interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 0usize, + EsdtTokenType::NonFungible, + ) + .await; + + // get token id from the contract + let nft_token_id = interact.last_issued_token().await; + + // update NFT + interact.update_token(nft_token_id.as_bytes()).await; +} + +#[tokio::test] +#[ignore = "run on demand"] +async fn modify_creator() { + let mut interact = ContractInteract::new( + Config::new(), + Some(FORWARDER_MODIFY_CREATOR_INTERACTOR_TRACE_PATH), + ) + .await; + + // deploy forwarder + interact.deploy().await; + + let wallet_address = interact.wallet_address.clone(); + let sc_address = interact.state.current_address().clone(); + + // issue dynamic NFT + let dynamic_nft_token_id = interact + .issue_dynamic_token_from_wallet( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + EsdtTokenType::DynamicNFT, + 0usize, + ) + .await; + + // set roles for self to mint + interact + .set_roles_from_wallet( + &wallet_address, + dynamic_nft_token_id.as_bytes(), + vec![EsdtLocalRole::NftCreate], + ) + .await; + + // mint NFT + let nonce = interact + .mint_nft_from_wallet( + dynamic_nft_token_id.as_bytes(), + RustBigUint::from(1u64), + b"myNFT", + 30u64, + b"", + &Color { + r: 1u8, + g: 2u8, + b: 3u8, + }, + Vec::new(), + ) + .await; + + println!("Dynamic NFT minted at nonce {nonce:?}"); + + // set modify creator role for the contract + interact + .set_roles_from_wallet( + &sc_address.to_address(), + dynamic_nft_token_id.as_bytes(), + vec![EsdtLocalRole::ModifyCreator], + ) + .await; + + // send nft to the contract + interact + .send_esdt_from_wallet( + &sc_address.to_address(), + dynamic_nft_token_id.as_bytes(), + 1u64, + 1u64.into(), + ) + .await; + + // modify creator into the contract (from wallet to SC through a SC call) + interact + .modify_creator(dynamic_nft_token_id.as_bytes(), nonce) + .await; +} diff --git a/contracts/feature-tests/composability/forwarder-interactor/tests/scenarios_go_tests.rs b/contracts/feature-tests/composability/forwarder-interactor/tests/scenarios_go_tests.rs new file mode 100644 index 0000000000..6950bf2f5c --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-interactor/tests/scenarios_go_tests.rs @@ -0,0 +1,34 @@ +use multiversx_sc_snippets::multiversx_sc_scenario::*; + +fn world() -> ScenarioWorld { + ScenarioWorld::vm_go() +} + +#[test] +fn deploy_go() { + world().run("scenarios/forwarder_deploy_scenario.scen.json"); +} + +#[test] +#[ignore = "missing 'newTokenIdentifiers' syntax"] +fn builtin_func_go() { + world().run("scenarios/forwarder_builtin_scenario.scen.json"); +} + +#[test] +#[ignore = "missing 'newTokenIdentifiers' syntax"] +fn change_to_dynamic_go() { + world().run("scenarios/forwarder_change_to_dynamic_scenario.scen.json"); +} + +#[test] +#[ignore = "missing 'newTokenIdentifiers' syntax"] +fn update_token_go() { + world().run("scenarios/forwarder_update_token_scenario.scen.json"); +} + +#[test] +#[ignore = "missing 'newTokenIdentifiers' syntax"] +fn modify_creator_go() { + world().run("scenarios/forwarder_modify_creator_scenario.scen.json"); +} diff --git a/contracts/feature-tests/composability/forwarder/sc-config.toml b/contracts/feature-tests/composability/forwarder/sc-config.toml index b78f0086a5..5974cd2dbf 100644 --- a/contracts/feature-tests/composability/forwarder/sc-config.toml +++ b/contracts/feature-tests/composability/forwarder/sc-config.toml @@ -1,2 +1,6 @@ [[proxy]] path = "src/forwarder_proxy.rs" + +[[proxy]] +path = "../forwarder-interactor/src/proxy.rs" + diff --git a/contracts/feature-tests/composability/forwarder/src/forwarder_main.rs b/contracts/feature-tests/composability/forwarder/src/forwarder_main.rs index c6e9dcb443..fa75226891 100644 --- a/contracts/feature-tests/composability/forwarder/src/forwarder_main.rs +++ b/contracts/feature-tests/composability/forwarder/src/forwarder_main.rs @@ -7,6 +7,7 @@ pub mod fwd_call_sync; pub mod fwd_call_transf_exec; pub mod fwd_change_owner; pub mod fwd_deploy; +pub mod fwd_dynamic; pub mod fwd_esdt; pub mod fwd_nft; pub mod fwd_roles; @@ -31,6 +32,7 @@ pub trait Forwarder: + fwd_sft::ForwarderSftModule + fwd_nft::ForwarderNftModule + fwd_roles::ForwarderRolesModule + + fwd_dynamic::ForwarderDynamicModule + fwd_storage::ForwarderStorageModule { #[init] diff --git a/contracts/feature-tests/composability/forwarder/src/forwarder_proxy.rs b/contracts/feature-tests/composability/forwarder/src/forwarder_proxy.rs index d8ef19f3a4..efa27be50f 100644 --- a/contracts/feature-tests/composability/forwarder/src/forwarder_proxy.rs +++ b/contracts/feature-tests/composability/forwarder/src/forwarder_proxy.rs @@ -1171,6 +1171,190 @@ where .original_result() } + pub fn issue_dynamic_token< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg, + >( + self, + token_display_name: Arg0, + token_ticker: Arg1, + token_type: Arg2, + num_decimals: Arg3, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("issue_dynamic_token") + .argument(&token_display_name) + .argument(&token_ticker) + .argument(&token_type) + .argument(&num_decimals) + .original_result() + } + + pub fn issue_token_all_roles< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg, + >( + self, + token_display_name: Arg0, + token_ticker: Arg1, + token_type: Arg2, + num_decimals: Arg3, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("issue_token_all_roles") + .argument(&token_display_name) + .argument(&token_ticker) + .argument(&token_type) + .argument(&num_decimals) + .original_result() + } + + pub fn change_to_dynamic< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("change_to_dynamic") + .argument(&token_id) + .original_result() + } + + pub fn update_token< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("update_token") + .argument(&token_id) + .original_result() + } + + pub fn modify_royalties< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg, + >( + self, + token_id: Arg0, + nonce: Arg1, + new_royalty: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("modify_royalties") + .argument(&token_id) + .argument(&nonce) + .argument(&new_royalty) + .original_result() + } + + pub fn set_new_uris< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>>, + >( + self, + token_id: Arg0, + nonce: Arg1, + new_uris: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("set_new_uris") + .argument(&token_id) + .argument(&nonce) + .argument(&new_uris) + .original_result() + } + + pub fn modify_creator< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + token_id: Arg0, + nonce: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("modify_creator") + .argument(&token_id) + .argument(&nonce) + .original_result() + } + + pub fn metadata_recreate< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + Arg3: ProxyArg, + Arg4: ProxyArg>, + Arg5: ProxyArg, + Arg6: ProxyArg>>, + >( + self, + token_id: Arg0, + nonce: Arg1, + name: Arg2, + royalties: Arg3, + hash: Arg4, + new_attributes: Arg5, + uris: Arg6, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("metadata_recreate") + .argument(&token_id) + .argument(&nonce) + .argument(&name) + .argument(&royalties) + .argument(&hash) + .argument(&new_attributes) + .argument(&uris) + .original_result() + } + + pub fn metadata_update< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + Arg3: ProxyArg, + Arg4: ProxyArg>, + Arg5: ProxyArg, + Arg6: ProxyArg>>, + >( + self, + token_id: Arg0, + nonce: Arg1, + name: Arg2, + royalties: Arg3, + hash: Arg4, + new_attributes: Arg5, + uris: Arg6, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("metadata_update") + .argument(&token_id) + .argument(&nonce) + .argument(&name) + .argument(&royalties) + .argument(&hash) + .argument(&new_attributes) + .argument(&uris) + .original_result() + } + pub fn last_issued_token( self, ) -> TxTypedCall> { @@ -1191,7 +1375,7 @@ where } #[type_abi] -#[derive(TopEncode, TopDecode)] +#[derive(TopEncode, TopDecode, Debug)] pub struct CallbackData where Api: ManagedTypeApi, @@ -1204,7 +1388,7 @@ where } #[type_abi] -#[derive(TopEncode, TopDecode, Clone, Copy, PartialEq, Debug)] +#[derive(TopEncode, TopDecode, Clone, Copy, PartialEq, Debug, Default)] pub struct Color { pub r: u8, pub g: u8, diff --git a/contracts/feature-tests/composability/forwarder/src/fwd_call_async.rs b/contracts/feature-tests/composability/forwarder/src/fwd_call_async.rs index 5492a45a10..463cd26465 100644 --- a/contracts/feature-tests/composability/forwarder/src/fwd_call_async.rs +++ b/contracts/feature-tests/composability/forwarder/src/fwd_call_async.rs @@ -4,7 +4,7 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); #[type_abi] -#[derive(TopEncode, TopDecode)] +#[derive(TopEncode, TopDecode, Debug)] pub struct CallbackData { callback_name: ManagedBuffer, token_identifier: EgldOrEsdtTokenIdentifier, diff --git a/contracts/feature-tests/composability/forwarder/src/fwd_dynamic.rs b/contracts/feature-tests/composability/forwarder/src/fwd_dynamic.rs new file mode 100644 index 0000000000..14549d99ad --- /dev/null +++ b/contracts/feature-tests/composability/forwarder/src/fwd_dynamic.rs @@ -0,0 +1,145 @@ +use crate::fwd_nft::{CallbackProxy, Color}; + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait ForwarderDynamicModule: + crate::fwd_nft::ForwarderNftModule + crate::fwd_storage::ForwarderStorageModule +{ + #[payable["EGLD"]] + #[endpoint] + fn issue_dynamic_token( + &self, + token_display_name: ManagedBuffer, + token_ticker: ManagedBuffer, + token_type: EsdtTokenType, + num_decimals: usize, + ) { + let issue_cost = self.call_value().egld_value().clone_value(); + let caller = self.blockchain().get_caller(); + + self.send() + .esdt_system_sc_proxy() + .issue_dynamic( + issue_cost, + token_display_name, + token_ticker, + token_type, + num_decimals, + ) + .callback(self.callbacks().nft_issue_callback(&caller)) + .async_call_and_exit(); + } + + #[payable["EGLD"]] + #[endpoint] + fn issue_token_all_roles( + &self, + token_display_name: ManagedBuffer, + token_ticker: ManagedBuffer, + token_type: EsdtTokenType, + num_decimals: usize, + ) { + let issue_cost = self.call_value().egld_value().clone_value(); + let caller = self.blockchain().get_caller(); + + self.send() + .esdt_system_sc_proxy() + .issue_and_set_all_roles( + issue_cost, + token_display_name, + token_ticker, + token_type, + num_decimals, + ) + .callback(self.callbacks().nft_issue_callback(&caller)) + .async_call_and_exit(); + } + + #[endpoint] + fn change_to_dynamic(&self, token_id: TokenIdentifier) { + self.send() + .esdt_system_sc_proxy() + .change_to_dynamic(token_id) + .async_call_and_exit(); + } + + #[endpoint] + fn update_token(&self, token_id: TokenIdentifier) { + self.send() + .esdt_system_sc_proxy() + .update_token(token_id) + .async_call_and_exit(); + } + + #[endpoint] + fn modify_royalties(&self, token_id: TokenIdentifier, nonce: u64, new_royalty: u64) { + self.send() + .esdt_modify_royalties(&token_id, nonce, new_royalty); + } + + #[endpoint] + fn set_new_uris( + &self, + token_id: TokenIdentifier, + nonce: u64, + new_uris: MultiValueEncoded, + ) { + let new_uris = new_uris.to_vec(); + self.send() + .esdt_nft_set_new_uris(&token_id, nonce, &new_uris); + } + + #[endpoint] + fn modify_creator(&self, token_id: TokenIdentifier, nonce: u64) { + self.send().esdt_nft_modify_creator(&token_id, nonce); + } + + #[endpoint] + fn metadata_recreate( + &self, + token_id: TokenIdentifier, + nonce: u64, + name: ManagedBuffer, + royalties: u64, + hash: ManagedBuffer, + new_attributes: Color, + uris: MultiValueEncoded, + ) { + let uris = uris.to_vec(); + + self.send().esdt_metadata_recreate( + token_id, + nonce, + name, + royalties, + hash, + &new_attributes, + uris, + ); + } + + #[endpoint] + fn metadata_update( + &self, + token_id: TokenIdentifier, + nonce: u64, + name: ManagedBuffer, + royalties: u64, + hash: ManagedBuffer, + new_attributes: Color, + uris: MultiValueEncoded, + ) { + let uris = uris.to_vec(); + + self.send().esdt_metadata_update( + token_id, + nonce, + name, + royalties, + hash, + &new_attributes, + uris, + ); + } +} diff --git a/contracts/feature-tests/composability/forwarder/src/fwd_nft.rs b/contracts/feature-tests/composability/forwarder/src/fwd_nft.rs index 5358397df9..53f01ec5ea 100644 --- a/contracts/feature-tests/composability/forwarder/src/fwd_nft.rs +++ b/contracts/feature-tests/composability/forwarder/src/fwd_nft.rs @@ -5,7 +5,7 @@ use super::fwd_storage; // used as mock attributes for NFTs #[type_abi] -#[derive(TopEncode, TopDecode, Clone, Copy, PartialEq, Debug)] +#[derive(TopEncode, TopDecode, Clone, Copy, PartialEq, Debug, Default)] pub struct Color { pub r: u8, pub g: u8, @@ -13,7 +13,7 @@ pub struct Color { } #[type_abi] -#[derive(TopEncode, TopDecode, PartialEq, Eq, Clone)] +#[derive(TopEncode, TopDecode, PartialEq, Eq, Clone, Debug)] pub struct ComplexAttributes { pub biguint: BigUint, pub vec_u8: ManagedBuffer, diff --git a/contracts/feature-tests/composability/forwarder/wasm/src/lib.rs b/contracts/feature-tests/composability/forwarder/wasm/src/lib.rs index 74d50dd752..b9be382059 100644 --- a/contracts/feature-tests/composability/forwarder/wasm/src/lib.rs +++ b/contracts/feature-tests/composability/forwarder/wasm/src/lib.rs @@ -5,9 +5,9 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 69 +// Endpoints: 78 // Async Callback: 1 -// Total number of exported functions: 71 +// Total number of exported functions: 80 #![no_std] @@ -85,6 +85,15 @@ multiversx_sc_wasm_adapter::endpoints! { create_and_send => create_and_send setLocalRoles => set_local_roles unsetLocalRoles => unset_local_roles + issue_dynamic_token => issue_dynamic_token + issue_token_all_roles => issue_token_all_roles + change_to_dynamic => change_to_dynamic + update_token => update_token + modify_royalties => modify_royalties + set_new_uris => set_new_uris + modify_creator => modify_creator + metadata_recreate => metadata_recreate + metadata_update => metadata_update lastIssuedToken => last_issued_token lastErrorMessage => last_error_message ) diff --git a/framework/base/src/contract_base/wrappers/send_wrapper.rs b/framework/base/src/contract_base/wrappers/send_wrapper.rs index 0c23b67cd4..9fe01f232a 100644 --- a/framework/base/src/contract_base/wrappers/send_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/send_wrapper.rs @@ -53,7 +53,7 @@ where self.esdt_system_sc_tx() } - /// Prepares a proxy object to call the system SC. + /// Prepares a proxy object to call the ESDT system SC. /// It has the destination address set, as well as the contract type (as specified in the proxy). pub fn esdt_system_sc_tx( &self, @@ -763,4 +763,84 @@ where .nft_update_attributes(token_id, nft_nonce, new_attributes) .sync_call() } + + /// Modifies royalties for a specific token. + pub fn esdt_modify_royalties( + &self, + token_id: &TokenIdentifier, + nonce: u64, + new_royalty: u64, + ) { + Tx::new_tx_from_sc() + .to(ToSelf) + .gas(GasLeft) + .typed(system_proxy::UserBuiltinProxy) + .esdt_modify_royalties(token_id, nonce, new_royalty) + .sync_call() + } + + /// Sets new uris for a specific token. + pub fn esdt_nft_set_new_uris( + &self, + token_id: &TokenIdentifier, + nonce: u64, + uris: &ManagedVec>, + ) { + Tx::new_tx_from_sc() + .to(ToSelf) + .gas(GasLeft) + .typed(system_proxy::UserBuiltinProxy) + .esdt_nft_set_new_uris(token_id, nonce, uris) + .sync_call() + } + + /// Changes the creator of a specific token into the caller. + pub fn esdt_nft_modify_creator(&self, token_id: &TokenIdentifier, nonce: u64) { + Tx::new_tx_from_sc() + .to(ToSelf) + .gas(GasLeft) + .typed(system_proxy::UserBuiltinProxy) + .esdt_nft_modify_creator(token_id, nonce) + .sync_call() + } + + /// Recreates an ESDT token with the newly specified attributes. + #[allow(clippy::too_many_arguments)] + pub fn esdt_metadata_recreate( + &self, + token_id: TokenIdentifier, + nonce: u64, + name: ManagedBuffer, + royalties: u64, + hash: ManagedBuffer, + new_attributes: &T, + uris: ManagedVec>, + ) { + Tx::new_tx_from_sc() + .to(ToSelf) + .gas(GasLeft) + .typed(system_proxy::UserBuiltinProxy) + .esdt_metadata_recreate(token_id, nonce, name, royalties, hash, new_attributes, uris) + .sync_call() + } + + /// Updates an ESDT token with the newly specified attributes. + #[allow(clippy::too_many_arguments)] + pub fn esdt_metadata_update( + &self, + token_id: TokenIdentifier, + nonce: u64, + name: ManagedBuffer, + royalties: u64, + hash: ManagedBuffer, + new_attributes: &T, + uris: ManagedVec>, + ) { + Tx::new_tx_from_sc() + .to(ToSelf) + .gas(GasLeft) + .typed(system_proxy::UserBuiltinProxy) + .esdt_metadata_update(token_id, nonce, name, royalties, hash, new_attributes, uris) + .sync_call() + } } diff --git a/framework/base/src/types/interaction/system_proxy/builtin_func_proxy.rs b/framework/base/src/types/interaction/system_proxy/builtin_func_proxy.rs index 1bf7c3a1fc..601f978393 100644 --- a/framework/base/src/types/interaction/system_proxy/builtin_func_proxy.rs +++ b/framework/base/src/types/interaction/system_proxy/builtin_func_proxy.rs @@ -7,9 +7,11 @@ use crate::types::{ use crate::chain_core::builtin_func_names::{ CHANGE_OWNER_BUILTIN_FUNC_NAME, CLAIM_DEVELOPER_REWARDS_FUNC_NAME, DELETE_USERNAME_FUNC_NAME, - ESDT_LOCAL_BURN_FUNC_NAME, ESDT_LOCAL_MINT_FUNC_NAME, ESDT_NFT_ADD_QUANTITY_FUNC_NAME, - ESDT_NFT_ADD_URI_FUNC_NAME, ESDT_NFT_BURN_FUNC_NAME, ESDT_NFT_CREATE_FUNC_NAME, - ESDT_NFT_UPDATE_ATTRIBUTES_FUNC_NAME, SET_USERNAME_FUNC_NAME, + ESDT_LOCAL_BURN_FUNC_NAME, ESDT_LOCAL_MINT_FUNC_NAME, ESDT_METADATA_RECREATE_FUNC_NAME, + ESDT_METADATA_UPDATE_FUNC_NAME, ESDT_MODIFY_CREATOR_FUNC_NAME, ESDT_MODIFY_ROYALTIES_FUNC_NAME, + ESDT_NFT_ADD_QUANTITY_FUNC_NAME, ESDT_NFT_ADD_URI_FUNC_NAME, ESDT_NFT_BURN_FUNC_NAME, + ESDT_NFT_CREATE_FUNC_NAME, ESDT_NFT_UPDATE_ATTRIBUTES_FUNC_NAME, ESDT_SET_NEW_URIS_FUNC_NAME, + SET_USERNAME_FUNC_NAME, }; /// Proxy describing the user builtin function signatures. @@ -214,4 +216,136 @@ where tx.original_result() } + + pub fn esdt_modify_royalties< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg, + >( + self, + token_id: Arg0, + nonce: Arg1, + new_royalty: Arg2, + ) -> TxTypedCall { + let tx = self + .wrapped_tx + .payment(NotPayable) + .raw_call(ESDT_MODIFY_ROYALTIES_FUNC_NAME) + .argument(&token_id) + .argument(&nonce) + .argument(&new_royalty); + + tx.original_result() + } + + pub fn esdt_nft_set_new_uris>, Arg1: ProxyArg>( + self, + token_id: Arg0, + nonce: Arg1, + uris: &ManagedVec>, + ) -> TxTypedCall { + let mut tx = self + .wrapped_tx + .payment(NotPayable) + .raw_call(ESDT_SET_NEW_URIS_FUNC_NAME) + .argument(&token_id) + .argument(&nonce); + + if uris.is_empty() { + // at least one URI is required, so we push an empty one + tx = tx.argument(&Empty); + } else { + // The API function has the last argument as variadic, + // so we top-encode each and send as separate argument + for uri in uris { + tx = tx.argument(&uri); + } + } + + tx.original_result() + } + + pub fn esdt_nft_modify_creator< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + token_id: Arg0, + nonce: Arg1, + ) -> TxTypedCall { + let tx = self + .wrapped_tx + .payment(NotPayable) + .raw_call(ESDT_MODIFY_CREATOR_FUNC_NAME) + .argument(&token_id) + .argument(&nonce); + + tx.original_result() + } + + #[allow(clippy::too_many_arguments)] + pub fn esdt_metadata_recreate< + T: TopEncode, + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + Arg3: ProxyArg, + Arg4: ProxyArg>, + >( + self, + token_id: Arg0, + nonce: Arg1, + name: Arg2, + royalties: Arg3, + hash: Arg4, + new_attributes: &T, + uris: ManagedVec>, + ) -> TxTypedCall { + let tx = self + .wrapped_tx + .payment(NotPayable) + .raw_call(ESDT_METADATA_RECREATE_FUNC_NAME) + .argument(&token_id) + .argument(&nonce) + .argument(&name) + .argument(&royalties) + .argument(&hash) + .argument(&new_attributes) + .argument(&uris); + + tx.original_result() + } + + #[allow(clippy::too_many_arguments)] + pub fn esdt_metadata_update< + T: TopEncode, + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + Arg3: ProxyArg, + Arg4: ProxyArg>, + >( + self, + token_id: Arg0, + nonce: Arg1, + name: Arg2, + royalties: Arg3, + hash: Arg4, + new_attributes: &T, + uris: ManagedVec>, + ) -> TxTypedCall { + let tx = self + .wrapped_tx + .payment(NotPayable) + .raw_call(ESDT_METADATA_UPDATE_FUNC_NAME) + .argument(&token_id) + .argument(&nonce) + .argument(&name) + .argument(&royalties) + .argument(&hash) + .argument(&new_attributes) + .argument(&uris); + + tx.original_result() + } } diff --git a/framework/base/src/types/interaction/system_proxy/esdt_system_sc_proxy.rs b/framework/base/src/types/interaction/system_proxy/esdt_system_sc_proxy.rs index 979f9d1d60..7e4e0fb4ed 100644 --- a/framework/base/src/types/interaction/system_proxy/esdt_system_sc_proxy.rs +++ b/framework/base/src/types/interaction/system_proxy/esdt_system_sc_proxy.rs @@ -14,6 +14,8 @@ const ISSUE_NON_FUNGIBLE_ENDPOINT_NAME: &str = "issueNonFungible"; const ISSUE_SEMI_FUNGIBLE_ENDPOINT_NAME: &str = "issueSemiFungible"; const REGISTER_META_ESDT_ENDPOINT_NAME: &str = "registerMetaESDT"; const ISSUE_AND_SET_ALL_ROLES_ENDPOINT_NAME: &str = "registerAndSetAllRoles"; +const REGISTER_DYNAMIC_ESDT_ENDPOINT_NAME: &str = "registerDynamic"; +const REGISTER_AND_SET_ALL_ROLES_DYNAMIC_ESDT_ENDPOINT_NAME: &str = "registerAndSetAllRolesDynamic"; /// The specific `Tx` type produces by the issue operations of the ESDTSystemSCProxy. pub type IssueCall = Tx< @@ -211,20 +213,78 @@ where ) -> IssueCall { let token_type_name = match token_type { EsdtTokenType::Fungible => "FNG", - EsdtTokenType::NonFungible => "NFT", - EsdtTokenType::SemiFungible => "SFT", - EsdtTokenType::Meta => "META", + EsdtTokenType::NonFungible | EsdtTokenType::DynamicNFT => "NFT", + EsdtTokenType::SemiFungible | EsdtTokenType::DynamicSFT => "SFT", + EsdtTokenType::Meta | EsdtTokenType::DynamicMeta => "META", EsdtTokenType::Invalid => "", }; - self.wrapped_tx - .raw_call(ISSUE_AND_SET_ALL_ROLES_ENDPOINT_NAME) + let endpoint = match token_type { + EsdtTokenType::Fungible + | EsdtTokenType::NonFungible + | EsdtTokenType::SemiFungible + | EsdtTokenType::Meta => ISSUE_AND_SET_ALL_ROLES_ENDPOINT_NAME, + EsdtTokenType::DynamicNFT | EsdtTokenType::DynamicSFT | EsdtTokenType::DynamicMeta => { + REGISTER_AND_SET_ALL_ROLES_DYNAMIC_ESDT_ENDPOINT_NAME + }, + + EsdtTokenType::Invalid => "", + }; + + let mut tx = self + .wrapped_tx + .raw_call(endpoint) .egld(issue_cost) .argument(&token_display_name) .argument(&token_ticker) - .argument(&token_type_name) - .argument(&num_decimals) - .original_result() + .argument(&token_type_name); + + if token_type != EsdtTokenType::DynamicNFT && token_type != EsdtTokenType::DynamicSFT { + tx = tx.argument(&num_decimals); + } + + tx.original_result() + } + + /// Issues dynamic ESDT tokens + pub fn issue_dynamic< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + issue_cost: BigUint, + token_display_name: Arg0, + token_ticker: Arg1, + token_type: EsdtTokenType, + num_decimals: usize, + ) -> IssueCall { + let endpoint_name = match token_type { + EsdtTokenType::DynamicNFT | EsdtTokenType::DynamicSFT | EsdtTokenType::DynamicMeta => { + REGISTER_DYNAMIC_ESDT_ENDPOINT_NAME + }, + _ => "", + }; + + let token_type_name = match token_type { + EsdtTokenType::DynamicNFT => "NFT", + EsdtTokenType::DynamicSFT => "SFT", + EsdtTokenType::DynamicMeta => "META", + _ => "", + }; + + let mut tx = self + .wrapped_tx + .raw_call(endpoint_name) + .egld(issue_cost) + .argument(&token_display_name) + .argument(&token_ticker) + .argument(&token_type_name); + + if token_type != EsdtTokenType::DynamicNFT && token_type != EsdtTokenType::DynamicSFT { + tx = tx.argument(&num_decimals); + } + + tx.original_result() } /// Deduplicates code from all the possible issue functions @@ -246,7 +306,7 @@ where EsdtTokenType::NonFungible => ISSUE_NON_FUNGIBLE_ENDPOINT_NAME, EsdtTokenType::SemiFungible => ISSUE_SEMI_FUNGIBLE_ENDPOINT_NAME, EsdtTokenType::Meta => REGISTER_META_ESDT_ENDPOINT_NAME, - EsdtTokenType::Invalid => "", + _ => "", }; let mut tx = self @@ -579,6 +639,31 @@ where append_token_property_arguments(&mut tx.data, property_arguments); tx.original_result() } + + /// Changes token to dynamic. + /// Does not work for: FungibleESDT, NonFungibleESDT, NonFungibleESDTv2. + pub fn change_to_dynamic>>( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("changeToDynamic") + .argument(&token_id) + .original_result() + } + + /// Updates a specific token to the newest version. + pub fn update_token>>( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("updateTokenID") + .argument(&token_id) + .original_result() + } } const TRUE_STR: &str = "true"; diff --git a/framework/base/src/types/interaction/system_proxy/legacy_system_sc_proxy.rs b/framework/base/src/types/interaction/system_proxy/legacy_system_sc_proxy.rs index 6f74b80812..3f5d9aaccb 100644 --- a/framework/base/src/types/interaction/system_proxy/legacy_system_sc_proxy.rs +++ b/framework/base/src/types/interaction/system_proxy/legacy_system_sc_proxy.rs @@ -17,6 +17,8 @@ const ISSUE_NON_FUNGIBLE_ENDPOINT_NAME: &str = "issueNonFungible"; const ISSUE_SEMI_FUNGIBLE_ENDPOINT_NAME: &str = "issueSemiFungible"; const REGISTER_META_ESDT_ENDPOINT_NAME: &str = "registerMetaESDT"; const ISSUE_AND_SET_ALL_ROLES_ENDPOINT_NAME: &str = "registerAndSetAllRoles"; +const REGISTER_DYNAMIC_ESDT_ENDPOINT_NAME: &str = "registerDynamic"; +const REGISTER_AND_SET_ALL_ROLES_DYNAMIC_ESDT_ENDPOINT_NAME: &str = "registerAndSetAllRolesDynamic"; /// Proxy for the ESDT system smart contract. /// Unlike other contract proxies, this one has a fixed address, @@ -185,21 +187,75 @@ where let token_type_name = match token_type { EsdtTokenType::Fungible => "FNG", - EsdtTokenType::NonFungible => "NFT", - EsdtTokenType::SemiFungible => "SFT", - EsdtTokenType::Meta => "META", + EsdtTokenType::NonFungible | EsdtTokenType::DynamicNFT => "NFT", + EsdtTokenType::SemiFungible | EsdtTokenType::DynamicSFT => "SFT", + EsdtTokenType::Meta | EsdtTokenType::DynamicMeta => "META", EsdtTokenType::Invalid => "", }; - ContractCallWithEgld::new( - esdt_system_sc_address, - ISSUE_AND_SET_ALL_ROLES_ENDPOINT_NAME, - issue_cost, - ) - .argument(&token_display_name) - .argument(&token_ticker) - .argument(&token_type_name) - .argument(&num_decimals) + let endpoint = match token_type { + EsdtTokenType::Fungible + | EsdtTokenType::NonFungible + | EsdtTokenType::SemiFungible + | EsdtTokenType::Meta => ISSUE_AND_SET_ALL_ROLES_ENDPOINT_NAME, + + EsdtTokenType::DynamicNFT | EsdtTokenType::DynamicSFT | EsdtTokenType::DynamicMeta => { + REGISTER_AND_SET_ALL_ROLES_DYNAMIC_ESDT_ENDPOINT_NAME + }, + + EsdtTokenType::Invalid => "", + }; + + let mut contract_call = + ContractCallWithEgld::new(esdt_system_sc_address, endpoint, issue_cost) + .argument(&token_display_name) + .argument(&token_ticker) + .argument(&token_type_name); + + if token_type != EsdtTokenType::DynamicNFT { + contract_call = contract_call.argument(&num_decimals); + } + + contract_call + } + + /// Issues dynamic ESDT tokens + pub fn issue_dynamic( + self, + issue_cost: BigUint, + token_display_name: &ManagedBuffer, + token_ticker: &ManagedBuffer, + token_type: EsdtTokenType, + num_decimals: usize, + ) -> ContractCallWithEgld { + let esdt_system_sc_address = self.esdt_system_sc_address(); + + let endpoint_name = match token_type { + EsdtTokenType::DynamicNFT | EsdtTokenType::DynamicSFT | EsdtTokenType::DynamicMeta => { + REGISTER_DYNAMIC_ESDT_ENDPOINT_NAME + }, + _ => "", + }; + + let token_type_name = match token_type { + EsdtTokenType::DynamicNFT => "NFT", + EsdtTokenType::DynamicSFT => "SFT", + EsdtTokenType::DynamicMeta => "META", + _ => "", + }; + + let mut contract_call = + ContractCallWithEgld::new(esdt_system_sc_address, endpoint_name, issue_cost); + + contract_call.proxy_arg(token_display_name); + contract_call.proxy_arg(token_ticker); + contract_call.proxy_arg(&token_type_name); + + if token_type != EsdtTokenType::DynamicNFT { + contract_call.proxy_arg(&num_decimals); + } + + contract_call } /// Deduplicates code from all the possible issue functions @@ -219,7 +275,7 @@ where EsdtTokenType::NonFungible => ISSUE_NON_FUNGIBLE_ENDPOINT_NAME, EsdtTokenType::SemiFungible => ISSUE_SEMI_FUNGIBLE_ENDPOINT_NAME, EsdtTokenType::Meta => REGISTER_META_ESDT_ENDPOINT_NAME, - EsdtTokenType::Invalid => "", + _ => "", }; let mut contract_call = diff --git a/framework/meta/Cargo.toml b/framework/meta/Cargo.toml index 3d92426f81..1b07fca11b 100644 --- a/framework/meta/Cargo.toml +++ b/framework/meta/Cargo.toml @@ -40,7 +40,8 @@ copy_dir = "0.1.2" pathdiff = "0.2.1" common-path = "1.0.0" bip39 = "2.0.0" -home = "0.5.2" +# TODO: 0.5.11 doesn't support rustc 1.80, needs >= 1.81 (issue on ci/cd for nightly builds) +home = "=0.5.5" [dependencies.multiversx-sc-meta-lib] version = "=0.54.5" diff --git a/framework/snippets/src/network_response.rs b/framework/snippets/src/network_response.rs index c17ae4456d..3e6bb2931d 100644 --- a/framework/snippets/src/network_response.rs +++ b/framework/snippets/src/network_response.rs @@ -173,12 +173,17 @@ fn process_new_issued_token_identifier(tx: &TransactionOnNetwork) -> Option { basic_interact - .issue_token( + .issue_token_all_roles( args.cost.clone(), args.display_name.as_bytes(), args.ticker.as_bytes(), @@ -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,22 +221,23 @@ async fn main() { } } -#[allow(unused)] -struct SysFuncCallsInteract { +pub struct SysFuncCallsInteract { interactor: Interactor, wallet_address: Bech32Address, + other_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; + let other_wallet_address = interactor.register_wallet(test_wallets::mike()).await; // generate blocks until ESDTSystemSCAddress is enabled interactor.generate_blocks_until_epoch(1).await.unwrap(); @@ -242,11 +245,12 @@ impl SysFuncCallsInteract { Self { interactor, wallet_address: wallet_address.into(), + other_wallet_address: other_wallet_address.into(), state: State::load_state(), } } - async fn issue_fungible_token( + pub async fn issue_fungible_token( &mut self, issue_cost: RustBigUint, token_display_name: &[u8], @@ -281,14 +285,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 +321,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 +357,54 @@ impl SysFuncCallsInteract { }, ) .returns(ReturnsNewTokenIdentifier) - .prepare_async() .run() .await; println!("SFT Collection ID: {:?}", sft_collection_id); } - async fn issue_token( + pub async fn issue_dynamic_token( + &mut self, + issue_cost: RustBigUint, + token_display_name: &[u8], + token_ticker: &[u8], + token_type: EsdtTokenType, + num_decimals: usize, + ) -> String { + println!("Registering dynamic token {token_ticker:?} of type {token_type:?}..."); + + let token_id = self + .interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .issue_dynamic( + issue_cost.into(), + token_display_name, + token_ticker, + token_type, + num_decimals, + ) + .returns(ReturnsNewTokenIdentifier) + .run() + .await; + + println!("TOKEN ID: {:?}", token_id); + + token_id + } + + pub async fn issue_token_all_roles( &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 +421,36 @@ 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_for_other(&mut self, token_id: &[u8], roles: Vec) { + let wallet_address = &self.other_wallet_address.clone().into_address(); + println!("Setting the following roles: {roles:?} for {token_id:?} for other_address"); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .set_special_roles( + ManagedAddress::from_address(wallet_address), + TokenIdentifier::from(token_id), + roles.into_iter(), + ) + .run() + .await; + } + + 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 +463,39 @@ impl SysFuncCallsInteract { TokenIdentifier::from(token_id), roles.into_iter(), ) - .prepare_async() .run() .await; } - async fn mint_sft( + pub async fn change_to_dynamic(&mut self, token_id: &[u8]) { + println!("Changing the following token {token_id:?} to dynamic..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .change_to_dynamic(TokenIdentifier::from(token_id)) + .run() + .await; + } + + pub async fn update_token(&mut self, token_id: &[u8]) { + println!("Updating the following token {token_id:?} to the newest version..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .update_token(TokenIdentifier::from(token_id)) + .run() + .await; + } + + pub async fn mint_sft( &mut self, token_id: &[u8], amount: RustBigUint, @@ -442,12 +523,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 +559,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 +575,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 +589,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 +603,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 +617,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 +631,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 +645,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 +659,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 +673,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 +687,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 +701,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 +715,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 +764,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 +778,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 +797,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 +824,126 @@ impl SysFuncCallsInteract { can_add_special_roles: Some(true), }, ) - .prepare_async() + .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; + } + + pub async fn send_esdt(&mut self, token_id: &[u8], nonce: u64, amount: RustBigUint) { + println!("Sending token {token_id:?} with nonce {nonce:?} to other_wallet_address..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(&self.other_wallet_address) + .single_esdt(&token_id.into(), nonce, &amount.into()) // .transfer() + .run() + .await; + } + + // changes creator into caller + pub async fn modify_creator(&mut self, token_id: &[u8], nonce: u64) { + println!( + "Modifying the creator (into caller - other_wallet_address) for token {token_id:?} with nonce {nonce:?}..." + ); + + self.interactor + .tx() + .from(&self.other_wallet_address) + .to(&self.other_wallet_address) + .gas(100_000_000u64) + .typed(UserBuiltinProxy) + .esdt_nft_modify_creator(token_id, nonce) + .run() + .await; + } + + #[allow(clippy::too_many_arguments)] + pub async fn metadata_recreate( + &mut self, + token_id: &[u8], + nonce: u64, + name: &[u8], + royalties: u64, + hash: &[u8], + new_attributes: &T, + uris: Vec, + ) { + println!("Recreating the token {token_id:?} with nonce {nonce:?} with new attributes..."); + + 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_metadata_recreate(token_id, nonce, name, royalties, hash, new_attributes, uris) + .run() + .await; + } + + #[allow(clippy::too_many_arguments)] + pub async fn metadata_update( + &mut self, + token_id: &[u8], + nonce: u64, + name: &[u8], + royalties: u64, + hash: &[u8], + new_attributes: &T, + uris: Vec, + ) { + println!("Updating the token {token_id:?} with nonce {nonce:?} with new attributes..."); + + 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_metadata_update(token_id, nonce, name, royalties, hash, new_attributes, uris) .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..f950dc7592 --- /dev/null +++ b/tools/interactor-system-func-calls/tests/chain_simulator_token_tests.rs @@ -0,0 +1,276 @@ +use multiversx_sc_snippets::imports::{EsdtLocalRole, EsdtTokenType, RustBigUint}; +use system_sc_interact::{Config, NftDummyAttributes, SysFuncCallsInteract}; + +const ISSUE_COST: u64 = 50000000000000000u64; + +// real blockchain tests for now, fixes needed for chain simulator +#[tokio::test] +#[ignore = "run on demand"] +async fn cs_builtin_func_tokens_test() { + // let mut interact = SysFuncCallsInteract::init(Config::chain_simulator_config()).await; + + let mut interact = SysFuncCallsInteract::init(Config::load_config()).await; + + // issue dynamic NFT + interact + .issue_dynamic_token( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + EsdtTokenType::DynamicNFT, + 0usize, + ) + .await; + + // issue dynamic SFT + interact + .issue_dynamic_token( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + EsdtTokenType::DynamicSFT, + 0usize, + ) + .await; + + // issue dynamic META + interact + .issue_dynamic_token( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + EsdtTokenType::DynamicMeta, + 18usize, + ) + .await; + + // issue dynamic META with all roles + let _ = interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 0usize, + EsdtTokenType::DynamicMeta, + ) + .await; + + // issue dynamic SFT with all roles + let _ = interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 0usize, + EsdtTokenType::DynamicSFT, + ) + .await; + + // issue dynamic NFT with all roles + let dynamic_nft_token_id = interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + 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:?}"); + + // metadata update + interact + .metadata_update( + dynamic_nft_token_id.as_bytes(), + nonce, + b"TESTNFT", + 30u64, + b"new_hash", + &NftDummyAttributes { + creation_epoch: 3u64, + cool_factor: 5u8, + }, + Vec::new(), + ) + .await; + + println!("Metadata updated for {dynamic_nft_token_id:?} with nonce {nonce:?}"); + + // metadata recreate + interact + .metadata_recreate( + dynamic_nft_token_id.as_bytes(), + nonce, + b"TESTNFT", + 30u64, + b"new_hash_recreated", + &NftDummyAttributes { + creation_epoch: 100u64, + cool_factor: 1u8, + }, + Vec::new(), + ) + .await; + + println!("Metadata recreated for {dynamic_nft_token_id:?} with nonce {nonce:?}. A new token has been created."); +} + +#[tokio::test] +#[ignore = "run on demand"] +async fn change_to_dynamic_test() { + let mut interact = SysFuncCallsInteract::init(Config::load_config()).await; + + // issue NFT with all roles + let _ = interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 0usize, + EsdtTokenType::NonFungible, + ) + .await; + + // issue META token with all roles + let meta_token_id = interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 18usize, + EsdtTokenType::Meta, + ) + .await; + + // change META to dynamic + interact.change_to_dynamic(meta_token_id.as_bytes()).await; + + // issue SFT token with all roles + let sft_token_id = interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 18usize, + EsdtTokenType::SemiFungible, + ) + .await; + + // change SFT to dynamic + interact.change_to_dynamic(sft_token_id.as_bytes()).await; +} + +#[tokio::test] +#[ignore = "run on demand"] +async fn update_token_test() { + let mut interact = SysFuncCallsInteract::init(Config::load_config()).await; + + // issue NFT with all roles + let nft_token_id = interact + .issue_token_all_roles( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + 0usize, + EsdtTokenType::NonFungible, + ) + .await; + + // update NFT + interact.update_token(nft_token_id.as_bytes()).await; +} + +#[tokio::test] +#[ignore = "run on demand"] +async fn modify_creator() { + let mut interact = SysFuncCallsInteract::init(Config::load_config()).await; + + // issue dynamic NFT + let dynamic_nft_token_id = interact + .issue_dynamic_token( + RustBigUint::from(ISSUE_COST), + b"TESTNFT", + b"TEST", + EsdtTokenType::DynamicNFT, + 0usize, + ) + .await; + + // set roles + interact + .set_roles( + dynamic_nft_token_id.as_bytes(), + vec![EsdtLocalRole::NftCreate], + ) + .await; + + // 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:?}"); + + // set roles for other_address + interact + .set_roles_for_other( + dynamic_nft_token_id.as_bytes(), + vec![EsdtLocalRole::ModifyCreator], + ) + .await; + + // send to other_address + interact + .send_esdt(dynamic_nft_token_id.as_bytes(), 1u64, 1u64.into()) + .await; + + // modify creator + interact + .modify_creator(dynamic_nft_token_id.as_bytes(), nonce) + .await; +}