mxpy 10.2.0__tar.gz → 11.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. {mxpy-10.2.0 → mxpy-11.0.0}/.gitignore +2 -0
  2. {mxpy-10.2.0 → mxpy-11.0.0}/PKG-INFO +3 -3
  3. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/args_validation.py +0 -10
  4. mxpy-11.0.0/multiversx_sdk_cli/base_transactions_controller.py +172 -0
  5. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli.py +49 -9
  6. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_config.py +15 -7
  7. mxpy-11.0.0/multiversx_sdk_cli/cli_config_env.py +160 -0
  8. mxpy-11.0.0/multiversx_sdk_cli/cli_config_wallet.py +155 -0
  9. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_contracts.py +21 -73
  10. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_delegation.py +1 -3
  11. mxpy-11.0.0/multiversx_sdk_cli/cli_get.py +232 -0
  12. mxpy-11.0.0/multiversx_sdk_cli/cli_governance.py +449 -0
  13. mxpy-11.0.0/multiversx_sdk_cli/cli_multisig.py +1866 -0
  14. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_password.py +12 -0
  15. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_shared.py +220 -47
  16. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_transactions.py +8 -40
  17. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_validators.py +12 -3
  18. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_wallet.py +14 -3
  19. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/config.py +16 -78
  20. mxpy-11.0.0/multiversx_sdk_cli/config_env.py +224 -0
  21. mxpy-11.0.0/multiversx_sdk_cli/config_wallet.py +177 -0
  22. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/constants.py +13 -0
  23. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/contracts.py +13 -83
  24. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/delegation.py +1 -1
  25. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/dns.py +2 -4
  26. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/errors.py +72 -0
  27. mxpy-11.0.0/multiversx_sdk_cli/governance.py +262 -0
  28. mxpy-11.0.0/multiversx_sdk_cli/multisig.py +916 -0
  29. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/utils.py +29 -15
  30. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/workstation.py +3 -2
  31. {mxpy-10.2.0 → mxpy-11.0.0}/pyproject.toml +3 -3
  32. mxpy-10.2.0/multiversx_sdk_cli/base_transactions_controller.py +0 -86
  33. {mxpy-10.2.0 → mxpy-11.0.0}/LICENSE +0 -0
  34. {mxpy-10.2.0 → mxpy-11.0.0}/README.md +0 -0
  35. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/__init__.py +0 -0
  36. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_data.py +0 -0
  37. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_deps.py +0 -0
  38. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_dns.py +0 -0
  39. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_faucet.py +0 -0
  40. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_ledger.py +0 -0
  41. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_localnet.py +0 -0
  42. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_output.py +0 -0
  43. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cli_validator_wallet.py +0 -0
  44. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/contract_verification.py +0 -0
  45. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/cosign_transaction.py +0 -0
  46. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/dependencies/__init__.py +0 -0
  47. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/dependencies/install.py +0 -0
  48. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/dependencies/modules.py +0 -0
  49. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/dependencies/resolution.py +0 -0
  50. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/docker.py +0 -0
  51. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/downloader.py +0 -0
  52. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/guardian_relayer_data.py +0 -0
  53. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/guards.py +0 -0
  54. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/interfaces.py +0 -0
  55. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/__init__.py +0 -0
  56. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/config_default.py +0 -0
  57. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/config_general.py +0 -0
  58. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/config_networking.py +0 -0
  59. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/config_part.py +0 -0
  60. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/config_root.py +0 -0
  61. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/config_sharding.py +0 -0
  62. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/config_software.py +0 -0
  63. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/constants.py +0 -0
  64. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/genesis.py +0 -0
  65. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/genesis_json.py +0 -0
  66. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/genesis_smart_contracts_json.py +0 -0
  67. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/libraries.py +0 -0
  68. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/node.py +0 -0
  69. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/node_config_toml.py +0 -0
  70. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/nodes_setup_json.py +0 -0
  71. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/p2p_toml.py +0 -0
  72. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/seednode_p2pKey.pem +0 -0
  73. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/step_build_software.py +0 -0
  74. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/step_clean.py +0 -0
  75. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/step_config.py +0 -0
  76. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/step_new.py +0 -0
  77. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/step_prerequisites.py +0 -0
  78. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/step_start.py +0 -0
  79. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/localnet/wallets.py +0 -0
  80. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/myprocess.py +0 -0
  81. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/sign_verify.py +0 -0
  82. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/simulation.py +0 -0
  83. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/transactions.py +0 -0
  84. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/ux.py +0 -0
  85. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/validators.py +0 -0
  86. {mxpy-10.2.0 → mxpy-11.0.0}/multiversx_sdk_cli/version.py +0 -0
