From 1c91d5c3ddcca0f041933bbea57a664ab33bd82a Mon Sep 17 00:00:00 2001 From: Lara Tifui Date: Mon, 8 Sep 2025 05:19:33 +0200 Subject: [PATCH 1/5] setup parser for cli_token --- multiversx_sdk_cli/cli.py | 2 ++ multiversx_sdk_cli/cli_token.py | 53 +++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 multiversx_sdk_cli/cli_token.py diff --git a/multiversx_sdk_cli/cli.py b/multiversx_sdk_cli/cli.py index 8ad91fd5..f9eff03e 100644 --- a/multiversx_sdk_cli/cli.py +++ b/multiversx_sdk_cli/cli.py @@ -23,6 +23,7 @@ import multiversx_sdk_cli.cli_ledger import multiversx_sdk_cli.cli_localnet import multiversx_sdk_cli.cli_multisig +import multiversx_sdk_cli.cli_token import multiversx_sdk_cli.cli_transactions import multiversx_sdk_cli.cli_validator_wallet import multiversx_sdk_cli.cli_validators @@ -142,6 +143,7 @@ def setup_parser(args: list[str]): commands.append(multiversx_sdk_cli.cli_governance.setup_parser(args, subparsers)) commands.append(multiversx_sdk_cli.cli_config_env.setup_parser(subparsers)) commands.append(multiversx_sdk_cli.cli_get.setup_parser(subparsers)) + commands.append(multiversx_sdk_cli.cli_token.setup_parser(args, subparsers)) parser.epilog = """ ---------------------- diff --git a/multiversx_sdk_cli/cli_token.py b/multiversx_sdk_cli/cli_token.py new file mode 100644 index 00000000..7ace42a7 --- /dev/null +++ b/multiversx_sdk_cli/cli_token.py @@ -0,0 +1,53 @@ +from typing import Any + +from multiversx_sdk_cli import cli_shared +from multiversx_sdk_cli.cli_output import CLIOutputBuilder +from multiversx_sdk_cli.cli_transactions import _add_common_arguments + + +def setup_parser(args: list[str], subparsers: Any) -> Any: + parser = cli_shared.add_group_subparser(subparsers, "token", "Perform operations with tokens") + subparsers = parser.add_subparsers() + + sub = cli_shared.add_command_subparser( + subparsers, + "token", + "issue-fungible", + f"Issue a new fungible ESDT token.{CLIOutputBuilder.describe()}", + ) + sub.add_argument( + "--token-name", + required=True, + type=str, + help="the name of the token to be issued: 3-20 alphanumerical characters", + ) + sub.add_argument( + "--token-ticker", + required=True, + type=str, + help="the ticker of the token to be issued: 3-10 UPPERCASE alphanumerical characters", + ) + sub.add_argument("--initial-supply", required=True, type=int, help="the initial supply of the token to be issued") + sub.add_argument( + "--num-decimals", + required=True, + type=int, + help="a numerical value between 0 and 18 representing number of decimals", + ) + sub.add_argument("--can-freeze", type=bool, help="whether a token can be freezed") + sub.add_argument("--can-wipe", type=bool, help="whether a token can be wiped") + sub.add_argument("--can-pause", type=bool, help="whether a token can be paused") + sub.add_argument("--can-change-owner", type=bool, help="whether a token can change owner") + sub.add_argument("--can-upgrade", type=bool, help="whether a token can be upgraded") + sub.add_argument("--can-add_special-roles", type=bool, help="whether special roles can be added for the token") + + _add_common_arguments(args, sub) + cli_shared.add_broadcast_args(sub) + cli_shared.add_proxy_arg(sub) + cli_shared.add_wait_result_and_timeout_args(sub) + + sub.set_defaults(func=issue_fungible) + + +def issue_fungible(arg: Any): + pass From cb5d4723d2d56d0bce21cf91987720df3f195320 Mon Sep 17 00:00:00 2001 From: Lara Tifui Date: Mon, 8 Sep 2025 06:37:47 +0200 Subject: [PATCH 2/5] added token wraper and issue fungible --- multiversx_sdk_cli/cli_token.py | 56 ++++++++++++++++++++++- multiversx_sdk_cli/token.py | 79 +++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 multiversx_sdk_cli/token.py diff --git a/multiversx_sdk_cli/cli_token.py b/multiversx_sdk_cli/cli_token.py index 7ace42a7..7746c9d4 100644 --- a/multiversx_sdk_cli/cli_token.py +++ b/multiversx_sdk_cli/cli_token.py @@ -1,8 +1,15 @@ from typing import Any +from multiversx_sdk import TransactionsFactoryConfig + from multiversx_sdk_cli import cli_shared +from multiversx_sdk_cli.args_validation import ( + validate_broadcast_args, + validate_chain_id_args, +) from multiversx_sdk_cli.cli_output import CLIOutputBuilder from multiversx_sdk_cli.cli_transactions import _add_common_arguments +from multiversx_sdk_cli.token import TokenWrapper def setup_parser(args: list[str], subparsers: Any) -> Any: @@ -45,9 +52,56 @@ def setup_parser(args: list[str], subparsers: Any) -> Any: cli_shared.add_broadcast_args(sub) cli_shared.add_proxy_arg(sub) cli_shared.add_wait_result_and_timeout_args(sub) + cli_shared.add_guardian_wallet_args(args, sub) + cli_shared.add_relayed_v3_wallet_args(args, sub) + cli_shared.add_outfile_arg(sub) sub.set_defaults(func=issue_fungible) + parser.epilog = cli_shared.build_group_epilog(subparsers) + return subparsers + -def issue_fungible(arg: Any): +def validate_token_args(args: Any): pass + + +def _ensure_args(args: Any): + validate_broadcast_args(args) + validate_chain_id_args(args) + validate_token_args(args) + + +def issue_fungible(args: Any): + _ensure_args(args) + + sender = cli_shared.prepare_sender(args) + guardian_and_relayer_data = cli_shared.get_guardian_and_relayer_data( + sender=sender.address.to_bech32(), + args=args, + ) + chain_id = cli_shared.get_chain_id(args.proxy, args.chain) + gas_estimator = cli_shared.initialize_gas_limit_estimator(args) + controller = TokenWrapper(config=TransactionsFactoryConfig(chain_id), gas_limit_estimator=gas_estimator) + + transaction = controller.create_transaction_for_issuing_fungible_token( + sender=sender, + nonce=sender.nonce, + token_name=args.token_name, + token_ticker=args.token_ticker, + initial_supply=args.initial_supply, + num_decimals=args.num_decimals, + gas_limit=args.gas_limit, + gas_price=args.gas_price, + version=args.version, + options=args.options, + guardian_and_relayer_data=guardian_and_relayer_data, + can_freeze=args.can_freeze if args.can_freeze is not None else True, + can_wipe=args.can_wipe if args.can_wipe is not None else True, + can_pause=args.can_pause if args.can_pause is not None else True, + can_change_owner=args.can_change_owner if args.can_change_owner is not None else True, + can_upgrade=args.can_upgrade if args.can_upgrade is not None else True, + can_add_special_roles=args.can_add_special_roles if args.can_add_special_roles is not None else True, + ) + + cli_shared.send_or_simulate(transaction, args) diff --git a/multiversx_sdk_cli/token.py b/multiversx_sdk_cli/token.py new file mode 100644 index 00000000..230f373a --- /dev/null +++ b/multiversx_sdk_cli/token.py @@ -0,0 +1,79 @@ +from typing import Optional + +from multiversx_sdk import ( + GasLimitEstimator, + TokenManagementTransactionsFactory, + Transaction, + TransactionsFactoryConfig, +) + +from multiversx_sdk_cli.base_transactions_controller import BaseTransactionsController +from multiversx_sdk_cli.guardian_relayer_data import GuardianRelayerData +from multiversx_sdk_cli.interfaces import IAccount + + +class TokenWrapper(BaseTransactionsController): + def __init__( + self, + config: TransactionsFactoryConfig, + gas_limit_estimator: Optional[GasLimitEstimator] = None, + ) -> None: + self.factory = TokenManagementTransactionsFactory(config=config, gas_limit_estimator=gas_limit_estimator) + + def create_transaction_for_issuing_fungible_token( + self, + sender: IAccount, + nonce: int, + token_name: str, + token_ticker: str, + initial_supply: int, + num_decimals: int, + gas_limit: Optional[int], + gas_price: int, + version: int, + options: int, + guardian_and_relayer_data: GuardianRelayerData, + can_freeze: bool = True, + can_wipe: bool = True, + can_pause: bool = True, + can_change_owner: bool = True, + can_upgrade: bool = True, + can_add_special_roles: bool = True, + ) -> Transaction: + tx = self.factory.create_transaction_for_issuing_fungible( + sender=sender.address, + token_name=token_name, + token_ticker=token_ticker, + initial_supply=initial_supply, + num_decimals=num_decimals, + can_freeze=can_freeze, + can_wipe=can_wipe, + can_pause=can_pause, + can_change_owner=can_change_owner, + can_upgrade=can_upgrade, + can_add_special_roles=can_add_special_roles, + ) + + self._set_transaction_fields( + transaction=tx, + nonce=nonce, + version=version, + options=options, + gas_price=gas_price, + guardian_and_relayer_data=guardian_and_relayer_data, + ) + + self.add_extra_gas_limit_if_required(tx) + if gas_limit: + tx.gas_limit = gas_limit + + self.sign_transaction( + transaction=tx, + sender=sender, + guardian=guardian_and_relayer_data.guardian, + relayer=guardian_and_relayer_data.relayer, + guardian_service_url=guardian_and_relayer_data.guardian_service_url, + guardian_2fa_code=guardian_and_relayer_data.guardian_2fa_code, + ) + + return tx From 53b9ad5a49d7bfdc341b49baf4025c636e6639ba Mon Sep 17 00:00:00 2001 From: Lara Tifui Date: Mon, 8 Sep 2025 06:47:39 +0200 Subject: [PATCH 3/5] addition of args validation --- multiversx_sdk_cli/cli_token.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/multiversx_sdk_cli/cli_token.py b/multiversx_sdk_cli/cli_token.py index 7746c9d4..4e397cb0 100644 --- a/multiversx_sdk_cli/cli_token.py +++ b/multiversx_sdk_cli/cli_token.py @@ -63,7 +63,17 @@ def setup_parser(args: list[str], subparsers: Any) -> Any: def validate_token_args(args: Any): - pass + if args.initial_supply < 0: + raise ValueError("Initial supply must be a non-negative integer") + + if not (0 <= args.num_decimals <= 18): + raise ValueError("Number of decimals must be between 0 and 18") + + if not (3 <= len(args.token_name) <= 20) or not args.token_name.isalnum(): + raise ValueError("Token name must be 3-20 alphanumerical characters") + + if not (3 <= len(args.token_ticker) <= 10) or not args.token_ticker.isalnum() or not args.token_ticker.isupper(): + raise ValueError("Token ticker must be 3-10 UPPERCASE alphanumerical characters") def _ensure_args(args: Any): From 94ca7681d8f3c629c94df6118b51c622a48cdf0a Mon Sep 17 00:00:00 2001 From: Lara Tifui Date: Mon, 8 Sep 2025 12:28:38 +0200 Subject: [PATCH 4/5] update after comments --- multiversx_sdk_cli/cli.py | 4 +- .../{cli_token.py => cli_tokens.py} | 52 +++++++++++++------ multiversx_sdk_cli/{token.py => tokens.py} | 12 ++--- 3 files changed, 43 insertions(+), 25 deletions(-) rename multiversx_sdk_cli/{cli_token.py => cli_tokens.py} (68%) rename multiversx_sdk_cli/{token.py => tokens.py} (91%) diff --git a/multiversx_sdk_cli/cli.py b/multiversx_sdk_cli/cli.py index f9eff03e..f6be73cc 100644 --- a/multiversx_sdk_cli/cli.py +++ b/multiversx_sdk_cli/cli.py @@ -23,7 +23,7 @@ import multiversx_sdk_cli.cli_ledger import multiversx_sdk_cli.cli_localnet import multiversx_sdk_cli.cli_multisig -import multiversx_sdk_cli.cli_token +import multiversx_sdk_cli.cli_tokens import multiversx_sdk_cli.cli_transactions import multiversx_sdk_cli.cli_validator_wallet import multiversx_sdk_cli.cli_validators @@ -143,7 +143,7 @@ def setup_parser(args: list[str]): commands.append(multiversx_sdk_cli.cli_governance.setup_parser(args, subparsers)) commands.append(multiversx_sdk_cli.cli_config_env.setup_parser(subparsers)) commands.append(multiversx_sdk_cli.cli_get.setup_parser(subparsers)) - commands.append(multiversx_sdk_cli.cli_token.setup_parser(args, subparsers)) + commands.append(multiversx_sdk_cli.cli_tokens.setup_parser(args, subparsers)) parser.epilog = """ ---------------------- diff --git a/multiversx_sdk_cli/cli_token.py b/multiversx_sdk_cli/cli_tokens.py similarity index 68% rename from multiversx_sdk_cli/cli_token.py rename to multiversx_sdk_cli/cli_tokens.py index 4e397cb0..c1b3ea76 100644 --- a/multiversx_sdk_cli/cli_token.py +++ b/multiversx_sdk_cli/cli_tokens.py @@ -8,12 +8,13 @@ validate_chain_id_args, ) from multiversx_sdk_cli.cli_output import CLIOutputBuilder -from multiversx_sdk_cli.cli_transactions import _add_common_arguments -from multiversx_sdk_cli.token import TokenWrapper +from multiversx_sdk_cli.tokens import TokenWrapper def setup_parser(args: list[str], subparsers: Any) -> Any: - parser = cli_shared.add_group_subparser(subparsers, "token", "Perform operations with tokens") + parser = cli_shared.add_group_subparser( + subparsers, "token", "Perform token management operations (issue tokens, create NFTs, set roles, etc.)" + ) subparsers = parser.add_subparsers() sub = cli_shared.add_command_subparser( @@ -41,14 +42,31 @@ def setup_parser(args: list[str], subparsers: Any) -> Any: type=int, help="a numerical value between 0 and 18 representing number of decimals", ) - sub.add_argument("--can-freeze", type=bool, help="whether a token can be freezed") - sub.add_argument("--can-wipe", type=bool, help="whether a token can be wiped") - sub.add_argument("--can-pause", type=bool, help="whether a token can be paused") - sub.add_argument("--can-change-owner", type=bool, help="whether a token can change owner") - sub.add_argument("--can-upgrade", type=bool, help="whether a token can be upgraded") - sub.add_argument("--can-add_special-roles", type=bool, help="whether special roles can be added for the token") - - _add_common_arguments(args, sub) + sub.add_argument( + "--can-freeze", required=True, type=lambda x: x.lower() == "true", help="whether a token can be freezed" + ) + sub.add_argument( + "--can-wipe", required=True, type=lambda x: x.lower() == "true", help="whether a token can be wiped" + ) + sub.add_argument( + "--can-pause", required=True, type=lambda x: x.lower() == "true", help="whether a token can be paused" + ) + sub.add_argument( + "--can-change-owner", required=True, type=lambda x: x.lower() == "true", help="whether a token can change owner" + ) + sub.add_argument( + "--can-upgrade", required=True, type=lambda x: x.lower() == "true", help="whether a token can be upgraded" + ) + sub.add_argument( + "--can-add_special-roles", + required=lambda x: x.lower() == "true", + type=bool, + help="whether special roles can be added for the token", + ) + + cli_shared.add_wallet_args(args, sub) + cli_shared.add_tx_args(args, sub, with_receiver=False, with_data=False) + sub.add_argument("--data-file", type=str, default=None, help="a file containing transaction data") cli_shared.add_broadcast_args(sub) cli_shared.add_proxy_arg(sub) cli_shared.add_wait_result_and_timeout_args(sub) @@ -106,12 +124,12 @@ def issue_fungible(args: Any): version=args.version, options=args.options, guardian_and_relayer_data=guardian_and_relayer_data, - can_freeze=args.can_freeze if args.can_freeze is not None else True, - can_wipe=args.can_wipe if args.can_wipe is not None else True, - can_pause=args.can_pause if args.can_pause is not None else True, - can_change_owner=args.can_change_owner if args.can_change_owner is not None else True, - can_upgrade=args.can_upgrade if args.can_upgrade is not None else True, - can_add_special_roles=args.can_add_special_roles if args.can_add_special_roles is not None else True, + can_freeze=args.can_freeze, + can_wipe=args.can_wipe, + can_pause=args.can_pause, + can_change_owner=args.can_change_owner, + can_upgrade=args.can_upgrade, + can_add_special_roles=args.can_add_special_roles, ) cli_shared.send_or_simulate(transaction, args) diff --git a/multiversx_sdk_cli/token.py b/multiversx_sdk_cli/tokens.py similarity index 91% rename from multiversx_sdk_cli/token.py rename to multiversx_sdk_cli/tokens.py index 230f373a..a17ed13f 100644 --- a/multiversx_sdk_cli/token.py +++ b/multiversx_sdk_cli/tokens.py @@ -28,17 +28,17 @@ def create_transaction_for_issuing_fungible_token( token_ticker: str, initial_supply: int, num_decimals: int, + can_freeze: bool, + can_wipe: bool, + can_pause: bool, + can_change_owner: bool, + can_upgrade: bool, + can_add_special_roles: bool, gas_limit: Optional[int], gas_price: int, version: int, options: int, guardian_and_relayer_data: GuardianRelayerData, - can_freeze: bool = True, - can_wipe: bool = True, - can_pause: bool = True, - can_change_owner: bool = True, - can_upgrade: bool = True, - can_add_special_roles: bool = True, ) -> Transaction: tx = self.factory.create_transaction_for_issuing_fungible( sender=sender.address, From 920c2a216814ec721fb558268c3ca985f325c78f Mon Sep 17 00:00:00 2001 From: Lara Tifui Date: Mon, 8 Sep 2025 16:41:17 +0200 Subject: [PATCH 5/5] Added semi- & non- fungible issuing implementation + fixes and reformating --- multiversx_sdk_cli/cli_tokens.py | 165 ++++++++++++++++++++++++------- multiversx_sdk_cli/tokens.py | 112 +++++++++++++++++++++ 2 files changed, 244 insertions(+), 33 deletions(-) diff --git a/multiversx_sdk_cli/cli_tokens.py b/multiversx_sdk_cli/cli_tokens.py index c1b3ea76..e7154201 100644 --- a/multiversx_sdk_cli/cli_tokens.py +++ b/multiversx_sdk_cli/cli_tokens.py @@ -17,12 +17,50 @@ def setup_parser(args: list[str], subparsers: Any) -> Any: ) subparsers = parser.add_subparsers() + sub = cli_shared.add_command_subparser( + subparsers, "token", "issue-fungible", f"Issue a new fungible ESDT token.{CLIOutputBuilder.describe()}" + ) + sub.add_argument("--initial-supply", required=True, type=int, help="the initial supply of the token to be issued") + add_issuing_tokens_args(args, sub, with_num_decimals=True, with_transfer_nft_create_role=False) + add_common_args(args, sub) + sub.set_defaults(func=issue_fungible) + sub = cli_shared.add_command_subparser( subparsers, "token", - "issue-fungible", - f"Issue a new fungible ESDT token.{CLIOutputBuilder.describe()}", + "issue-semi-fungible", + f"Issue a new semi-fungible ESDT token.{CLIOutputBuilder.describe()}", + ) + add_issuing_tokens_args(args, sub) + add_common_args(args, sub) + sub.set_defaults(func=issue_semi_fungible) + + sub = cli_shared.add_command_subparser( + subparsers, "token", "issue-non-fungible", f"Issue a new non-fungible ESDT token.{CLIOutputBuilder.describe()}" ) + add_issuing_tokens_args(args, sub) + add_common_args(args, sub) + sub.set_defaults(func=issue_non_fungible) + + parser.epilog = cli_shared.build_group_epilog(subparsers) + return subparsers + + +def add_common_args(args: list[str], sub: Any): + cli_shared.add_wallet_args(args, sub) + cli_shared.add_tx_args(args, sub, with_receiver=False, with_data=False) + sub.add_argument("--data-file", type=str, default=None, help="a file containing transaction data") + cli_shared.add_broadcast_args(sub) + cli_shared.add_proxy_arg(sub) + cli_shared.add_wait_result_and_timeout_args(sub) + cli_shared.add_guardian_wallet_args(args, sub) + cli_shared.add_relayed_v3_wallet_args(args, sub) + cli_shared.add_outfile_arg(sub) + + +def add_issuing_tokens_args( + args: list[str], sub: Any, with_num_decimals: bool = False, with_transfer_nft_create_role: bool = True +): sub.add_argument( "--token-name", required=True, @@ -35,13 +73,6 @@ def setup_parser(args: list[str], subparsers: Any) -> Any: type=str, help="the ticker of the token to be issued: 3-10 UPPERCASE alphanumerical characters", ) - sub.add_argument("--initial-supply", required=True, type=int, help="the initial supply of the token to be issued") - sub.add_argument( - "--num-decimals", - required=True, - type=int, - help="a numerical value between 0 and 18 representing number of decimals", - ) sub.add_argument( "--can-freeze", required=True, type=lambda x: x.lower() == "true", help="whether a token can be freezed" ) @@ -59,32 +90,32 @@ def setup_parser(args: list[str], subparsers: Any) -> Any: ) sub.add_argument( "--can-add_special-roles", - required=lambda x: x.lower() == "true", - type=bool, + required=True, + type=lambda x: x.lower() == "true", help="whether special roles can be added for the token", ) - cli_shared.add_wallet_args(args, sub) - cli_shared.add_tx_args(args, sub, with_receiver=False, with_data=False) - sub.add_argument("--data-file", type=str, default=None, help="a file containing transaction data") - cli_shared.add_broadcast_args(sub) - cli_shared.add_proxy_arg(sub) - cli_shared.add_wait_result_and_timeout_args(sub) - cli_shared.add_guardian_wallet_args(args, sub) - cli_shared.add_relayed_v3_wallet_args(args, sub) - cli_shared.add_outfile_arg(sub) - - sub.set_defaults(func=issue_fungible) - - parser.epilog = cli_shared.build_group_epilog(subparsers) - return subparsers - - -def validate_token_args(args: Any): - if args.initial_supply < 0: + if with_num_decimals: + sub.add_argument( + "--num-decimals", + required=True, + type=int, + help="a numerical value between 0 and 18 representing number of decimals", + ) + if with_transfer_nft_create_role: + sub.add_argument( + "--can-transfer-nft-create-role", + required=True, + type=lambda x: x.lower() == "true", + help="whether nft create roles can be transfered for the token", + ) + + +def validate_token_args(args: Any, with_initial_supply: bool = False, with_num_decimals: bool = False): + if with_initial_supply and args.initial_supply < 0: raise ValueError("Initial supply must be a non-negative integer") - if not (0 <= args.num_decimals <= 18): + if with_num_decimals and not (0 <= args.num_decimals <= 18): raise ValueError("Number of decimals must be between 0 and 18") if not (3 <= len(args.token_name) <= 20) or not args.token_name.isalnum(): @@ -94,14 +125,14 @@ def validate_token_args(args: Any): raise ValueError("Token ticker must be 3-10 UPPERCASE alphanumerical characters") -def _ensure_args(args: Any): +def _ensure_args(args: Any, with_initial_supply: bool = False, with_num_decimals: bool = False): validate_broadcast_args(args) validate_chain_id_args(args) - validate_token_args(args) + validate_token_args(args, with_initial_supply, with_num_decimals) def issue_fungible(args: Any): - _ensure_args(args) + _ensure_args(args, with_initial_supply=True, with_num_decimals=True) sender = cli_shared.prepare_sender(args) guardian_and_relayer_data = cli_shared.get_guardian_and_relayer_data( @@ -133,3 +164,71 @@ def issue_fungible(args: Any): ) cli_shared.send_or_simulate(transaction, args) + + +def issue_semi_fungible(args: Any): + _ensure_args(args) + + sender = cli_shared.prepare_sender(args) + guardian_and_relayer_data = cli_shared.get_guardian_and_relayer_data( + sender=sender.address.to_bech32(), + args=args, + ) + chain_id = cli_shared.get_chain_id(args.proxy, args.chain) + gas_estimator = cli_shared.initialize_gas_limit_estimator(args) + controller = TokenWrapper(config=TransactionsFactoryConfig(chain_id), gas_limit_estimator=gas_estimator) + + transaction = controller.create_transaction_for_issuing_semi_fungible_token( + sender=sender, + nonce=sender.nonce, + token_name=args.token_name, + token_ticker=args.token_ticker, + gas_limit=args.gas_limit, + gas_price=args.gas_price, + version=args.version, + options=args.options, + guardian_and_relayer_data=guardian_and_relayer_data, + can_freeze=args.can_freeze, + can_wipe=args.can_wipe, + can_pause=args.can_pause, + can_transfer_nft_create_role=args.can_transfer_nft_create_role, + can_change_owner=args.can_change_owner, + can_upgrade=args.can_upgrade, + can_add_special_roles=args.can_add_special_roles, + ) + + cli_shared.send_or_simulate(transaction, args) + + +def issue_non_fungible(args: Any): + _ensure_args(args) + + sender = cli_shared.prepare_sender(args) + guardian_and_relayer_data = cli_shared.get_guardian_and_relayer_data( + sender=sender.address.to_bech32(), + args=args, + ) + chain_id = cli_shared.get_chain_id(args.proxy, args.chain) + gas_estimator = cli_shared.initialize_gas_limit_estimator(args) + controller = TokenWrapper(config=TransactionsFactoryConfig(chain_id), gas_limit_estimator=gas_estimator) + + transaction = controller.create_transaction_for_issuing_non_fungible_token( + sender=sender, + nonce=sender.nonce, + token_name=args.token_name, + token_ticker=args.token_ticker, + gas_limit=args.gas_limit, + gas_price=args.gas_price, + version=args.version, + options=args.options, + guardian_and_relayer_data=guardian_and_relayer_data, + can_freeze=args.can_freeze, + can_wipe=args.can_wipe, + can_pause=args.can_pause, + can_transfer_nft_create_role=args.can_transfer_nft_create_role, + can_change_owner=args.can_change_owner, + can_upgrade=args.can_upgrade, + can_add_special_roles=args.can_add_special_roles, + ) + + cli_shared.send_or_simulate(transaction, args) diff --git a/multiversx_sdk_cli/tokens.py b/multiversx_sdk_cli/tokens.py index a17ed13f..2adf7e12 100644 --- a/multiversx_sdk_cli/tokens.py +++ b/multiversx_sdk_cli/tokens.py @@ -77,3 +77,115 @@ def create_transaction_for_issuing_fungible_token( ) return tx + + def create_transaction_for_issuing_semi_fungible_token( + self, + sender: IAccount, + nonce: int, + token_name: str, + token_ticker: str, + can_freeze: bool, + can_wipe: bool, + can_pause: bool, + can_transfer_nft_create_role: bool, + can_change_owner: bool, + can_upgrade: bool, + can_add_special_roles: bool, + gas_limit: Optional[int], + gas_price: int, + version: int, + options: int, + guardian_and_relayer_data: GuardianRelayerData, + ) -> Transaction: + tx = self.factory.create_transaction_for_issuing_semi_fungible( + sender=sender.address, + token_name=token_name, + token_ticker=token_ticker, + can_freeze=can_freeze, + can_wipe=can_wipe, + can_pause=can_pause, + can_transfer_nft_create_role=can_transfer_nft_create_role, + can_change_owner=can_change_owner, + can_upgrade=can_upgrade, + can_add_special_roles=can_add_special_roles, + ) + + self._set_transaction_fields( + transaction=tx, + nonce=nonce, + version=version, + options=options, + gas_price=gas_price, + guardian_and_relayer_data=guardian_and_relayer_data, + ) + + self.add_extra_gas_limit_if_required(tx) + if gas_limit: + tx.gas_limit = gas_limit + + self.sign_transaction( + transaction=tx, + sender=sender, + guardian=guardian_and_relayer_data.guardian, + relayer=guardian_and_relayer_data.relayer, + guardian_service_url=guardian_and_relayer_data.guardian_service_url, + guardian_2fa_code=guardian_and_relayer_data.guardian_2fa_code, + ) + + return tx + + def create_transaction_for_issuing_non_fungible_token( + self, + sender: IAccount, + nonce: int, + token_name: str, + token_ticker: str, + can_freeze: bool, + can_wipe: bool, + can_pause: bool, + can_transfer_nft_create_role: bool, + can_change_owner: bool, + can_upgrade: bool, + can_add_special_roles: bool, + gas_limit: Optional[int], + gas_price: int, + version: int, + options: int, + guardian_and_relayer_data: GuardianRelayerData, + ) -> Transaction: + tx = self.factory.create_transaction_for_issuing_non_fungible( + sender=sender.address, + token_name=token_name, + token_ticker=token_ticker, + can_freeze=can_freeze, + can_wipe=can_wipe, + can_pause=can_pause, + can_transfer_nft_create_role=can_transfer_nft_create_role, + can_change_owner=can_change_owner, + can_upgrade=can_upgrade, + can_add_special_roles=can_add_special_roles, + ) + + self._set_transaction_fields( + transaction=tx, + nonce=nonce, + version=version, + options=options, + gas_price=gas_price, + guardian_and_relayer_data=guardian_and_relayer_data, + ) + + self.add_extra_gas_limit_if_required(tx) + if gas_limit: + tx.gas_limit = gas_limit + + self.sign_transaction( + transaction=tx, + sender=sender, + guardian=guardian_and_relayer_data.guardian, + relayer=guardian_and_relayer_data.relayer, + guardian_service_url=guardian_and_relayer_data.guardian_service_url, + guardian_2fa_code=guardian_and_relayer_data.guardian_2fa_code, + ) + + return tx