Skip to content

Commit bc08d7f

Browse files
authored
Merge pull request #476 from multiversx/contract-refactoring
Refactored smart contract interactions
2 parents ed875ff + dfe48d4 commit bc08d7f

8 files changed

+179
-60
lines changed

multiversx_sdk_cli/cli_contracts.py

+78-40
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import logging
33
import os
44
from pathlib import Path
5-
from typing import Any
5+
from typing import Any, Union
66

77
from multiversx_sdk import (
88
Address,
@@ -21,8 +21,8 @@
2121
from multiversx_sdk_cli.contracts import SmartContract
2222
from multiversx_sdk_cli.cosign_transaction import cosign_transaction
2323
from multiversx_sdk_cli.docker import is_docker_installed, run_docker
24-
from multiversx_sdk_cli.errors import DockerMissingError, NoWalletProvided
25-
from multiversx_sdk_cli.interfaces import IAddress
24+
from multiversx_sdk_cli.errors import DockerMissingError
25+
from multiversx_sdk_cli.interfaces import IAccount
2626
from multiversx_sdk_cli.ux import show_warning
2727

2828
logger = logging.getLogger("cli.contracts")
@@ -32,15 +32,10 @@ def setup_parser(args: list[str], subparsers: Any) -> Any:
3232
parser = cli_shared.add_group_subparser(
3333
subparsers,
3434
"contract",
35-
"Build, deploy, upgrade and interact with Smart Contracts",
35+
"Deploy, upgrade and interact with Smart Contracts",
3636
)
3737
subparsers = parser.add_subparsers()
3838

39-
sub = cli_shared.add_command_subparser(
40-
subparsers, "contract", "build", "Build a Smart Contract project. This command is DISABLED."
41-
)
42-
sub.set_defaults(func=build)
43-
4439
output_description = CLIOutputBuilder.describe(
4540
with_contract=True, with_transaction_on_network=True, with_simulation=True
4641
)
@@ -72,6 +67,7 @@ def setup_parser(args: list[str], subparsers: Any) -> Any:
7267
)
7368
cli_shared.add_broadcast_args(sub)
7469
cli_shared.add_guardian_wallet_args(args, sub)
70+
cli_shared.add_relayed_v3_wallet_args(args, sub)
7571

7672
sub.set_defaults(func=deploy)
7773

@@ -103,6 +99,7 @@ def setup_parser(args: list[str], subparsers: Any) -> Any:
10399
)
104100
cli_shared.add_broadcast_args(sub)
105101
cli_shared.add_guardian_wallet_args(args, sub)
102+
cli_shared.add_relayed_v3_wallet_args(args, sub)
106103

107104
sub.set_defaults(func=call)
108105

@@ -134,6 +131,7 @@ def setup_parser(args: list[str], subparsers: Any) -> Any:
134131
)
135132
cli_shared.add_broadcast_args(sub)
136133
cli_shared.add_guardian_wallet_args(args, sub)
134+
cli_shared.add_relayed_v3_wallet_args(args, sub)
137135

138136
sub.set_defaults(func=upgrade)
139137

@@ -205,6 +203,11 @@ def setup_parser(args: list[str], subparsers: Any) -> Any:
205203
)
206204
sub.set_defaults(func=do_reproducible_build)
207205

206+
sub = cli_shared.add_command_subparser(
207+
subparsers, "contract", "build", "Build a Smart Contract project. This command is DISABLED."
208+
)
209+
sub.set_defaults(func=build)
210+
208211
parser.epilog = cli_shared.build_group_epilog(subparsers)
209212
return subparsers
210213

@@ -274,7 +277,7 @@ def _add_contract_arg(sub: Any):
274277

275278

276279
def _add_contract_abi_arg(sub: Any):
277-
sub.add_argument("--abi", type=str, help="the ABI of the Smart Contract")
280+
sub.add_argument("--abi", type=str, help="the ABI file of the Smart Contract")
278281

279282

280283
def _add_function_arg(sub: Any):
@@ -338,9 +341,20 @@ def deploy(args: Any):
338341
cli_shared.check_guardian_and_options_args(args)
339342
cli_shared.check_broadcast_args(args)
340343
cli_shared.prepare_chain_id_in_args(args)
341-
cli_shared.prepare_nonce_in_args(args)
342344