@@ -30,3 +30,5 @@ venv.bak/
30
30
  typings
31
31
 
32
32
  multiversx_sdk_cli/tests/testdata-out
33
+
34
+ .DS_store
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mxpy
3
- Version: 10.2.0
3
+ Version: 11.0.0
4
4
  Summary: MultiversX Smart Contracts Tools
5
5
  Project-URL: Homepage, https://github.com/multiversx/mx-sdk-py-cli
6
6
  Author: MultiversX
@@ -10,10 +10,10 @@ Classifier: Intended Audience :: Developers
10
10
  Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Operating System :: OS Independent
12
12
  Classifier: Programming Language :: Python :: 3
13
- Requires-Python: >=3.8
13
+ Requires-Python: >=3.10
14
14
  Requires-Dist: argcomplete==3.2.2
15
15
  Requires-Dist: ledgercomm[hid]
16
- Requires-Dist: multiversx-sdk[ledger]==1.2.0
16
+ Requires-Dist: multiversx-sdk[ledger]==1.6.2
17
17
  Requires-Dist: requests<3.0.0,>=2.32.0
18
18
  Requires-Dist: rich==13.3.4
19
19
  Requires-Dist: toml>=0.10.2
@@ -29,16 +29,6 @@ def validate_gas_limit_args(args: Any):
29
29
  raise InvalidArgumentsError("--gas-limit must be provided")
30
30
 
31
31
 
32
- def ensure_wallet_args_are_provided(args: Any):
33
- signing_methods = [args.pem, args.keyfile, args.ledger]
34
-
35
- if all(signing_methods):
36
- raise InvalidArgumentsError("Only one of --pem, --keyfile, or --ledger must be provided")
37
-
38
- if not any(signing_methods):
39
- raise InvalidArgumentsError("One of --pem, --keyfile, or --ledger must be provided")
40
-
41
-
42
32
  def ensure_relayer_wallet_args_are_provided(args: Any):
43
33
  signing_methods = [args.relayer_pem, args.relayer_keyfile, args.relayer_ledger]
44
34
 
