From 87eaaeeb5be18e37d9cc2b40b78784f6397d0bab Mon Sep 17 00:00:00 2001 From: Coline Date: Mon, 4 Jul 2022 10:38:32 +0200 Subject: [PATCH] feat: erc20information simple test and refacto plugin class --- .../speculos/ethereum_client/ethereum_cmd.py | 18 ++++++++--- .../ethereum_client/ethereum_cmd_builder.py | 23 ++++++++++++- tests/speculos/ethereum_client/plugin.py | 29 +++++++++++++++-- tests/speculos/test_erc1155.py | 8 ++--- tests/speculos/test_erc20information.py | 32 +++++++++++++++++++ tests/speculos/test_erc721.py | 4 +-- 6 files changed, 100 insertions(+), 14 deletions(-) create mode 100644 tests/speculos/test_erc20information.py diff --git a/tests/speculos/ethereum_client/ethereum_cmd.py b/tests/speculos/ethereum_client/ethereum_cmd.py index 50e38c0..5aa0eeb 100644 --- a/tests/speculos/ethereum_client/ethereum_cmd.py +++ b/tests/speculos/ethereum_client/ethereum_cmd.py @@ -8,7 +8,7 @@ from speculos.client import SpeculosClient, ApduException from ethereum_client.ethereum_cmd_builder import EthereumCommandBuilder, InsType from ethereum_client.exception import DeviceException from ethereum_client.transaction import PersonalTransaction, Transaction -from ethereum_client.plugin import Plugin +from ethereum_client.plugin import ERC20_Information, Plugin from ethereum_client.utils import parse_sign_response @@ -42,20 +42,30 @@ class EthereumCommand: def set_plugin(self, plugin: Plugin): try: - response = self.client._apdu_exchange( + self.client._apdu_exchange( self.builder.set_plugin(plugin=plugin) ) + except ApduException as error: raise DeviceException(error_code=error.sw, ins=InsType.INS_SET_PLUGIN) def provide_nft_information(self, plugin: Plugin): try: - response = self.client._apdu_exchange( + self.client._apdu_exchange( self.builder.provide_nft_information(plugin=plugin) ) except ApduException as error: - raise DeviceException(error_code=error.sw, ins=InsType.INS_SET_PLUGIN) + raise DeviceException(error_code=error.sw, ins=InsType.INS_PROVIDE_NFT_INFORMATION) + + def provide_erc20_token_information(self, info: ERC20_Information): + try: + self.client._apdu_exchange( + self.builder.provide_erc20_token_information(info=info) + ) + + except ApduException as error: + raise DeviceException(error_code=error.sw, ins=InsType.INS_PROVIDE_ERC20) @contextmanager diff --git a/tests/speculos/ethereum_client/ethereum_cmd_builder.py b/tests/speculos/ethereum_client/ethereum_cmd_builder.py index e0e8f0a..c5213d9 100644 --- a/tests/speculos/ethereum_client/ethereum_cmd_builder.py +++ b/tests/speculos/ethereum_client/ethereum_cmd_builder.py @@ -4,7 +4,7 @@ import struct from typing import List, Tuple, Union, Iterator, cast from ethereum_client.transaction import PersonalTransaction, Transaction -from ethereum_client.plugin import Plugin +from ethereum_client.plugin import ERC20_Information, Plugin from ethereum_client.utils import bip32_path_from_string MAX_APDU_LEN: int = 255 @@ -164,6 +164,27 @@ class EthereumCommandBuilder: p2=0x00, cdata=cdata) + def provide_erc20_token_information(self, info: ERC20_Information): + """Command builder for PROVIDE_ERC20_INFORMATION. + + Parameters + ---------- + -> Check documentation of APDU + + Returns + ------- + bytes + APDU command for PROVIDE_ERC20_INFORMATION. + + """ + + cdata: bytes = info.serialize() + + return self.serialize(cla=self.CLA, + ins=InsType.INS_PROVIDE_ERC20, + p1=0x00, + p2=0x00, + cdata=cdata) def get_public_key(self, bip32_path: str, display: bool = False) -> bytes: """Command builder for GET_PUBLIC_KEY. diff --git a/tests/speculos/ethereum_client/plugin.py b/tests/speculos/ethereum_client/plugin.py index d6bdc58..8b33cdd 100644 --- a/tests/speculos/ethereum_client/plugin.py +++ b/tests/speculos/ethereum_client/plugin.py @@ -1,6 +1,29 @@ +import string from typing import Union -from ethereum_client.utils import write_varint +from ethereum_client.utils import apdu_as_string, write_varint + +class ERC20_Information: + def __init__(self, erc20_ticker: string , addr: Union[str, bytes], nb_decimals: int, chainID: int, sign: str) -> None: + self.erc20_ticker: bytes = apdu_as_string(erc20_ticker) + self.addr: bytes = bytes.fromhex(addr[2:]) if isinstance(addr, str) else addr + self.nb_decimals: int = nb_decimals + self.chainID: int = chainID + self.sign: bytes = apdu_as_string(sign) + + def serialize(self) -> bytes: + return b"".join([ + write_varint(len(self.erc20_ticker)), + self.erc20_ticker, + + self.addr, + + self.nb_decimals.to_bytes(4, byteorder="big"), + + self.chainID.to_bytes(4, byteorder="big"), + + self.sign, + ]) class Plugin: """Plugin class @@ -11,7 +34,7 @@ class Plugin: do not define a selector """ - def __init__(self, type: int, version: int, name: str, addr: Union[str, bytes], selector: int = -1, chainID: int = 1, keyID: int = 0, algorithm: int = 1, sign: bytes = b'') -> None: + def __init__(self, type: int, version: int, name: str, addr: Union[str, bytes], selector: int = -1, chainID: int = 1, keyID: int = 0, algorithm: int = 1, sign: str = "") -> None: self.type: int = type self.version: int = version self.name: bytes = bytes(name, 'UTF-8') @@ -20,7 +43,7 @@ class Plugin: self.chainID: int = chainID self.keyID: int = keyID self.algorithm: int = algorithm - self.sign: bytes = sign + self.sign: bytes = apdu_as_string(sign) def serialize(self) -> bytes: return b"".join([ diff --git a/tests/speculos/test_erc1155.py b/tests/speculos/test_erc1155.py index 44463a5..c2d634b 100644 --- a/tests/speculos/test_erc1155.py +++ b/tests/speculos/test_erc1155.py @@ -16,7 +16,7 @@ PLUGIN = Plugin( chainID=1, keyID=0, algorithm=1, - sign=b"\x30\x45\x02\x21\x00\xec\x43\x77\xd1\x7e\x8d\x98\xd4\x24\xbf\x16\xb2\x9c\x69\x1b\xc1\xa0\x10\x82\x5f\xb5\xb8\xa3\x5d\xe0\x26\x8a\x9d\xc2\x2e\xab\x24\x02\x20\x67\x01\xb0\x16\xfe\x67\x18\xbf\x51\x9d\x18\xcc\x12\xe9\x83\x8e\x9e\xf8\x98\xcc\x4c\x14\x30\x17\x83\x90\x23\xc3\x26\x0b\x2d\x74", + sign="3045022100ec4377d17e8d98d424bf16b29c691bc1a010825fb5b8a35de0268a9dc22eab2402206701b016fe6718bf519d18cc12e9838e9ef898cc4c143017839023c3260b2d74", ) PROVIDE_NFT_INFORMATION = Plugin( @@ -27,7 +27,7 @@ PROVIDE_NFT_INFORMATION = Plugin( chainID=1, keyID=0, algorithm=1, - sign=b"\x30\x45\x02\x21\x00\x83\xe3\x57\xa8\x28\xf1\x3d\x57\x4b\x12\x96\x21\x4a\x37\x49\xc1\x94\xab\x1d\xf1\xf8\xa2\x43\x65\x5c\x05\x3b\x1c\x72\xf9\x1e\x0c\x02\x20\x1e\xd9\x3c\xfa\xc7\xe8\x77\x59\x44\x5c\x4d\xa2\xe4\xbf\xd6\xe1\xcf\x04\x05\xea\x37\xc7\x29\x3b\xc9\x65\x94\x8f\x51\xbe\xf5\xcc", + sign="304502210083e357a828f13d574b1296214a3749c194ab1df1f8a243655c053b1c72f91e0c02201ed93cfac7e87759445c4da2e4bfd6e1cf0405ea37c7293bc965948f51bef5cc", ) def test_transfer_erc1155(cmd): @@ -139,7 +139,7 @@ PLUGIN_BATCH = Plugin( chainID=1, keyID=0, algorithm=1, - sign=b"\x30\x45\x02\x21\x00\x87\xb3\x5c\xef\xc5\x3f\xd9\x4e\x25\x40\x49\x33\xeb\x0d\x5f\xf0\x8f\x20\xba\x65\x5d\x18\x1d\xe3\xb2\x4f\xf0\x09\x9d\xc3\x31\x7f\x02\x20\x4a\x21\x6a\xa9\xe0\xb8\x4b\xef\x6e\x20\xfc\xb0\x36\xbd\x49\x64\x7b\xf0\xca\xb6\x67\x32\xb9\x9b\x49\xec\x27\x7f\xfb\x68\x2a\xa1", + sign="304502210087b35cefc53fd94e25404933eb0d5ff08f20ba655d181de3b24ff0099dc3317f02204a216aa9e0b84bef6e20fcb036bd49647bf0cab66732b99b49ec277ffb682aa1", ) PROVIDE_NFT_INFORMATION_BATCH = Plugin( @@ -150,7 +150,7 @@ PROVIDE_NFT_INFORMATION_BATCH = Plugin( chainID=1, keyID=0, algorithm=1, - sign=b"\x30\x45\x02\x21\x00\xc7\x4c\xd6\x13\xa2\x7a\x9f\x48\x87\x21\x0f\x5a\x3a\x0e\x12\x74\x5e\x1b\xa0\xab\x3a\x0d\x28\x4c\xb6\x48\x5d\x89\xc3\xcc\xe4\xe6\x02\x20\x5a\x13\xe6\x2a\x91\x16\x49\x85\xcf\x58\xa8\x38\xf8\xf5\x31\xc0\xb9\x1b\x98\x0d\x20\x6a\x5b\xa8\xdf\x28\x27\x00\x23\xef\x93\xa3", + sign="3045022100c74cd613a27a9f4887210f5a3a0e12745e1ba0ab3a0d284cb6485d89c3cce4e602205a13e62a91164985cf58a838f8f531c0b91b980d206a5ba8df28270023ef93a3", ) def test_transfer_batch_erc1155(cmd): diff --git a/tests/speculos/test_erc20information.py b/tests/speculos/test_erc20information.py new file mode 100644 index 0000000..60f411b --- /dev/null +++ b/tests/speculos/test_erc20information.py @@ -0,0 +1,32 @@ +from ethereum_client.plugin import ERC20_Information +import ethereum_client + +def test_provide_erc20_token(cmd): + erc20_info = ERC20_Information( + erc20_ticker="5a5258", + addr="0xe41d2489571d322189246dafa5ebde1f4699f498", + nb_decimals=18, + chainID=1, + sign="304402200ae8634c22762a8ba41d2acb1e068dcce947337c6dd984f13b820d396176952302203306a49d8a6c35b11a61088e1570b3928ca3a0db6bd36f577b5ef87628561ff7" + ) + + # Test if return 9000 + try: + cmd.provide_erc20_token_information(info=erc20_info) + except: + raise + +def test_provide_erc20_token_error(cmd): + erc20_info = ERC20_Information( + erc20_ticker="5a5258", + addr="0xe41d2489571d322189246dafa5ebde1f4699f498", + nb_decimals=18, + chainID=1, + sign="deadbeef" + ) + + # Test if return 9000 + try: + cmd.provide_erc20_token_information(info=erc20_info) + except ethereum_client.exception.errors.UnknownDeviceError as error: + assert error.args[0] == '0x6a80' \ No newline at end of file diff --git a/tests/speculos/test_erc721.py b/tests/speculos/test_erc721.py index f2ac564..c542b89 100644 --- a/tests/speculos/test_erc721.py +++ b/tests/speculos/test_erc721.py @@ -16,7 +16,7 @@ PLUGIN = Plugin( chainID=1, keyID=0, algorithm=1, - sign=b"\x30\x45\x02\x20\x2e\x22\x82\xd7\xd3\xea\x71\x4d\xa2\x83\x01\x0f\x51\x7a\xf4\x69\xe1\xd5\x96\x54\xaa\xee\x0f\xc4\x38\xf0\x17\xaa\x55\x7e\xae\xa5\x02\x21\x00\x8b\x36\x96\x79\x38\x10\x65\xbb\xe0\x11\x35\x72\x3a\x4f\x9a\xdb\x22\x92\x95\x01\x7d\x37\xc4\xd3\x01\x38\xb9\x0a\x51\xcf\x6a\xb6", + sign="304502202e2282d7d3ea714da283010f517af469e1d59654aaee0fc438f017aa557eaea50221008b369679381065bbe01135723a4f9adb229295017d37c4d30138b90a51cf6ab6", ) PROVIDE_NFT_INFORMATION = Plugin( @@ -27,7 +27,7 @@ PROVIDE_NFT_INFORMATION = Plugin( chainID=1, keyID=0, algorithm=1, - sign=b"\x30\x45\x02\x20\x25\x69\x69\x86\xef\x5f\x0e\xe2\xf7\x2d\x9c\x6e\x41\xd7\xe2\xbf\x2e\x4f\x06\x37\x3a\xb2\x6d\x73\xeb\xe3\x26\xc7\xfd\x4c\x7a\x66\x02\x21\x00\x84\xf6\xb0\x64\xd8\x75\x0a\xe6\x8e\xd5\xdd\x01\x22\x96\xf3\x70\x30\x39\x0e\xc0\x6f\xf5\x34\xc5\xda\x6f\x0f\x4a\x44\x60\xaf\x33", + sign="3045022025696986ef5f0ee2f72d9c6e41d7e2bf2e4f06373ab26d73ebe326c7fd4c7a6602210084f6b064d8750ae68ed5dd012296f37030390ec06ff534c5da6f0f4a4460af33", ) def test_transfer_erc721(cmd):