343345
sender = cli_shared.prepare_account(args)
346+
347+
if not args.nonce:
348+
nonce = cli_shared.get_current_nonce_for_address(sender.address, args.proxy)
349+
else:
350+
nonce = int(args.nonce)
351+
352+
guardian = cli_shared.load_guardian_account(args)
353+
guardian_address = cli_shared.get_guardian_address(guardian, args)
354+
355+
relayer = cli_shared.load_relayer_account(args)
356+
relayer_address = cli_shared.get_relayer_address(relayer, args)
357+
344358
config = TransactionsFactoryConfig(args.chain)
345359
abi = Abi.load(Path(args.abi)) if args.abi else None
346360
contract = SmartContract(config, abi)
@@ -358,45 +372,57 @@ def deploy(args: Any):
358372
payable_by_sc=args.metadata_payable_by_sc,
359373
gas_limit=int(args.gas_limit),
360374
value=int(args.value),
361-
nonce=int(args.nonce),
375+
nonce=nonce,
362376
version=int(args.version),
363377
options=int(args.options),
364-
guardian=args.guardian,
378+
guardian=guardian_address,
379+
relayer=relayer_address,
365380
)
366-
tx = _sign_guarded_tx(args, tx)
381+
tx = _sign_guarded_tx_if_guardian(guardian, args, tx)
382+
_sign_relayed_tx_if_relayer(relayer, tx)
367383

368384
address_computer = AddressComputer(NUMBER_OF_SHARDS)
369-
contract_address = address_computer.compute_contract_address(deployer=sender.address, deployment_nonce=args.nonce)
385+
contract_address = address_computer.compute_contract_address(deployer=sender.address, deployment_nonce=tx.nonce)
370386

371387
logger.info("Contract address: %s", contract_address.to_bech32())
372388
utils.log_explorer_contract_address(args.chain, contract_address.to_bech32())
373389

374390
_send_or_simulate(tx, contract_address, args)
375391

376392

377-
def _sign_guarded_tx(args: Any, tx: Transaction) -> Transaction:
378-
try:
379-
guardian_account = cli_shared.prepare_guardian_account(args)
380-
except NoWalletProvided:
381-
guardian_account = None
382-
383-
if guardian_account:
384-
tx.guardian_signature = bytes.fromhex(guardian_account.sign_transaction(tx))
385-
elif args.guardian:
386-
tx = cosign_transaction(tx, args.guardian_service_url, args.guardian_2fa_code) # type: ignore
393+
def _sign_guarded_tx_if_guardian(guardian: Union[IAccount, None], args: Any, tx: Transaction) -> Transaction:
394+
if guardian:
395+
tx.guardian_signature = bytes.fromhex(guardian.sign_transaction(tx))
396+
elif tx.guardian and args.guardian_service_url and args.guardian_2fa_code:
397+
tx = cosign_transaction(tx, args.guardian_service_url, args.guardian_2fa_code)
387398

388399
return tx
389400

390401

402+
def _sign_relayed_tx_if_relayer(relayer: Union[IAccount, None], tx: Transaction):
403+
if relayer and tx.relayer:
404+
tx.relayer_signature = bytes.fromhex(relayer.sign_transaction(tx))
405+
406+
391407
def call(args: Any):
392408
logger.debug("call")
393409
cli_shared.check_guardian_and_options_args(args)
394410
cli_shared.check_broadcast_args(args)
395411
cli_shared.prepare_chain_id_in_args(args)
396-
cli_shared.prepare_nonce_in_args(args)
397412

398413
sender = cli_shared.prepare_account(args)
399414

415+
if not args.nonce:
416+
nonce = cli_shared.get_current_nonce_for_address(sender.address, args.proxy)
417+
else:
418+
nonce = int(args.nonce)
419+
420+
guardian = cli_shared.load_guardian_account(args)
421+
guardian_address = cli_shared.get_guardian_address(guardian, args)
422+
423+
relayer = cli_shared.load_relayer_account(args)
424+
relayer_address = cli_shared.get_relayer_address(relayer, args)
425+
400426
config = TransactionsFactoryConfig(args.chain)
401427
abi = Abi.load(Path(args.abi)) if args.abi else None
402428
contract = SmartContract(config, abi)
@@ -413,12 +439,14 @@ def call(args: Any):
413439
gas_limit=int(args.gas_limit),
414440
value=int(args.value),
415441
transfers=args.token_transfers,
416-
nonce=int(args.nonce),
442+
nonce=nonce,
417443
version=int(args.version),
418444
options=int(args.options),
419-
guardian=args.guardian,
445+
guardian=guardian_address,
446+
relayer=relayer_address,
420447
)
421-
tx = _sign_guarded_tx(args, tx)
448+
tx = _sign_guarded_tx_if_guardian(guardian, args, tx)
449+
_sign_relayed_tx_if_relayer(relayer, tx)
422450

423451
_send_or_simulate(tx, contract_address, args)
424452