@@ -0,0 +1,172 @@
1
+ import logging
2
+ from typing import Any, Optional, Union
3
+
4
+ from multiversx_sdk import Address, LedgerAccount, Transaction, TransactionComputer
5
+ from multiversx_sdk.abi import (
6
+ AddressValue,
7
+ BigUIntValue,
8
+ BoolValue,
9
+ BytesValue,
10
+ StringValue,
11
+ )
12
+
13
+ from multiversx_sdk_cli.config_env import get_address_hrp
14
+ from multiversx_sdk_cli.constants import (
15
+ ADDRESS_PREFIX,
16
+ EXTRA_GAS_LIMIT_FOR_GUARDED_TRANSACTIONS,
17
+ EXTRA_GAS_LIMIT_FOR_RELAYED_TRANSACTIONS,
18
+ FALSE_STR_LOWER,
19
+ HEX_PREFIX,
20
+ MAINCHAIN_ADDRESS_HRP,
21
+ STR_PREFIX,
22
+ TRUE_STR_LOWER,
23
+ )
24
+ from multiversx_sdk_cli.cosign_transaction import cosign_transaction
25
+ from multiversx_sdk_cli.errors import BadUserInput, TransactionSigningError
26
+ from multiversx_sdk_cli.guardian_relayer_data import GuardianRelayerData
27
+ from multiversx_sdk_cli.interfaces import IAccount
28
+
29
+ logger = logging.getLogger("base_controller")
30
+
31
+
32
+ class BaseTransactionsController:
33
+ def __init__(self) -> None:
34
+ pass
35
+
36
+ def sign_transaction(
37
+ self,
38
+ transaction: Transaction,
39
+ sender: Optional[IAccount] = None,
40
+ guardian: Optional[IAccount] = None,
41
+ relayer: Optional[IAccount] = None,
42
+ guardian_service_url: Optional[str] = None,
43
+ guardian_2fa_code: Optional[str] = None,
44
+ ):
45
+ """Signs the transaction using the sender's account and, if required, additionally signs with the guardian's and relayer's accounts. Ensures the appropriate transaction options are set as needed."""
46
+ self._set_options_for_guarded_transaction_if_needed(transaction)
47
+ self._set_options_for_hash_signing_if_needed(transaction, sender, guardian, relayer)
48
+
49
+ if sender:
50
+ try:
51
+ transaction.signature = sender.sign_transaction(transaction)
52
+ except Exception as e:
53
+ raise TransactionSigningError(f"Could not sign transaction: {str(e)}")
54
+
55
+ self._sign_guarded_transaction_if_guardian(
56
+ transaction,
57
+ guardian,
58
+ guardian_service_url,
59
+ guardian_2fa_code,
60
+ )
61
+ self._sign_relayed_transaction_if_relayer(transaction, relayer)
62
+
63
+ def add_extra_gas_limit_if_required(self, transaction: Transaction):
64
+ """In case of guarded or relayed transactions, extra gas limit is added."""
65
+ if transaction.guardian:
66
+ transaction.gas_limit += EXTRA_GAS_LIMIT_FOR_GUARDED_TRANSACTIONS
67
+
68
+ if transaction.relayer:
69
+ transaction.gas_limit += EXTRA_GAS_LIMIT_FOR_RELAYED_TRANSACTIONS
70
+
71
+ def _set_options_for_guarded_transaction_if_needed(self, transaction: Transaction):
72
+ if transaction.guardian:
73
+ transaction_computer = TransactionComputer()
74
+ transaction_computer.apply_guardian(transaction, transaction.guardian)
75
+
76
+ def _set_options_for_hash_signing_if_needed(
77
+ self,
78
+ transaction: Transaction,
79
+ sender: Union[IAccount, None],
80
+ guardian: Union[IAccount, None],
81
+ relayer: Union[IAccount, None],
82
+ ):
83
+ if (
84
+ isinstance(sender, LedgerAccount)
85
+ or isinstance(guardian, LedgerAccount)
86
+ or isinstance(relayer, LedgerAccount)
87
+ ):
88
+ transaction_computer = TransactionComputer()
89
+ transaction_computer.apply_options_for_hash_signing(transaction)
90
+
91
+ def _sign_guarded_transaction_if_guardian(
92
+ self,
93
+ transaction: Transaction,
94
+ guardian: Union[IAccount, None],
95
+ guardian_service_url: Union[str, None],
96
+ guardian_2fa_code: Union[str, None],
97
+ ) -> Transaction:
98
+ # If the guardian account is provided, we sign locally. Otherwise, we reach for the trusted cosign service.
99
+ if guardian:
100
+ try:
101
+ transaction.guardian_signature = guardian.sign_transaction(transaction)
102
+ except Exception as e:
103
+ raise TransactionSigningError(f"Could not sign transaction: {str(e)}")
104
+ elif transaction.guardian and guardian_service_url and guardian_2fa_code:
105
+ cosign_transaction(transaction, guardian_service_url, guardian_2fa_code)
106
+
107
+ return transaction
108
+
109
+ def _sign_relayed_transaction_if_relayer(self, transaction: Transaction, relayer: Union[IAccount, None]):
110
+ if relayer and transaction.relayer:
111
+ try:
112
+ transaction.relayer_signature = relayer.sign_transaction(transaction)
113
+ except Exception as e:
114
+ raise TransactionSigningError(f"Could not sign transaction: {str(e)}")
115
+
116
+ def _convert_args_to_typed_values(self, arguments: list[str]) -> list[Any]:
117
+ args: list[Any] = []
118
+
119
+ for arg in arguments:
120
+ if arg.startswith(HEX_PREFIX):
121
+ args.append(BytesValue(self._hex_to_bytes(arg)))
122
+ elif arg.isnumeric():
123
+ args.append(BigUIntValue(int(arg)))
124
+ elif arg.startswith(ADDRESS_PREFIX):
125
+ args.append(AddressValue.new_from_address(Address.new_from_bech32(arg[len(ADDRESS_PREFIX) :])))
126
+ elif arg.startswith(MAINCHAIN_ADDRESS_HRP):
127
+ # this flow will be removed in the future
128
+ logger.warning(
129
+ "Address argument has no prefix. This flow will be removed in the future. Please provide each address using the `addr:` prefix. (e.g. --arguments addr:erd1...)"
130
+ )
131
+ args.append(AddressValue.new_from_address(Address.new_from_bech32(arg)))
132
+ elif arg.startswith(get_address_hrp()):
133
+ args.append(AddressValue.new_from_address(Address.new_from_bech32(arg)))
134
+ elif arg.lower() == FALSE_STR_LOWER:
135
+ args.append(BoolValue(False))
136
+ elif arg.lower() == TRUE_STR_LOWER:
137
+ args.append(BoolValue(True))
138
+ elif arg.startswith(STR_PREFIX):
139
+ args.append(StringValue(arg[len(STR_PREFIX) :]))
140
+ else:
141
+ raise BadUserInput(
142
+ f"Unknown argument type for argument: `{arg}`. Use `mxpy contract <sub-command> --help` to check all supported arguments"
143
+ )
144
+
145
+ return args
146
+
147
+ def _hex_to_bytes(self, arg: str):
148
+ argument = arg[len(HEX_PREFIX) :]
149
+ argument = argument.upper()
150
+ argument = self.ensure_even_length(argument)
151
+ return bytes.fromhex(argument)
152
+
153
+ def ensure_even_length(self, string: str) -> str:
154
+ if len(string) % 2 == 1:
155
+ return "0" + string
156
+ return string
157
+
158
+ def _set_transaction_fields(
159
+ self,
160
+ transaction: Transaction,
161
+ nonce: int,
162
+ version: int,
163
+ options: int,
164
+ gas_price: int,
165
+ guardian_and_relayer_data: GuardianRelayerData,
166
+ ):
167
+ transaction.nonce = nonce
168
+ transaction.version = version
169
+ transaction.options = options
170
+ transaction.gas_price = gas_price
171
+ transaction.guardian = guardian_and_relayer_data.guardian_address
172
+ transaction.relayer = guardian_and_relayer_data.relayer_address
@@ -10,20 +10,28 @@ from multiversx_sdk import LibraryConfig
10
10
  from rich.logging import RichHandler
