-
Notifications
You must be signed in to change notification settings - Fork 36
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
Relayed V3 #434
Relayed V3 #434
Changes from 7 commits
98d8858
648430c
c0c817b
1cee88f
3686e19
ffe264e
28b172f
83591d9
3443391
d9cbc62
7410fee
bbfba04
1fb13f3
a551af9
dbb68ac
3110bc0
952cd34
ff3de4c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,21 @@ | ||
import logging | ||
from pathlib import Path | ||
from typing import Any, List | ||
from typing import Any, Dict, List | ||
|
||
from multiversx_sdk import Transaction, TransactionsConverter | ||
|
||
from multiversx_sdk_cli import cli_shared, utils | ||
from multiversx_sdk_cli.cli_output import CLIOutputBuilder | ||
from multiversx_sdk_cli.cosign_transaction import cosign_transaction | ||
from multiversx_sdk_cli.custom_network_provider import CustomNetworkProvider | ||
from multiversx_sdk_cli.errors import NoWalletProvided | ||
from multiversx_sdk_cli.errors import BadUsage, NoWalletProvided | ||
from multiversx_sdk_cli.transactions import (compute_relayed_v1_data, | ||
do_prepare_transaction, | ||
load_inner_transactions_from_file, | ||
load_transaction_from_file) | ||
|
||
logger = logging.getLogger("cli.transactions") | ||
|
||
|
||
def setup_parser(args: List[str], subparsers: Any) -> Any: | ||
parser = cli_shared.add_group_subparser(subparsers, "tx", "Create and broadcast Transactions") | ||
|
@@ -79,15 +85,46 @@ def create_transaction(args: Any): | |
if args.data_file: | ||
args.data = Path(args.data_file).read_text() | ||
|
||
check_relayer_transaction_with_data_field_for_relayed_v3(args) | ||
|
||
tx = do_prepare_transaction(args) | ||
|
||
if hasattr(args, "inner_transactions_outfile") and args.inner_transactions_outfile: | ||
save_transaction_to_inner_transactions_file(tx, args) | ||
return | ||
|
||
if hasattr(args, "relay") and args.relay: | ||
logger.warning("RelayedV1 transactions are deprecated. Please use RelayedV3 instead.") | ||
args.outfile.write(compute_relayed_v1_data(tx)) | ||
return | ||
|
||
cli_shared.send_or_simulate(tx, args) | ||
|
||
|
||
def save_transaction_to_inner_transactions_file(transaction: Transaction, args: Any): | ||
inner_txs_file = Path(args.inner_transactions_outfile).expanduser() | ||
transactions = get_inner_transactions_if_any(inner_txs_file) | ||
transactions.append(transaction) | ||
|
||
tx_converter = TransactionsConverter() | ||
inner_transactions: Dict[str, Any] = {} | ||
inner_transactions["innerTransactions"] = [tx_converter.transaction_to_dictionary(tx) for tx in transactions] | ||
|
||
with open(inner_txs_file, "w") as file: | ||
utils.dump_out_json(inner_transactions, file) | ||
|
||
|
||
def get_inner_transactions_if_any(file: Path) -> List[Transaction]: | ||
if file.is_file(): | ||
return load_inner_transactions_from_file(file) | ||
return [] | ||
|
||
|
||
def check_relayer_transaction_with_data_field_for_relayed_v3(args: Any): | ||
if hasattr(args, "inner_transactions") and args.inner_transactions and args.data: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a double check - is this an invalid case (wrt. to the Protocol)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, we can't set data field for the relayer's transaction. |
||
raise BadUsage("Can't set data field when creating a relayedV3 transaction") | ||
|
||
|
||
def send_transaction(args: Any): | ||
args = utils.as_object(args) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,10 +2,11 @@ | |
import json | ||
import logging | ||
import time | ||
from pathlib import Path | ||
from typing import Any, Dict, List, Optional, Protocol, TextIO | ||
|
||
from multiversx_sdk import (Address, Token, TokenComputer, TokenTransfer, | ||
Transaction, TransactionPayload, | ||
Transaction, TransactionsConverter, | ||
TransactionsFactoryConfig, | ||
TransferTransactionsFactory) | ||
|
||
|
@@ -37,48 +38,34 @@ def get_transaction(self, tx_hash: str, with_process_status: Optional[bool] = Fa | |
... | ||
|
||
|
||
class JSONTransaction: | ||
def __init__(self) -> None: | ||
self.hash = "" | ||
self.nonce = 0 | ||
self.value = "0" | ||
self.receiver = "" | ||
self.sender = "" | ||
self.senderUsername = "" | ||
self.receiverUsername = "" | ||
self.gasPrice = 0 | ||
self.gasLimit = 0 | ||
self.data: str = "" | ||
self.chainID = "" | ||
self.version = 0 | ||
self.options = 0 | ||
self.signature = "" | ||
self.guardian = "" | ||
self.guardianSignature = "" | ||
|
||
|
||
def do_prepare_transaction(args: Any) -> Transaction: | ||
account = load_sender_account_from_args(args) | ||
|
||
native_amount = int(args.value) | ||
transfers = getattr(args, "token_transfers", []) | ||
transfers = prepare_token_transfers(transfers) if transfers else [] | ||
transfers = prepare_token_transfers(transfers) | ||
|
||
config = TransactionsFactoryConfig(args.chain) | ||
factory = TransferTransactionsFactory(config) | ||
receiver = Address.new_from_bech32(args.receiver) | ||
|
||
# will be replaced with 'create_transaction_for_transfer' | ||
if transfers: | ||
tx = factory.create_transaction_for_esdt_token_transfer( | ||
# temporary workaround until proper fix in sdk-py | ||
if native_amount or transfers: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, we can drop the if-else after the fix in sdk-py. Or keep this as it is, but then drop the comment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll keep is as it is, at least for now. Removed the comment. |
||
tx = factory.create_transaction_for_transfer( | ||
sender=account.address, | ||
receiver=receiver, | ||
token_transfers=transfers | ||
native_amount=native_amount, | ||
token_transfers=transfers, | ||
data=str(args.data).encode() | ||
) | ||
else: | ||
tx = factory.create_transaction_for_native_token_transfer( | ||
sender=account.address, | ||
receiver=receiver, | ||
native_amount=int(args.value), | ||
data=str(args.data) | ||
# this is for transactions with no token transfers(egld/esdt); useful for setting the data field | ||
tx = Transaction( | ||
sender=account.address.to_bech32(), | ||
receiver=receiver.to_bech32(), | ||
data=str(args.data).encode(), | ||
gas_limit=int(args.gas_limit), | ||
chain_id=args.chain | ||
) | ||
|
||
tx.gas_limit = int(args.gas_limit) | ||
|
@@ -93,6 +80,12 @@ def do_prepare_transaction(args: Any) -> Transaction: | |
if args.guardian: | ||
tx.guardian = args.guardian | ||
|
||
if args.relayer: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
tx.relayer = Address.new_from_bech32(args.relayer).to_bech32() | ||
|
||
if args.inner_transactions: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
tx.inner_transactions = load_inner_transactions_from_file(Path(args.inner_transactions).expanduser()) | ||
|
||
tx.signature = bytes.fromhex(account.sign_transaction(tx)) | ||
tx = sign_tx_by_guardian(args, tx) | ||
|
||
|
@@ -231,37 +224,15 @@ def compute_relayed_v1_data(tx: Transaction) -> str: | |
|
||
def load_transaction_from_file(f: TextIO) -> Transaction: | ||
data_json: bytes = f.read().encode() | ||
fields = json.loads(data_json).get("tx") or json.loads(data_json).get("emittedTransaction") | ||
|
||
instance = JSONTransaction() | ||
instance.__dict__.update(fields) | ||
|
||
loaded_tx = Transaction( | ||
chain_id=instance.chainID, | ||
sender=instance.sender, | ||
receiver=instance.receiver, | ||
sender_username=decode_field_value(instance.senderUsername), | ||
receiver_username=decode_field_value(instance.receiverUsername), | ||
gas_limit=instance.gasLimit, | ||
gas_price=instance.gasPrice, | ||
value=int(instance.value), | ||
data=TransactionPayload.from_encoded_str(instance.data).data, | ||
version=instance.version, | ||
options=instance.options, | ||
nonce=instance.nonce | ||
) | ||
|
||
if instance.guardian: | ||
loaded_tx.guardian = instance.guardian | ||
|
||
if instance.signature: | ||
loaded_tx.signature = bytes.fromhex(instance.signature) | ||
transaction_dictionary = json.loads(data_json).get("tx") or json.loads(data_json).get("emittedTransaction") | ||
|
||
if instance.guardianSignature: | ||
loaded_tx.guardian_signature = bytes.fromhex(instance.guardianSignature) | ||
tx_converter = TransactionsConverter() | ||
return tx_converter.dictionary_to_transaction(transaction_dictionary) | ||
|
||
return loaded_tx | ||
|
||
def load_inner_transactions_from_file(path: Path) -> List[Transaction]: | ||
data_json = path.read_bytes() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. read_text(), instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done! |
||
transactions: List[Dict[str, Any]] = json.loads(data_json).get("innerTransactions") | ||
|
||
def decode_field_value(value: str) -> str: | ||
return base64.b64decode(value).decode() | ||
tx_converter = TransactionsConverter() | ||
return [tx_converter.dictionary_to_transaction(transaction) for transaction in transactions] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,4 +10,4 @@ requests-cache | |
rich==13.3.4 | ||
argcomplete==3.2.2 | ||
|
||
multiversx-sdk>=0.9.2,<1.0.0 | ||
multiversx-sdk @ git+https://github.com/multiversx/mx-sdk-py@feat/next | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 (maybe even a fixed commit hash or tag) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can simplify the arguments of
add_tx_args
, with respect to its usage. E.g. we can dropwith_relayed_v3
andwith_guardian
, since the defaults are not overridden (at least, not now, maybe never).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Removed
with_guardian
andwith_relayed_v3
. Arguments are now always present.