@@ -428,9 +456,20 @@ def upgrade(args: Any):
428456
cli_shared.check_guardian_and_options_args(args)
429457
cli_shared.check_broadcast_args(args)
430458
cli_shared.prepare_chain_id_in_args(args)
431-
cli_shared.prepare_nonce_in_args(args)
432459

433460
sender = cli_shared.prepare_account(args)
461+
462+
if not args.nonce:
463+
nonce = cli_shared.get_current_nonce_for_address(sender.address, args.proxy)
464+
else:
465+
nonce = int(args.nonce)
466+
467+
guardian = cli_shared.load_guardian_account(args)
468+
guardian_address = cli_shared.get_guardian_address(guardian, args)
469+
470+
relayer = cli_shared.load_relayer_account(args)
471+
relayer_address = cli_shared.get_relayer_address(relayer, args)
472+
434473
config = TransactionsFactoryConfig(args.chain)
435474
abi = Abi.load(Path(args.abi)) if args.abi else None
436475
contract = SmartContract(config, abi)
@@ -450,24 +489,23 @@ def upgrade(args: Any):
450489
payable_by_sc=args.metadata_payable_by_sc,
451490
gas_limit=int(args.gas_limit),
452491
value=int(args.value),
453-
nonce=int(args.nonce),
492+
nonce=nonce,
454493
version=int(args.version),
455494
options=int(args.options),
456-
guardian=args.guardian,
495+
guardian=guardian_address,
496+
relayer=relayer_address,
457497
)
458-
tx = _sign_guarded_tx(args, tx)
498+
tx = _sign_guarded_tx_if_guardian(guardian, args, tx)
499+
_sign_relayed_tx_if_relayer(relayer, tx)
459500

460501
_send_or_simulate(tx, contract_address, args)
461502

462503

463504
def query(args: Any):
464505
logger.debug("query")
465506

466-
# workaround so we can use the function below to set chainID
467-
args.chain = ""
468-
cli_shared.prepare_chain_id_in_args(args)
469-
470-
factory_config = TransactionsFactoryConfig(args.chain)
507+
# we don't need chainID to query a contract; we use the provided proxy
508+
factory_config = TransactionsFactoryConfig("")
471509
abi = Abi.load(Path(args.abi)) if args.abi else None
472510
contract = SmartContract(factory_config, abi)
473511

@@ -504,14 +542,14 @@ def _get_contract_arguments(args: Any) -> tuple[list[Any], bool]:
504542
return args.arguments, True
505543

506544

507-
def _send_or_simulate(tx: Transaction, contract_address: IAddress, args: Any):
545+
def _send_or_simulate(tx: Transaction, contract_address: Address, args: Any):
508546
output_builder = cli_shared.send_or_simulate(tx, args, dump_output=False)
509547
output_builder.set_contract_address(contract_address)
510548
utils.dump_out_json(output_builder.build(), outfile=args.outfile)
511549

512550

513551
def verify(args: Any) -> None:
514-
contract = Address.from_bech32(args.contract)
552+
contract = Address.new_from_bech32(args.contract)
515553
verifier_url = args.verifier_url
516554

517555
packaged_src = Path(args.packaged_src).expanduser().resolve()

multiversx_sdk_cli/cli_delegation.py

+1
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ def _add_common_arguments(args: List[str], sub: Any):
359359
cli_shared.add_broadcast_args(sub)
360360
cli_shared.add_outfile_arg(sub, what="signed transaction, hash")
361361
cli_shared.add_guardian_wallet_args(args, sub)
362+
cli_shared.add_relayed_v3_wallet_args(args, sub)
362363

363364

364365
def ensure_arguments_are_provided_and_prepared(args: Any):

multiversx_sdk_cli/cli_dns.py

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def setup_parser(args: List[str], subparsers: Any) -> Any:
3535
cli_shared.add_proxy_arg(sub)
3636
cli_shared.add_tx_args(args, sub, with_receiver=False, with_data=False)
3737
cli_shared.add_guardian_wallet_args(args, sub)
38+
cli_shared.add_relayed_v3_wallet_args(args, sub)
3839
sub.add_argument("--name", help="the name to register")
3940
sub.set_defaults(func=register)
4041

multiversx_sdk_cli/cli_password.py

+7
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,10 @@ def load_guardian_password(args: Any) -> str:
1414
with open(args.guardian_passfile) as pass_file:
1515
return pass_file.read().strip()
1616
return getpass("Keyfile's password: ")
17+
18+
19+
def load_relayer_password(args: Any) -> str:
20+
if args.relayer_passfile:
21+
with open(args.relayer_passfile) as pass_file:
22+
return pass_file.read().strip()
23+
return getpass("Keyfile's password: ")

0 commit comments

Comments
 (0)