11
11
 
12
12
  import multiversx_sdk_cli.cli_config
13
+ import multiversx_sdk_cli.cli_config_env
14
+ import multiversx_sdk_cli.cli_config_wallet
13
15
  import multiversx_sdk_cli.cli_contracts
14
16
  import multiversx_sdk_cli.cli_data
15
17
  import multiversx_sdk_cli.cli_delegation
16
18
  import multiversx_sdk_cli.cli_deps
17
19
  import multiversx_sdk_cli.cli_dns
18
20
  import multiversx_sdk_cli.cli_faucet
21
+ import multiversx_sdk_cli.cli_get
22
+ import multiversx_sdk_cli.cli_governance
19
23
  import multiversx_sdk_cli.cli_ledger
20
24
  import multiversx_sdk_cli.cli_localnet
25
+ import multiversx_sdk_cli.cli_multisig
21
26
  import multiversx_sdk_cli.cli_transactions
22
27
  import multiversx_sdk_cli.cli_validator_wallet
23
28
  import multiversx_sdk_cli.cli_validators
24
29
  import multiversx_sdk_cli.cli_wallet
25
30
  import multiversx_sdk_cli.version
26
31
  from multiversx_sdk_cli import config, errors, utils, ux
32
+ from multiversx_sdk_cli.cli_shared import set_proxy_from_config_if_not_provided
33
+ from multiversx_sdk_cli.config_env import get_address_hrp
34
+ from multiversx_sdk_cli.constants import LOG_LEVELS, SDK_PATH
27
35
 
28
36
  logger = logging.getLogger("cli")
29
37
 
@@ -42,11 +50,12 @@ def main(cli_args: list[str] = sys.argv[1:]):
42
50
 
43
51
 
44
52
  def _do_main(cli_args: list[str]):
45
- utils.ensure_folder(config.SDK_PATH)
46
- argv_with_config_args = config.add_config_args(cli_args)
47
- parser = setup_parser(argv_with_config_args)
53
+ utils.ensure_folder(SDK_PATH)
54
+ parser = setup_parser(cli_args)
48
55
  argcomplete.autocomplete(parser)
49
- args = parser.parse_args(argv_with_config_args)
56
+
57
+ _handle_global_arguments(cli_args)
58
+ args = parser.parse_args(cli_args)
50
59
 
51
60
  if args.verbose:
