diff --git a/trezorctl b/trezorctl index 51380f30be..35b9abfd94 100755 --- a/trezorctl +++ b/trezorctl @@ -38,6 +38,7 @@ from trezorlib import messages as proto from trezorlib import protobuf from trezorlib import stellar from trezorlib import tools +from trezorlib import ripple class ChoiceType(click.Choice): @@ -1060,8 +1061,16 @@ def stellar_sign_transaction(connect, b64envelope, address, network_passphrase): @click.pass_obj def ripple_get_address(connect, address, show_display): client = connect() - address_n = tools.parse_path(address) - return client.ripple_get_address(address_n, show_display) + return ripple.ripple_get_address(client, address, show_display) + + +@cli.command(help='Sign Ripple transaction') +@click.option('-n', '--address', required=True, help="BIP-32 path to key, e.g. m/44'/144'/0'/0/0") +@click.pass_obj +def ripple_sign_transaction(connect, address, show_display): + client = connect() + # todo load from json + return ripple.ripple_sign_tx(client, address, show_display) # # Main diff --git a/trezorlib/client.py b/trezorlib/client.py index e11f09a67b..e8cc4d67a0 100644 --- a/trezorlib/client.py +++ b/trezorlib/client.py @@ -33,7 +33,6 @@ from . import mapping from . import nem from . import protobuf from . import stellar -from . import ripple from .debuglink import DebugLink if sys.version_info.major < 3: @@ -1083,19 +1082,6 @@ class ProtocolMixin(object): return self.call(proto.SelfTest(payload=b'\x00\xFF\x55\xAA\x66\x99\x33\xCCABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\x00\xFF\x55\xAA\x66\x99\x33\xCC')) - @field('address') - @expect(proto.RippleAddress) - def ripple_get_address(self, address_n, show_display=False): - return self.call( - proto.RippleGetAddress( - address_n=address_n, show_display=show_display)) - - @expect(proto.RippleSignedTx) - def ripple_sign_tx(self, n, transaction): - msg = ripple.create_sign_tx(transaction) - msg.address_n = tools.parse_path(n) - return self.call(msg) - @field('public_key') @expect(proto.StellarPublicKey) def stellar_get_public_key(self, address_n, show_display=False): diff --git a/trezorlib/ripple.py b/trezorlib/ripple.py index 908b117a21..e1fdf1d3ae 100644 --- a/trezorlib/ripple.py +++ b/trezorlib/ripple.py @@ -18,9 +18,27 @@ import base64 import struct from . import messages +from . import tools +from .client import field +from .client import expect -def create_sign_tx(transaction) -> messages.RippleSignTx: +@field('address') +@expect(messages.RippleAddress) +def ripple_get_address(client, address_n, show_display=False): + return client.call( + messages.RippleGetAddress( + address_n=address_n, show_display=show_display)) + + +@expect(messages.RippleSignedTx) +def ripple_sign_tx(client, address_n, transaction): + msg = _create_sign_tx(transaction) + msg.address_n = address_n + return client.call(msg) + + +def _create_sign_tx(transaction) -> messages.RippleSignTx: if not all(transaction.get(k) for k in ("Fee", "Sequence", "TransactionType", "Amount", "Destination")): raise ValueError("Some of the required fields missing (Fee, Sequence, TransactionType, Amount, Destination") if transaction["TransactionType"] != "Payment": @@ -31,11 +49,11 @@ def create_sign_tx(transaction) -> messages.RippleSignTx: sequence=transaction.get("Sequence"), flags=transaction.get("Flags"), last_ledger_sequence=transaction.get("LastLedgerSequence"), - payment=create_payment(transaction), + payment=_create_payment(transaction), ) -def create_payment(transaction) -> messages.RipplePayment: +def _create_payment(transaction) -> messages.RipplePayment: return messages.RipplePayment( amount=transaction.get("Amount"), destination=transaction.get("Destination") diff --git a/trezorlib/tests/device_tests/test_msg_ripple_get_address.py b/trezorlib/tests/device_tests/test_msg_ripple_get_address.py index 3c2d2a4a7b..872e2e07d9 100644 --- a/trezorlib/tests/device_tests/test_msg_ripple_get_address.py +++ b/trezorlib/tests/device_tests/test_msg_ripple_get_address.py @@ -20,6 +20,7 @@ from .common import TrezorTest from .conftest import TREZOR_VERSION from binascii import hexlify from trezorlib.client import CallException +from trezorlib.ripple import ripple_get_address from trezorlib.tools import parse_path @@ -32,11 +33,11 @@ class TestMsgRippleGetAddress(TrezorTest): # data from https://iancoleman.io/bip39/#english self.setup_mnemonic_allallall() - address = self.client.ripple_get_address(parse_path("m/44'/144'/0'/0/0")) + address = ripple_get_address(self.client, parse_path("m/44'/144'/0'/0/0")) assert address == 'rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H' - address = self.client.ripple_get_address(parse_path("m/44'/144'/0'/0/1")) + address = ripple_get_address(self.client, parse_path("m/44'/144'/0'/0/1")) assert address == 'rBKz5MC2iXdoS3XgnNSYmF69K1Yo4NS3Ws' - address = self.client.ripple_get_address(parse_path("m/44'/144'/1'/0/0")) + address = ripple_get_address(self.client, parse_path("m/44'/144'/1'/0/0")) assert address == 'rJX2KwzaLJDyFhhtXKi3htaLfaUH2tptEX' def test_ripple_get_address_other(self): @@ -47,7 +48,7 @@ class TestMsgRippleGetAddress(TrezorTest): passphrase_protection=False, label='test', language='english') - address = self.client.ripple_get_address(parse_path("m/44'/144'/0'/0/0")) + address = ripple_get_address(self.client, parse_path("m/44'/144'/0'/0/0")) assert address == 'r4ocGE47gm4G4LkA9mriVHQqzpMLBTgnTY' - address = self.client.ripple_get_address(parse_path("m/44'/144'/0'/0/1")) + address = ripple_get_address(self.client, parse_path("m/44'/144'/0'/0/1")) assert address == 'rUt9ULSrUvfCmke8HTFU1szbmFpWzVbBXW' diff --git a/trezorlib/tests/device_tests/test_msg_ripple_sign_tx.py b/trezorlib/tests/device_tests/test_msg_ripple_sign_tx.py index 69d1a9a7af..568dfd5933 100644 --- a/trezorlib/tests/device_tests/test_msg_ripple_sign_tx.py +++ b/trezorlib/tests/device_tests/test_msg_ripple_sign_tx.py @@ -19,9 +19,9 @@ import pytest from .common import TrezorTest from .conftest import TREZOR_VERSION from binascii import unhexlify -from trezorlib import ripple -from trezorlib import messages as proto +from trezorlib import messages from trezorlib.client import CallException +from trezorlib.ripple import ripple_sign_tx from trezorlib.tools import parse_path @@ -33,7 +33,8 @@ class TestMsgRippleSignTx(TrezorTest): def test_ripple_sign_simple_tx(self): self.setup_mnemonic_allallall() - resp = self.client.ripple_sign_tx( + resp = ripple_sign_tx( + self.client, parse_path("m/44'/144'/0'/0/0"), { "TransactionType": "Payment", "Destination": "rBKz5MC2iXdoS3XgnNSYmF69K1Yo4NS3Ws", @@ -45,7 +46,8 @@ class TestMsgRippleSignTx(TrezorTest): assert resp.signature == unhexlify('3045022100e243ef623675eeeb95965c35c3e06d63a9fc68bb37e17dc87af9c0af83ec057e02206ca8aa5eaab8396397aef6d38d25710441faf7c79d292ee1d627df15ad9346c0') assert resp.serialized_tx == unhexlify('12000022800000002400000019614000000005f5e1006840000000000186a0732102131facd1eab748d6cddc492f54b04e8c35658894f4add2232ebc5afe7521dbe474473045022100e243ef623675eeeb95965c35c3e06d63a9fc68bb37e17dc87af9c0af83ec057e02206ca8aa5eaab8396397aef6d38d25710441faf7c79d292ee1d627df15ad9346c081148fb40e1ffa5d557ce9851a535af94965e0dd098883147148ebebf7304ccdf1676fefcf9734cf1e780826') - resp = self.client.ripple_sign_tx( + resp = ripple_sign_tx( + self.client, parse_path("m/44'/144'/0'/0/2"), { "TransactionType": "Payment", "Destination": "rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H", @@ -56,7 +58,8 @@ class TestMsgRippleSignTx(TrezorTest): assert resp.signature == unhexlify('3044022069900e6e578997fad5189981b74b16badc7ba8b9f1052694033fa2779113ddc002206c8006ada310edf099fb22c0c12073550c8fc73247b236a974c5f1144831dd5f') assert resp.serialized_tx == unhexlify('1200002280000000240000000161400000000000000168400000000000000a732103dbed1e77cb91a005e2ec71afbccce5444c9be58276665a3859040f692de8fed274463044022069900e6e578997fad5189981b74b16badc7ba8b9f1052694033fa2779113ddc002206c8006ada310edf099fb22c0c12073550c8fc73247b236a974c5f1144831dd5f8114bdf86f3ae715ba346b7772ea0e133f48828b766483148fb40e1ffa5d557ce9851a535af94965e0dd0988') - resp = self.client.ripple_sign_tx( + resp = ripple_sign_tx( + self.client, parse_path("m/44'/144'/0'/0/2"), { "TransactionType": "Payment", "Destination": "rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H", @@ -72,7 +75,8 @@ class TestMsgRippleSignTx(TrezorTest): def test_ripple_sign_invalid_fee(self): with pytest.raises(CallException) as exc: - self.client.ripple_sign_tx( + ripple_sign_tx( + self.client, parse_path("m/44'/144'/0'/0/2"), { "TransactionType": "Payment", "Destination": "rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H", @@ -81,5 +85,5 @@ class TestMsgRippleSignTx(TrezorTest): "Fee": 1, "Sequence": 1, }) - assert exc.value.args[0] == proto.FailureType.ProcessError + assert exc.value.args[0] == messages.FailureType.ProcessError assert exc.value.args[1].endswith('Fee must be in the range of 10 to 10,000 drops')