Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added RelayedV3 support #457

Merged
merged 5 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion multiversx_sdk_cli/cli_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ def add_tx_args(
with_nonce: bool = True,
with_receiver: bool = True,
with_data: bool = True,
with_estimate_gas: bool = False):
with_estimate_gas: bool = False,
with_relayer_wallet_args: bool = True):
if with_nonce:
sub.add_argument("--nonce", type=int, required=not ("--recall-nonce" in args), help="# the nonce for the transaction")
sub.add_argument("--recall-nonce", action="store_true", default=False, help="⭮ whether to recall the nonce when creating the transaction (default: %(default)s)")
Expand All @@ -90,6 +91,10 @@ def add_tx_args(
sub.add_argument("--chain", help="the chain identifier")
sub.add_argument("--version", type=int, default=DEFAULT_TX_VERSION, help="the transaction version (default: %(default)s)")

sub.add_argument("--relayer", help="the bech32 address of the relayer")
if with_relayer_wallet_args:
add_relayed_v3_wallet_args(args, sub)

add_guardian_args(sub)

sub.add_argument("--options", type=int, default=0, help="the transaction options (default: 0)")
Expand Down Expand Up @@ -122,6 +127,16 @@ def add_guardian_wallet_args(args: List[str], sub: Any):
sub.add_argument("--guardian-ledger-address-index", type=int, default=0, help="🔐 the index of the address when using Ledger")


def add_relayed_v3_wallet_args(args: List[str], sub: Any):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

sub.add_argument("--relayer-pem", required=check_if_sign_method_required(args, "--relayer-pem"), help="🔑 the PEM file, if keyfile not provided")
sub.add_argument("--relayer-pem-index", type=int, default=0, help="🔑 the index in the PEM file (default: %(default)s)")
sub.add_argument("--relayer-keyfile", required=check_if_sign_method_required(args, "--relayer-keyfile"), help="🔑 a JSON keyfile, if PEM not provided")
sub.add_argument("--relayer-passfile", help="🔑 a file containing keyfile's password, if keyfile provided")
sub.add_argument("--relayer-ledger", action="store_true", required=check_if_sign_method_required(args, "--relayer-ledger"), default=False, help="🔐 bool flag for signing transaction using ledger")
sub.add_argument("--relayer-ledger-account-index", type=int, default=0, help="🔐 the index of the account when using Ledger")
sub.add_argument("--relayer-ledger-address-index", type=int, default=0, help="🔐 the index of the address when using Ledger")


def add_proxy_arg(sub: Any):
sub.add_argument("--proxy", help="🔗 the URL of the proxy")

Expand Down
2 changes: 2 additions & 0 deletions multiversx_sdk_cli/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class ITransaction(Protocol):
guardian: str
signature: bytes
guardian_signature: bytes
relayer: str
relayer_signature: bytes


class IAccount(Protocol):
Expand Down
59 changes: 59 additions & 0 deletions multiversx_sdk_cli/tests/test_cli_transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from pathlib import Path
from typing import Any

import pytest

from multiversx_sdk_cli.cli import main

testdata_path = Path(__file__).parent / "testdata"
Expand Down Expand Up @@ -105,5 +107,62 @@ def test_create_multi_transfer_transaction_with_single_egld_transfer(capsys: Any
assert data == "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@01@45474c442d303030303030@@0de0b6b3a7640000"


def test_create_relayed_v3_transaction(capsys: Any):
return_code = main([
"tx", "new",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not possible to take a user transaction, already signed, and sign it with a relayer? Maybe mxpy tx relay or mxpy wallet sign-as-relayer? 💭

I think we should allow users to decouple (in a way or another) the step of signing as user from the step of signing as relayer.

Maybe brainstorm this a bit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, sounds like a good idea. Added a new command, mxpy tx relay.

"--pem", str(testdata_path / "alice.pem"),
"--receiver", "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx",
"--nonce", "7",
"--gas-limit", "1300000",
"--value", "1000000000000000000",
"--chain", "T",
"--relayer", "erd1cqqxak4wun7508e0yj9ng843r6hv4mzd0hhpjpsejkpn9wa9yq8sj7u2u5",
"--relayer-pem", str(testdata_path / "testUser.pem")
])
assert return_code == 0

tx = _read_stdout(capsys)
tx_json = json.loads(tx)["emittedTransaction"]
assert tx_json["sender"] == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
assert tx_json["receiver"] == "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"
assert tx_json["relayer"] == "erd1cqqxak4wun7508e0yj9ng843r6hv4mzd0hhpjpsejkpn9wa9yq8sj7u2u5"
assert tx_json["signature"]
assert tx_json["relayerSignature"]

# no relayer wallet provided
return_code = main([
"tx", "new",
"--pem", str(testdata_path / "alice.pem"),
"--receiver", "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx",
"--nonce", "7",
"--gas-limit", "1300000",
"--value", "1000000000000000000",
"--chain", "T",
"--relayer", "erd1cqqxak4wun7508e0yj9ng843r6hv4mzd0hhpjpsejkpn9wa9yq8sj7u2u5"
])
assert return_code == 0
tx = _read_stdout(capsys)
tx_json = json.loads(tx)["emittedTransaction"]
assert tx_json["sender"] == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
assert tx_json["receiver"] == "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"
assert tx_json["relayer"] == "erd1cqqxak4wun7508e0yj9ng843r6hv4mzd0hhpjpsejkpn9wa9yq8sj7u2u5"
assert tx_json["signature"]
assert not tx_json["relayerSignature"]

# incorrect relayer wallet
with pytest.raises(Exception, match="Relayer address does not match the provided relayer wallet."):
main([
"tx", "new",
"--pem", str(testdata_path / "alice.pem"),
"--receiver", "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx",
"--nonce", "7",
"--gas-limit", "1300000",
"--value", "1000000000000000000",
"--chain", "T",
"--relayer", "erd1cqqxak4wun7508e0yj9ng843r6hv4mzd0hhpjpsejkpn9wa9yq8sj7u2u5",
"--relayer-pem", str(testdata_path / "alice.pem")
])


def _read_stdout(capsys: Any) -> str:
return capsys.readouterr().out.strip()
26 changes: 26 additions & 0 deletions multiversx_sdk_cli/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,18 @@ def do_prepare_transaction(args: Any) -> Transaction:
if args.guardian:
tx.guardian = args.guardian

if args.relayer:
tx.relayer = args.relayer

try:
relayer_account = load_relayer_account_from_args(args)
if relayer_account.address.to_bech32() != tx.relayer:
raise Exception("Relayer address does not match the provided relayer wallet.")

tx.relayer_signature = bytes.fromhex(relayer_account.sign_transaction(tx))
except errors.NoWalletProvided:
logger.warning("Relayer wallet not provided. Transaction will not be signed by relayer.")

tx.signature = bytes.fromhex(account.sign_transaction(tx))
tx = sign_tx_by_guardian(args, tx)

Expand All @@ -97,6 +109,20 @@ def load_sender_account_from_args(args: Any) -> Account:
return account


def load_relayer_account_from_args(args: Any) -> Account:
if args.relayer_ledger:
account = LedgerAccount(account_index=args.relayer_ledger_account_index, address_index=args.relayer_ledger_address_index)
if args.relayer_pem:
account = Account(pem_file=args.relayer_pem, pem_index=args.relayer_pem_index)
elif args.relayer_keyfile:
password = load_password(args)
account = Account(key_file=args.relayer_keyfile, password=password)
else:
raise errors.NoWalletProvided()

return account


def prepare_token_transfers(transfers: List[Any]) -> List[TokenTransfer]:
token_computer = TokenComputer()
token_transfers: List[TokenTransfer] = []
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "multiversx-sdk-cli"
version = "9.8.1"
version = "9.9.0"
authors = [
{ name="MultiversX" },
]
Expand All @@ -28,7 +28,7 @@ dependencies = [
"requests-cache",
"rich==13.3.4",
"argcomplete==3.2.2",
"multiversx-sdk==0.16.3"
"multiversx-sdk==0.17.0"
]

[project.scripts]
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ requests-cache
rich==13.3.4
argcomplete==3.2.2

multiversx-sdk==0.16.3
multiversx-sdk==0.17.0
Loading