52
61
  logging.basicConfig(
@@ -56,22 +65,21 @@ def _do_main(cli_args: list[str]):
56
65
  handlers=[RichHandler(show_time=False, rich_tracebacks=True)],
57
66
  )
58
67
  else:
68
+ level: str = args.log_level
59
69
  logging.basicConfig(
60
- level="INFO",
70
+ level=level.upper(),
61
71
  format="%(name)s: %(message)s",
62
72
  handlers=[RichHandler(show_time=False, rich_tracebacks=True)],
63
73
  )
64
74
 
65
75
  verify_deprecated_entries_in_config_file()
66
- default_hrp = config.get_address_hrp()
76
+ default_hrp = get_address_hrp()
67
77
  LibraryConfig.default_address_hrp = default_hrp
68
78
 
69
- if hasattr(args, "recall_nonce") and args.recall_nonce:
70
- logger.warning("The --recall-nonce flag is DEPRECATED. The nonce is fetched from the network by default.")
71
-
72
79
  if not hasattr(args, "func"):
73
80
  parser.print_help()
74
81
  else:
82
+ set_proxy_from_config_if_not_provided(args)
75
83
  args.func(args)
76
84
 
77
85
 
@@ -105,10 +113,18 @@ See:
105
113
  version=f"MultiversX Python CLI (mxpy) {version}",
106
114
  )
107
115
  parser.add_argument("--verbose", action="store_true", default=False)
116
+ parser.add_argument(
117
+ "--log-level",
118
+ type=str,
119
+ default=config.get_log_level_from_config(),
120
+ choices=LOG_LEVELS,
121
+ help="default: %(default)s",
122
+ )
108
123
 
109
124
  subparsers = parser.add_subparsers()
110
125
  commands: list[Any] = []
111
126
 
127
+ commands.append(multiversx_sdk_cli.cli_config_wallet.setup_parser(subparsers))
112
128
  commands.append(multiversx_sdk_cli.cli_contracts.setup_parser(args, subparsers))
113
129
  commands.append(multiversx_sdk_cli.cli_transactions.setup_parser(args, subparsers))
114
130
  commands.append(multiversx_sdk_cli.cli_validators.setup_parser(args, subparsers))
@@ -122,6 +138,10 @@ See:
122
138
  commands.append(multiversx_sdk_cli.cli_delegation.setup_parser(args, subparsers))
123
139
  commands.append(multiversx_sdk_cli.cli_dns.setup_parser(args, subparsers))
124
140
  commands.append(multiversx_sdk_cli.cli_faucet.setup_parser(args, subparsers))
141
+ commands.append(multiversx_sdk_cli.cli_multisig.setup_parser(args, subparsers))
142
+ commands.append(multiversx_sdk_cli.cli_governance.setup_parser(args, subparsers))
143
+ commands.append(multiversx_sdk_cli.cli_config_env.setup_parser(subparsers))
144
+ commands.append(multiversx_sdk_cli.cli_get.setup_parser(subparsers))
125
145
 
