From 7ef2c59e74843ba3bf3a98814f8cb94c5f1b867d Mon Sep 17 00:00:00 2001 From: Charles-Edouard de la Vergne Date: Fri, 8 Nov 2024 18:30:09 +0100 Subject: [PATCH] Initial cardano tests implementation --- test/python/apps/cal.py | 2 + test/python/apps/cardano.py | 89 +++++++++++++++++++++++++++++++++++++ test/python/conftest.py | 1 + test/python/test_cardano.py | 41 +++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 test/python/apps/cardano.py create mode 100644 test/python/test_cardano.py diff --git a/test/python/apps/cal.py b/test/python/apps/cal.py index f057f10d..c0b5b595 100644 --- a/test/python/apps/cal.py +++ b/test/python/apps/cal.py @@ -21,6 +21,7 @@ from .ton import TON_PACKED_DERIVATION_PATH, TON_CONF from .tron import TRX_PACKED_DERIVATION_PATH, TRX_CONF from .tron import TRX_USDT_CONF, TRX_USDC_CONF, TRX_TUSD_CONF, TRX_USDD_CONF +from .cardano import ADA_PACKED_DERIVATION_PATH, ADA_CONF @dataclass class CurrencyConfiguration: @@ -54,6 +55,7 @@ def get_conf_for_ticker(self, overload_signer: Optional[SigningAuthority]=None) USDC_CURRENCY_CONFIGURATION = CurrencyConfiguration(ticker="USDC", conf=TRX_USDC_CONF, packed_derivation_path=TRX_PACKED_DERIVATION_PATH) TUSD_CURRENCY_CONFIGURATION = CurrencyConfiguration(ticker="TUSD", conf=TRX_TUSD_CONF, packed_derivation_path=TRX_PACKED_DERIVATION_PATH) USDD_CURRENCY_CONFIGURATION = CurrencyConfiguration(ticker="USDD", conf=TRX_USDD_CONF, packed_derivation_path=TRX_PACKED_DERIVATION_PATH) +ADA_CURRENCY_CONFIGURATION = CurrencyConfiguration(ticker="ADA", conf=ADA_CONF, packed_derivation_path=ADA_PACKED_DERIVATION_PATH) # Helper that can be called from outside if we want to generate errors easily diff --git a/test/python/apps/cardano.py b/test/python/apps/cardano.py new file mode 100644 index 00000000..2b293946 --- /dev/null +++ b/test/python/apps/cardano.py @@ -0,0 +1,89 @@ +from enum import IntEnum + +from ragger.backend.interface import BackendInterface, RAPDU +from ragger.bip import pack_derivation_path +from ragger.utils import create_currency_config + +ADA_CONF = create_currency_config("ADA", "Cardano ADA") + +ADA_BYRON_DERIVATION_PATH = "m/44'/1815'/0'/0/0'" +ADA_SHELLEY_DERIVATION_PATH = "m/1852'/1815'/0'/0/0'" +ADA_PACKED_DERIVATION_PATH = pack_derivation_path(ADA_SHELLEY_DERIVATION_PATH) + + + + +class Ins(IntEnum): + GET_PUBLIC_ADDR = 0x10 + DERIVE_PUBLIC_ADDR = 0x11 + SIGN_TX = 0x21 + + +class P1(IntEnum): + UNUSED = 0x00 + + +class P2(IntEnum): + UNUSED = 0x00 + + +class Errors(IntEnum): + SW_AUTORESPOND_START = 0x6E00 + SW_MALFORMED_REQUEST_HEADER = 0x6E01 + SW_BAD_CLA = 0x6E02 + SW_UNKNOWN_INS = 0x6E03 + SW_STILL_IN_CALL = 0x6E04 + SW_INVALID_REQUEST_PARAMETERS = 0x6E05 + SW_INVALID_STATE = 0x6E06 + SW_INVALID_DATA = 0x6E07 + SW_REJECTED_BY_USER = 0x6E09 + SW_REJECTED_BY_POLICY = 0x6E10 + SW_DEVICE_LOCKED = 0x6E11 + SW_SWAP_CHECKING_FAIL = 0x6E13 + SW_SUCCESS = 0x9000 + + +class CardanoClient: + CLA = 0xD7 + + def __init__(self, backend: BackendInterface): + self._backend = backend + + def send_simple_sign_tx(self, path: str, destination: str, send_amount: int) -> RAPDU: + packed_path = pack_derivation_path(path) + + + # response = self._backend.exchange(self.CLA, Ins.GET_PUBLIC_ADDR, P1.UNUSED, P2.UNUSED, packed_path) + # assert response.sw == Errors.SW_SUCCESS + # pubkey = response.data + + # print(f"{'*'*30}\n Received public key: {pubkey.hex()}\n{'*'*30}") + + signTx = { + "signTxInit": "d72101003c0000000000000000012d964a090201010101010101010103000000010000000100000000000000000000000000000000000000000000000000000001", + "signTxInputs": "d7210200241af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc00000000", + "signTxOutputBasic": "d72103303f00010000002b82d818582183581c9e1c71de652ec8b85fec296f0685ca3988781c94a2e1a5d89d92f45fa0001a0d0c256100000000002dd2e8000000000101", + "signTxOutputConfirm": "d721033300", + "signTxFees": "d721040008000000000000002a", + "signTxTtl": "d721050008000000000000000a", + "signTxConfirm": "d7210a0000", + "signTxWitness": "d7210f0015058000002c80000717800000000000000000000000", + } + + for _, value in signTx.items(): + response = self._backend.exchange_raw(bytes.fromhex(value)) + assert response.status == Errors.SW_SUCCESS + + + # tx = Transaction( + # signer_id="blablatest.testnet", + # public_key=PUBLIC_KEY.to_bytes(), + # nonce=NONCE, + # receiver_id=destination, + # actions=[create_transfer_action(send_amount * 10**24)], + # block_hash=BLOCK_HASH + # ) + + # serialized_tx = bytes(tx.to_vec(PRIVATE_KEY.to_bytes())) + + # return self._backend.exchange(self.CLA, Ins.SIGN, P1.MORE, P2.UNUSED, packed_path[1:] + serialized_tx) diff --git a/test/python/conftest.py b/test/python/conftest.py index 233cb6f4..4de3b8ed 100644 --- a/test/python/conftest.py +++ b/test/python/conftest.py @@ -26,6 +26,7 @@ "DOT": "Polkadot", "tron": "Tron", "ton": "TON", + "cardano": "Cardano ADA", } configuration.OPTIONAL.SIDELOADED_APPS_DIR = "test/python/lib_binaries/" diff --git a/test/python/test_cardano.py b/test/python/test_cardano.py new file mode 100644 index 00000000..ad8db931 --- /dev/null +++ b/test/python/test_cardano.py @@ -0,0 +1,41 @@ +import pytest + +from .apps.exchange_test_runner import ExchangeTestRunner, ALL_TESTS_EXCEPT_MEMO_AND_FEES +from .apps.cardano import CardanoClient, Errors +from .apps.cardano import ADA_BYRON_DERIVATION_PATH, ADA_SHELLEY_DERIVATION_PATH +from .apps import cal as cal + +# ExchangeTestRunner implementation for Cardano +class CardanoClientTests(ExchangeTestRunner): + + currency_configuration = cal.ADA_CURRENCY_CONFIGURATION + valid_destination_1 = "speculos.testnet" + valid_destination_memo_1 = "" + valid_destination_2 = "speculo.testnet" + valid_destination_memo_2 = "" + valid_refund = "EFr6nRvgKKeteKoEH7hudt8UHYiu94Liq2yMM7x2AU9U" + valid_refund_memo = "" + valid_send_amount_1 = 1 + valid_send_amount_2 = 446739662 + valid_fees_1 = 0 + valid_fees_2 = 0 + fake_refund = "abcdabcd" + fake_refund_memo = "bla" + fake_payout = "abcdabcd" + fake_payout_memo = "bla" + signature_refusal_error_code = Errors.SW_SWAP_CHECKING_FAIL + + def perform_final_tx(self, destination, send_amount, fees, memo): + CardanoClient(self.backend).send_simple_sign_tx(path=ADA_BYRON_DERIVATION_PATH, + destination=destination, + send_amount=send_amount) + + # TODO : assert signature validity + + +# Use a class to reuse the same Speculos instance +class TestsCardanoClient: + + @pytest.mark.parametrize('test_to_run', ALL_TESTS_EXCEPT_MEMO_AND_FEES) + def test_cardano(self, backend, exchange_navigation_helper, test_to_run): + CardanoClientTests(backend, exchange_navigation_helper).run_test(test_to_run) \ No newline at end of file