From 3490407b838a7e2f61c6f6ce5dc1d5c6f012f699 Mon Sep 17 00:00:00 2001 From: Coline Date: Fri, 22 Apr 2022 17:18:53 +0200 Subject: [PATCH] feat: all simple test of sign transaction without screen --- .../boilerplate_client/boilerplate_cmd.py | 3 - .../boilerplate_client/transaction.py | 23 ++- tests/speculos/test_sign_cmd.py | 168 +++++++++++++++++- 3 files changed, 181 insertions(+), 13 deletions(-) diff --git a/tests/speculos/boilerplate_client/boilerplate_cmd.py b/tests/speculos/boilerplate_client/boilerplate_cmd.py index 252668c..4e98c46 100644 --- a/tests/speculos/boilerplate_client/boilerplate_cmd.py +++ b/tests/speculos/boilerplate_client/boilerplate_cmd.py @@ -87,7 +87,6 @@ class BoilerplateCommand: a = self.builder.simple_sign_tx(bip32_path="44'/60'/1'/0/0", transaction=transaction) - print(a.hex()) try: response = self.client._apdu_exchange( @@ -102,7 +101,6 @@ class BoilerplateCommand: # response = V (1) || R (32) || S (32) assert len(response) == 65 - print(response.hex()) offset: int = 0 @@ -133,7 +131,6 @@ class BoilerplateCommand: # response = V (1) || R (32) || S (32) assert len(response) == 65 - print(response.hex()) offset: int = 0 diff --git a/tests/speculos/boilerplate_client/transaction.py b/tests/speculos/boilerplate_client/transaction.py index 82c3049..8660c2a 100644 --- a/tests/speculos/boilerplate_client/transaction.py +++ b/tests/speculos/boilerplate_client/transaction.py @@ -10,14 +10,15 @@ class TransactionError(Exception): class Transaction: - def __init__(self, txType: int, nonce: int, gasPrice: int, gasLimit: int, to: Union[str, bytes], value: int, memo: Union[str, bytes]) -> None: + def __init__(self, txType: int, nonce: int, gasPrice: int, gasLimit: int, to: Union[str, bytes], value: int, data: Union[str, bytes] = "", chainID: int = -1) -> None: self.txType: int = txType self.nonce: int = nonce self.gasPrice: int = gasPrice self.gasLimit: int = gasLimit self.to: bytes = bytes.fromhex(to[2:]) if isinstance(to, str) else to self.value: int = value - self.memo: bytes = bytes.fromhex(memo[2:]) if isinstance(memo, str) else memo + self.data: bytes = bytes(data, "utf-8") + self.chainID = b'' if not (0 <= self.nonce <= UINT64_MAX): raise TransactionError(f"Bad nonce: '{self.nonce}'!") @@ -28,16 +29,27 @@ class Transaction: if len(self.to) != 20: raise TransactionError(f"Bad address: '{self.to}'!") + self.lenNonce = int((len(hex(self.nonce)) - 1) / 2) self.lenGP = int((len(hex(self.gasPrice)) - 1) / 2) self.lenGL = int((len(hex(self.gasLimit)) - 1) / 2) self.lenValue = int((len(hex(self.value)) - 1) / 2) + self.lenChainID = int((len(hex(chainID)) - 1) / 2) + + if chainID != -1: + self.chainID = b"".join([ + b'' if self.lenChainID == 1 else (self.lenChainID + 0x80).to_bytes(1, byteorder="big"), + chainID.to_bytes(self.lenChainID, byteorder="big"), + write_varint(0 + 0x80), + write_varint(0 + 0x80), + ]) def serialize(self) -> bytes: return b"".join([ self.txType.to_bytes(1, byteorder="big"), - self.nonce.to_bytes(1, byteorder="big"), + b'' if self.lenNonce == 1 else write_varint(self.lenNonce + 0x80), + self.nonce.to_bytes(self.lenNonce, byteorder="big"), write_varint(self.lenGP + 0x80), self.gasPrice.to_bytes(self.lenGP, byteorder="big"), @@ -51,6 +63,9 @@ class Transaction: write_varint(self.lenValue + 0x80), self.value.to_bytes(self.lenValue, byteorder="big"), - self.memo, + write_varint(len(self.data) + 0x80), + self.data, + + self.chainID, ]) diff --git a/tests/speculos/test_sign_cmd.py b/tests/speculos/test_sign_cmd.py index 786543c..0983325 100644 --- a/tests/speculos/test_sign_cmd.py +++ b/tests/speculos/test_sign_cmd.py @@ -2,12 +2,18 @@ from urllib import response import boilerplate_client import struct +from boilerplate_client.utils import UINT64_MAX from boilerplate_client.transaction import Transaction -def test_sign(cmd): +# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md + +def test_simple_sign(cmd): result: list = [] - + + # Ether coin type + bip32_path="44'/60'/1'/0/0" + transaction = Transaction( txType=0xEB, nonce=68, @@ -15,10 +21,10 @@ def test_sign(cmd): gasLimit=0x5208, to="0x5a321744667052affa8386ed49e00ef223cbffc3", value=0x6f9c9e7bf61818, - memo="0x80018080", + chainID=1, ) - with cmd.simple_sign_tx(bip32_path="44'/60'/1'/0/0", transaction=transaction, result=result) as ex: + with cmd.simple_sign_tx(bip32_path=bip32_path, transaction=transaction, result=result) as ex: # Review transaction cmd.client.press_and_release('right') # Amount 1/3, 2/3, 3/3 @@ -36,7 +42,157 @@ def test_sign(cmd): v, r, s = result - assert v == 0x26 + assert v == 0x26 # 38 assert r.hex() == "6f389d15320f0501383526ed03de917c14212716f09a262dbc98431086a5db49" assert s.hex() == "0dc994b7b97230bb35fdf6fec2f4d8ff4cfb8bfeb2a652c364c738ff033c05dd" - \ No newline at end of file + + +def test_sign_dai_coin_type_on_network_5234(cmd): + result: list = [] + + # DAI coin type + bip32_path="44'/700'/1'/0/0" + + transaction = Transaction( + txType=0xEB, + nonce=0, + gasPrice=0x0306dc4200, + gasLimit=0x5208, + to="0x5a321744667052affa8386ed49e00ef223cbffc3", + value=0x6f9c9e7bf61818, + chainID=5243, + ) + + with cmd.simple_sign_tx(bip32_path=bip32_path, transaction=transaction, result=result) as ex: + # Review transaction + cmd.client.press_and_release('right') + # Amount 1/3, 2/3, 3/3 + cmd.client.press_and_release('right') + cmd.client.press_and_release('right') + cmd.client.press_and_release('right') + # Address 1/3, 2/3, 3/3 + cmd.client.press_and_release('right') + cmd.client.press_and_release('right') + cmd.client.press_and_release('right') + # Network 5243 + cmd.client.press_and_release('right') + # Max Fees + cmd.client.press_and_release('right') + #Accept and send + cmd.client.press_and_release('both') + + v, r, s = result + + assert v == 0x1A # 26 + assert r.hex() == "7ebfa5d5cac1e16bb1f1a8c67706b5c6019c0f198df6bb44e742a9de72330961" + assert s.hex() == "537419d8d1443d38ea87943c110789decb43b8f4fea8fae256fe842f669da634" + + +def test_sign_reject(cmd): + result: list = [] + + # Ether coin type + bip32_path="44'/60'/1'/0/0" + + transaction = Transaction( + txType=0xEB, + nonce=0, + gasPrice=0x0306dc4200, + gasLimit=0x5208, + to="0x5a321744667052affa8386ed49e00ef223cbffc3", + value=0x6f9c9e7bf61818, + chainID=1, + ) + try: + with cmd.simple_sign_tx(bip32_path=bip32_path, transaction=transaction, result=result) as ex: + # Review transaction + cmd.client.press_and_release('right') + # Amount 1/3, 2/3, 3/3 + cmd.client.press_and_release('right') + cmd.client.press_and_release('right') + cmd.client.press_and_release('right') + # Address 1/3, 2/3, 3/3 + cmd.client.press_and_release('right') + cmd.client.press_and_release('right') + cmd.client.press_and_release('right') + # Max Fees + cmd.client.press_and_release('right') + # Accept and send + cmd.client.press_and_release('right') + # Reject + cmd.client.press_and_release('both') + except boilerplate_client.exception.errors.DenyError as error: + assert error.args[0] == '0x6985' + + +def test_sign_error_transaction_type(cmd): + result: list = [] + + # Ether coin type + bip32_path="44'/60'/1'/0/0" + + # the txType is between 0x00 and 0x7F + transaction = Transaction( + txType=0x00, + nonce=0, + gasPrice=10, + gasLimit=50000, + to="0x5a321744667052affa8386ed49e00ef223cbffc3", + value=0x19, + chainID=1, + ) + + try: + with cmd.simple_sign_tx(bip32_path=bip32_path, transaction=transaction, result=result) as ex: + pass + except boilerplate_client.exception.errors.UnknownDeviceError as error: + # Throw error of transaction type not supported + assert error.args[0] == '0x6501' + + transaction.txType = 0x7F + try: + with cmd.simple_sign_tx(bip32_path=bip32_path, transaction=transaction, result=result) as ex: + pass + except boilerplate_client.exception.errors.UnknownDeviceError as error: + # Throw error of transaction type not supported + assert error.args[0] == '0x6501' + + +def test_sign_limit_nonce(cmd): + result: list = [] + + # Ether coin type + bip32_path="44'/60'/1'/0/0" + + # EIP-2681: Limit account nonce to 2^64-1 + transaction = Transaction( + txType=0xEB, + nonce=2**64-1, + gasPrice=10, + gasLimit=50000, + to="0x5a321744667052affa8386ed49e00ef223cbffc3", + value=0x08762, + chainID=1, + ) + + with cmd.simple_sign_tx(bip32_path=bip32_path, transaction=transaction, result=result) as ex: + # Review transaction + cmd.client.press_and_release('right') + # Amount 1/3, 2/3, 3/3 + cmd.client.press_and_release('right') + cmd.client.press_and_release('right') + cmd.client.press_and_release('right') + # Address 1/3, 2/3, 3/3 + cmd.client.press_and_release('right') + cmd.client.press_and_release('right') + cmd.client.press_and_release('right') + # Max Fees + cmd.client.press_and_release('right') + #Accept and send + cmd.client.press_and_release('both') + + v, r, s = result + + assert v == 0x26 # 38 + assert r.hex() == "7f17f9efa5a6065f885a44a5f5d68a62381c6b2b23047817b4569c61ccf571c6" + assert s.hex() == "4b67d37cfe473e0b2daf246fa82c7595bcff0c1515d69089037d0c061f14b3b3"