126
146
  parser.epilog = """
127
147
  ----------------------
@@ -147,6 +167,26 @@ def verify_deprecated_entries_in_config_file():
147
167
  ux.show_warning(message.rstrip("\n"))
148
168
 
149
169
 
170
+ def _handle_global_arguments(args: list[str]):
171
+ """
172
+ Handle global arguments like --verbose and --log-level.
173
+ """
174
+ log_level_arg = "--log-level"
175
+ if log_level_arg in args:
176
+ index = args.index(log_level_arg)
177
+ if index + 1 >= len(args):
178
+ raise ValueError(f"Argument {log_level_arg} must be followed by a log level value.")
179
+
180
+ log_arg = args.pop(index)
181
+ log_value = args.pop(index)
182
+ args.insert(0, log_value)
183
+ args.insert(0, log_arg)
184
+
185
+ if "--verbose" in args:
186
+ args.remove("--verbose")
187
+ args.insert(0, "--verbose")
188
+
189
+
150
190
  if __name__ == "__main__":
151
191
  ret = main(sys.argv[1:])
152
192
  sys.exit(ret)
@@ -10,10 +10,10 @@ logger = logging.getLogger("cli.config")
10
10
 
11
11
 
12
12
  def setup_parser(subparsers: Any) -> Any:
13
- parser = cli_shared.add_group_subparser(subparsers, "config", "Configure multiversx-sdk (default values etc.)")
13
+ parser = cli_shared.add_group_subparser(subparsers, "config", "Configure MultiversX CLI (default values etc.)")
14
14
  subparsers = parser.add_subparsers()
15
15
 
16
- sub = cli_shared.add_command_subparser(subparsers, "config", "dump", "Dumps configuration.")
16
+ sub = cli_shared.add_command_subparser(subparsers, "config", "dump", "Dumps the active configuration.")
17
17
  sub.add_argument(
18
18
  "--defaults",
19
19
  required=False,
@@ -22,20 +22,28 @@ def setup_parser(subparsers: Any) -> Any:
22
22
  )
23
23
  sub.set_defaults(func=dump)
24
24
 
25
- sub = cli_shared.add_command_subparser(subparsers, "config", "get", "Gets a configuration value.")
25
+ sub = cli_shared.add_command_subparser(
26
+ subparsers, "config", "get", "Gets a configuration value from the active configuration."
27
+ )
26
28
  _add_name_arg(sub)
27
29
  sub.set_defaults(func=get_value)
28
30
 
29
- sub = cli_shared.add_command_subparser(subparsers, "config", "set", "Sets a configuration value.")
31
+ sub = cli_shared.add_command_subparser(
32
+ subparsers, "config", "set", "Sets a configuration value for the active configuration."
33
+ )
30
34
  _add_name_arg(sub)
31
35
  sub.add_argument("value", help="the new value")
32
36
  sub.set_defaults(func=set_value)
33
37
 
34
- sub = cli_shared.add_command_subparser(subparsers, "config", "delete", "Deletes a configuration value.")
38
+ sub = cli_shared.add_command_subparser(
39
+ subparsers, "config", "delete", "Deletes a configuration value from the active configuration."
40
+ )
35
41
  _add_name_arg(sub)
36
42
  sub.set_defaults(func=delete_value)
37
43
 
38
- sub = cli_shared.add_command_subparser(subparsers, "config", "new", "Creates a new configuration.")
44
+ sub = cli_shared.add_command_subparser(
45
+ subparsers, "config", "new", "Creates a new configuration and sets it as the active configuration."
46
+ )
39
47
  _add_name_arg(sub)
40
48
  sub.add_argument(
41
49
  "--template",
@@ -44,7 +52,7 @@ def setup_parser(subparsers: Any) -> Any:
44
52
  )
45
53
  sub.set_defaults(func=new_config)
46
54
 
47
- sub = cli_shared.add_command_subparser(subparsers, "config", "switch", "Switch to a different config")
55
+ sub = cli_shared.add_command_subparser(subparsers, "config", "switch", "Switch to a different config.")
48
56
  _add_name_arg(sub)
49
57
  sub.set_defaults(func=switch_config)
50
58
 
@@ -0,0 +1,160 @@
1
+ import logging
2
+ import os
3
+ from typing import Any
4
+
5
+ from multiversx_sdk_cli import cli_shared
6
+ from multiversx_sdk_cli.config_env import (
7
+ create_new_env,
8
+ delete_env,
9
+ delete_value,
10
+ get_active_env,
11
+ get_defaults,
12
+ get_value,
13
+ read_env_file,
14
+ resolve_env_path,
15
+ set_active,
16
+ set_value,
17
+ )
18
+ from multiversx_sdk_cli.utils import dump_out_json
19
+ from multiversx_sdk_cli.ux import confirm_continuation
20
+
21
+ logger = logging.getLogger("cli.config_env")
22
+
23
+
24
+ def setup_parser(subparsers: Any) -> Any:
25
+ parser = cli_shared.add_group_subparser(
26
+ subparsers, "config-env", "Configure MultiversX CLI to use specific environment values."
27
+ )
28
+ subparsers = parser.add_subparsers()
29
+
30
+ sub = cli_shared.add_command_subparser(
31
+ subparsers, "config-env", "new", "Creates a new environment and sets it as the active environment."
32
+ )
33
+ sub.add_argument("name", type=str, help="the name of the new environment")
34
+ sub.add_argument(
35
+ "--template",
36
+ required=False,
37
+ help="an environment from which to create the new environment",
38
+ )
39
+ sub.set_defaults(func=new_env)
40
+
41
+ sub = cli_shared.add_command_subparser(
42
+ subparsers, "config-env", "get", "Gets an env value from the specified environment."
43
+ )
44
+ _add_name_arg(sub)
45
+ _add_env_arg(sub)
46
+ sub.set_defaults(func=get_env_value)
47
+
48
+ sub = cli_shared.add_command_subparser(
49
+ subparsers, "config-env", "set", "Sets an env value for the specified environment."
50
+ )
51
+ _add_name_arg(sub)
52
+ sub.add_argument("value", type=str, help="the new value")
53
+ _add_env_arg(sub)
54
+ sub.set_defaults(func=set_env_value)
55
+
56
+ sub = cli_shared.add_command_subparser(subparsers, "config-env", "dump", "Dumps the active environment.")
57
+ sub.add_argument(
58
+ "--default",
59
+ required=False,
60
+ help="dumps the default environment instead of the active one.",
61
+ action="store_true",
62
+ )
63
+ sub.set_defaults(func=dump)
64
+
65
+ sub = cli_shared.add_command_subparser(
66
+ subparsers, "config-env", "delete", "Deletes an env value from the specified environment."
67
+ )
68
+ _add_name_arg(sub)
69
+ _add_env_arg(sub)
70
+ sub.set_defaults(func=delete_env_value)
71
+
72
+ sub = cli_shared.add_command_subparser(subparsers, "config-env", "switch", "Switch to a different environment.")
73
+ _add_env_arg(sub)
74
+ sub.set_defaults(func=switch_env)
75
+
76
+ sub = cli_shared.add_command_subparser(subparsers, "config-env", "list", "List available environments")
77
+ sub.set_defaults(func=list_envs)
78
+
79
+ sub = cli_shared.add_command_subparser(
80
+ subparsers,
81
+ "config-env",
82
+ "remove",
83
+ "Deletes an environment from the env file. Use `mxpy config-env switch` to switch to another env.",
84
+ )
85
+ _add_env_arg(sub)
86
+ sub.set_defaults(func=remove_env_entry)
87
+
88
+ sub = cli_shared.add_command_subparser(
89
+ subparsers,
90
+ "config-env",
91
+ "reset",
92
+ "Deletes the environment file. Default env will be used.",
93
+ )
94
+ sub.set_defaults(func=delete_env_file)
95
+
96
+ parser.epilog = cli_shared.build_group_epilog(subparsers)
97
+ return subparsers
98
+
99
+
100
+ def _add_name_arg(sub: Any):
101
+ sub.add_argument("name", type=str, help="the name of the configuration entry")
102
+
103
+
104
+ def _add_env_arg(sub: Any):
105
+ sub.add_argument("--env", required=True, type=str, help="the name of the environment to operate on")
106
+
107
+
108
+ def dump(args: Any):
109
+ if args.default:
110
+ dump_out_json(get_defaults())
111
+ else:
112
+ dump_out_json(get_active_env())
113
+
114
+
115
+ def get_env_value(args: Any):
116
+ value = get_value(args.name, args.env)
117
+ print(value)
118
+
119
+
120
+ def set_env_value(args: Any):
121
+ set_value(args.name, args.value, args.env)
122
+
123
+
124
+ def delete_env_value(args: Any):
125
+ delete_value(args.name, args.env)
126
+
127
+
128
+ def new_env(args: Any):
129
+ create_new_env(name=args.name, template=args.template)
130
+ dump_out_json(get_active_env())
131
+
132
+
133
+ def switch_env(args: Any):
134
+ set_active(args.env)
135
+ dump_out_json(get_active_env())
136
+
137
+
138
+ def list_envs(args: Any):
139
+ data = read_env_file()
140
+ dump_out_json(data)
141
+
142
+
143
+ def remove_env_entry(args: Any):
144
+ envs_file = resolve_env_path()
145
+ if not envs_file.is_file():
146
+ logger.info("Environment file not found. Aborting...")
147
+ return
148
+
149
+ delete_env(args.env)
150
+
151
+
152
+ def delete_env_file(args: Any):
153
+ envs_file = resolve_env_path()
154
+ if not envs_file.is_file():
155
+ logger.info("Environment file not found. Aborting...")
156
+ return
157
+
158
+ confirm_continuation(f"The file `{str(envs_file)}` will be deleted. Do you want to continue? (y/n)")
159
+ os.remove(envs_file)
160
+ logger.info("Successfully deleted the environment file.")