From b3ac52e98c4038cb2517434c1ab48db7200b66a6 Mon Sep 17 00:00:00 2001 From: Jun Luo <4catcode@gmail.com> Date: Fri, 8 Oct 2021 08:06:16 +0800 Subject: [PATCH] refactor(python/stellar): Since the firmware does not support MuxedAccount, we refuse to process this type of transaction. --- python/.changelog.d/1838.changed | 1 + python/src/trezorlib/stellar.py | 14 +++ python/tests/test_stellar.py | 169 ++++++++++++++++++++++++++++++- 3 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 python/.changelog.d/1838.changed diff --git a/python/.changelog.d/1838.changed b/python/.changelog.d/1838.changed new file mode 100644 index 000000000..5589843da --- /dev/null +++ b/python/.changelog.d/1838.changed @@ -0,0 +1 @@ +`trezorlib.stellar` will refuse to process transactions containing MuxedAccount diff --git a/python/src/trezorlib/stellar.py b/python/src/trezorlib/stellar.py index 401c84e5c..3b86413a7 100644 --- a/python/src/trezorlib/stellar.py +++ b/python/src/trezorlib/stellar.py @@ -45,6 +45,7 @@ try: Price, Network, ManageBuyOffer, + MuxedAccount, ) from stellar_sdk.xdr.signer_key_type import SignerKeyType @@ -92,6 +93,7 @@ def from_envelope(envelope: "TransactionEnvelope"): else: raise ValueError("Unsupported memo type") + _raise_if_account_muxed_id_exists(parsed_tx.source) tx = messages.StellarSignTx( source_account=parsed_tx.source.account_id, fee=parsed_tx.fee, @@ -113,6 +115,7 @@ def from_envelope(envelope: "TransactionEnvelope"): def _read_operation(op: "Operation"): # TODO: Let's add muxed account support later. if op.source: + _raise_if_account_muxed_id_exists(op.source) source_account = op.source.account_id else: source_account = None @@ -123,6 +126,7 @@ def _read_operation(op: "Operation"): starting_balance=_read_amount(op.starting_balance), ) if isinstance(op, Payment): + _raise_if_account_muxed_id_exists(op.destination) return messages.StellarPaymentOp( source_account=source_account, destination_account=op.destination.account_id, @@ -130,6 +134,7 @@ def _read_operation(op: "Operation"): amount=_read_amount(op.amount), ) if isinstance(op, PathPaymentStrictReceive): + _raise_if_account_muxed_id_exists(op.destination) operation = messages.StellarPathPaymentStrictReceiveOp( source_account=source_account, send_asset=_read_asset(op.send_asset), @@ -212,6 +217,7 @@ def _read_operation(op: "Operation"): is_authorized=bool(op.authorize.value), ) if isinstance(op, AccountMerge): + _raise_if_account_muxed_id_exists(op.destination) return messages.StellarAccountMergeOp( source_account=source_account, destination_account=op.destination.account_id, @@ -239,6 +245,7 @@ def _read_operation(op: "Operation"): offer_id=op.offer_id, ) if isinstance(op, PathPaymentStrictSend): + _raise_if_account_muxed_id_exists(op.destination) operation = messages.StellarPathPaymentStrictSendOp( source_account=source_account, send_asset=_read_asset(op.send_asset), @@ -252,6 +259,13 @@ def _read_operation(op: "Operation"): raise ValueError(f"Unknown operation type: {op.__class__.__name__}") +def _raise_if_account_muxed_id_exists(account: "MuxedAccount"): + # Currently Trezor firmware does not support MuxedAccount, + # so we throw an exception here. + if account.account_muxed_id is not None: + raise ValueError("MuxedAccount is not supported") + + def _read_amount(amount: str) -> int: return Operation.to_xdr_amount(amount) diff --git a/python/tests/test_stellar.py b/python/tests/test_stellar.py index c93c975c2..f6667b32e 100644 --- a/python/tests/test_stellar.py +++ b/python/tests/test_stellar.py @@ -14,7 +14,14 @@ # You should have received a copy of the License along with this library. # If not, see . import pytest -from stellar_sdk import Account, Asset, Network, TransactionBuilder, TrustLineEntryFlag +from stellar_sdk import ( + Account, + Asset, + Network, + TransactionBuilder, + TrustLineEntryFlag, + MuxedAccount, +) from stellar_sdk.strkey import StrKey from trezorlib import messages, stellar @@ -837,3 +844,163 @@ def test_path_payment_strict_send(): assert operations[0].paths[1].type == messages.StellarAssetType.ALPHANUM12 assert operations[0].paths[1].code == path_asset2.code assert operations[0].paths[1].issuer == path_asset2.issuer + + +def test_payment_muxed_account_not_support_raise(): + tx = make_default_tx() + destination = MuxedAccount( + "GDNSSYSCSSJ76FER5WEEXME5G4MTCUBKDRQSKOYP36KUKVDB2VCMERS6", 1 + ) + amount = "50.0111" + asset_code = "XLM" + asset_issuer = None + operation_source = "GAEB4MRKRCONK4J7MVQXAHTNDPAECUCCCNE7YC5CKM34U3OJ673A4D6V" + + envelope = tx.append_payment_op( + destination=destination, + amount=amount, + asset_code=asset_code, + asset_issuer=asset_issuer, + source=operation_source, + ).build() + + with pytest.raises(ValueError, match="MuxedAccount is not supported"): + stellar.from_envelope(envelope) + + +def test_path_payment_strict_send_muxed_account_not_support_raise(): + tx = make_default_tx() + destination = MuxedAccount( + "GDNSSYSCSSJ76FER5WEEXME5G4MTCUBKDRQSKOYP36KUKVDB2VCMERS6", 1 + ) + send_amount = "50.0112" + dest_min = "120" + send_code = "XLM" + send_issuer = None + dest_code = "USD" + dest_issuer = "GCSJ7MFIIGIRMAS4R3VT5FIFIAOXNMGDI5HPYTWS5X7HH74FSJ6STSGF" + operation_source = "GAEB4MRKRCONK4J7MVQXAHTNDPAECUCCCNE7YC5CKM34U3OJ673A4D6V" + path_asset1 = Asset( + "JPY", "GD6PV7DXQJX7AGVXFQ2MTCLTCH6LR3E6IO2EO2YDZD7F7IOZZCCB5DSQ" + ) + path_asset2 = Asset( + "BANANA", "GC7EKO37HNSKQ3V6RZ274EO7SFOWASQRHLX3OR5FIZK6UMV6LIEDXHGZ" + ) + + envelope = tx.append_path_payment_strict_send_op( + destination=destination, + send_code=send_code, + send_issuer=send_issuer, + send_amount=send_amount, + dest_code=dest_code, + dest_issuer=dest_issuer, + dest_min=dest_min, + path=[path_asset1, path_asset2], + source=operation_source, + ).build() + + with pytest.raises(ValueError, match="MuxedAccount is not supported"): + stellar.from_envelope(envelope) + + +def test_path_payment_strict_receive_muxed_account_not_support_raise(): + tx = make_default_tx() + destination = MuxedAccount( + "GDNSSYSCSSJ76FER5WEEXME5G4MTCUBKDRQSKOYP36KUKVDB2VCMERS6", 1 + ) + send_max = "50.0111" + dest_amount = "100" + send_code = "XLM" + send_issuer = None + dest_code = "USD" + dest_issuer = "GCSJ7MFIIGIRMAS4R3VT5FIFIAOXNMGDI5HPYTWS5X7HH74FSJ6STSGF" + operation_source = "GAEB4MRKRCONK4J7MVQXAHTNDPAECUCCCNE7YC5CKM34U3OJ673A4D6V" + path_asset1 = Asset( + "JPY", "GD6PV7DXQJX7AGVXFQ2MTCLTCH6LR3E6IO2EO2YDZD7F7IOZZCCB5DSQ" + ) + path_asset2 = Asset( + "BANANA", "GC7EKO37HNSKQ3V6RZ274EO7SFOWASQRHLX3OR5FIZK6UMV6LIEDXHGZ" + ) + + envelope = tx.append_path_payment_strict_receive_op( + destination=destination, + send_code=send_code, + send_issuer=send_issuer, + send_max=send_max, + dest_code=dest_code, + dest_issuer=dest_issuer, + dest_amount=dest_amount, + path=[path_asset1, path_asset2], + source=operation_source, + ).build() + + with pytest.raises(ValueError, match="MuxedAccount is not supported"): + stellar.from_envelope(envelope) + + +def test_account_merge_muxed_account_not_support_raise(): + tx = make_default_tx() + destination = MuxedAccount( + "GDNSSYSCSSJ76FER5WEEXME5G4MTCUBKDRQSKOYP36KUKVDB2VCMERS6", 1 + ) + operation_source = "GAEB4MRKRCONK4J7MVQXAHTNDPAECUCCCNE7YC5CKM34U3OJ673A4D6V" + + envelope = tx.append_account_merge_op( + destination=destination, source=operation_source + ).build() + + with pytest.raises(ValueError, match="MuxedAccount is not supported"): + stellar.from_envelope(envelope) + + +def test_op_source_muxed_account_not_support_raise(): + tx = make_default_tx() + destination = "GDNSSYSCSSJ76FER5WEEXME5G4MTCUBKDRQSKOYP36KUKVDB2VCMERS6" + amount = "50.0111" + asset_code = "XLM" + asset_issuer = None + operation_source = MuxedAccount( + "GAEB4MRKRCONK4J7MVQXAHTNDPAECUCCCNE7YC5CKM34U3OJ673A4D6V", 2 + ) + + envelope = tx.append_payment_op( + destination=destination, + amount=amount, + asset_code=asset_code, + asset_issuer=asset_issuer, + source=operation_source, + ).build() + + with pytest.raises(ValueError, match="MuxedAccount is not supported"): + stellar.from_envelope(envelope) + + +def test_tx_source_muxed_account_not_support_raise(): + source_account = Account( + account_id=MuxedAccount(TX_SOURCE, 123456), sequence=SEQUENCE + ) + destination = "GDNSSYSCSSJ76FER5WEEXME5G4MTCUBKDRQSKOYP36KUKVDB2VCMERS6" + amount = "50.0111" + asset_code = "XLM" + asset_issuer = None + operation_source = "GAEB4MRKRCONK4J7MVQXAHTNDPAECUCCCNE7YC5CKM34U3OJ673A4D6V" + + envelope = ( + TransactionBuilder( + source_account=source_account, + network_passphrase=Network.TESTNET_NETWORK_PASSPHRASE, + base_fee=BASE_FEE, + ) + .add_time_bounds(TIMEBOUNDS_START, TIMEBOUNDS_END) + .append_payment_op( + destination=destination, + amount=amount, + asset_code=asset_code, + asset_issuer=asset_issuer, + source=operation_source, + ) + .build() + ) + + with pytest.raises(ValueError, match="MuxedAccount is not supported"): + stellar.from_envelope(envelope)