diff --git a/tests/application_client/boilerplate_command_sender.py b/tests/application_client/boilerplate_command_sender.py index 46c4315f..ce4456f9 100644 --- a/tests/application_client/boilerplate_command_sender.py +++ b/tests/application_client/boilerplate_command_sender.py @@ -51,6 +51,10 @@ class P1(IntEnum): # Parameter 1 for deploy module P1_DEPLOY_MODULE_INITIAL = 0x00 P1_DEPLOY_MODULE_SOURCE = 0x01 + # Parameter 1 for init contract + P1_INIT_CONTRACT_INITIAL = 0x00 + P1_INIT_CONTRACT_NAME = 0x01 + P1_INIT_CONTRACT_PARAMS = 0x02 class P2(IntEnum): @@ -83,6 +87,7 @@ class InsType(IntEnum): CREDENTIAL_DEPLOYMENT = 0x04 EXPORT_PRIVATE_KEY = 0x05 DEPLOY_MODULE = 0x06 + INIT_CONTRACT = 0x07 ENCRYPTED_AMOUNT_TRANSFER = 0x10 TRANSFER_TO_ENCRYPTED = 0x11 TRANSFER_TO_PUBLIC = 0x12 @@ -791,5 +796,67 @@ def deploy_module( ) as response: yield response + @contextmanager + def init_contract( + self, + path: str, + header_and_type: bytes, + amount: int, + module_ref: bytes, + name: bytes, + params: bytes, + ) -> Generator[None, None, None]: + if amount > 0xFFFFFFFFFFFFFFFF: + raise ValueError("Amount must be less than 18446744073709551615") + # Send the initial data + data = pack_derivation_path(path) + data += header_and_type + data += amount.to_bytes(8, byteorder="big") + data += module_ref + temp_response = self.backend.exchange( + cla=CLA, + ins=InsType.INIT_CONTRACT, + p1=P1.P1_INIT_CONTRACT_INITIAL, + p2=P2.P2_NONE, + data=data, + ) + if temp_response.status != 0x9000: + raise ExceptionRAPDU(temp_response.status) + # Send the name + data = len(name).to_bytes(2, byteorder="big") + name_chunks = split_message(name, MAX_APDU_LEN) + for chunk in name_chunks: + temp_response = self.backend.exchange( + cla=CLA, + ins=InsType.INIT_CONTRACT, + p1=P1.P1_INIT_CONTRACT_NAME, + p2=P2.P2_NONE, + data=chunk, + ) + if temp_response.status != 0x9000: + raise ExceptionRAPDU(temp_response.status) + # Send the params + data = len(params).to_bytes(2, byteorder="big") + params_chunks = split_message(params, MAX_APDU_LEN) + last_chunk = params_chunks.pop() + for chunk in params_chunks: + temp_response = self.backend.exchange( + cla=CLA, + ins=InsType.INIT_CONTRACT, + p1=P1.P1_INIT_CONTRACT_PARAMS, + p2=P2.P2_NONE, + data=chunk, + ) + if temp_response.status != 0x9000: + raise ExceptionRAPDU(temp_response.status) + with self.backend.exchange_async( + cla=CLA, + ins=InsType.INIT_CONTRACT, + p1=P1.P1_INIT_CONTRACT_PARAMS, + p2=P2.P2_NONE, + data=last_chunk, + ) as response: + yield response + def get_async_response(self) -> Optional[RAPDU]: return self.backend.last_async_response diff --git a/tests/test_init_contract.py b/tests/test_init_contract.py new file mode 100644 index 00000000..6e90df38 --- /dev/null +++ b/tests/test_init_contract.py @@ -0,0 +1,47 @@ +import pytest + +from application_client.boilerplate_command_sender import ( + BoilerplateCommandSender, + Errors, +) +from application_client.boilerplate_response_unpacker import ( + unpack_get_public_key_response, +) +from ragger.bip import calculate_public_key_and_chaincode, CurveChoice +from ragger.error import ExceptionRAPDU +from ragger.navigator import NavInsID, NavIns +from ragger.firmware import Firmware +from utils import navigate_until_text_and_compare, instructions_builder + + +@pytest.mark.active_test_scope +def test_init_contract( + backend, firmware, navigator, test_name, default_screenshot_path +): + client = BoilerplateCommandSender(backend) + path = "m/1105/0/0/0/0/2/0/0" + header_and_type = bytes.fromhex( + "20a845815bd43a1999e90fbf971537a70392eb38f89e6bd32b3dd70e1a9551d7000000000000000a0000000000000064000000290000000063de5da701" + ) + amount = 1000000000000000000 + module_ref = bytes.fromhex( + "a00000000000000000000000000000000000000000000000000000000000000a" + ) + name = bytes.fromhex("696e69745f5465737420436f6e7472616374") + params = bytes.fromhex("0102030405060708090a") + + with client.init_contract( + path=path, + header_and_type=header_and_type, + amount=amount, + module_ref=module_ref, + name=name, + params=params, + ): + navigate_until_text_and_compare( + firmware, navigator, "Sign", default_screenshot_path, test_name + ) + response = client.get_async_response() + print(response.data.hex()) + assert response.status == 0x9000 + assert response.data == bytes.fromhex("Enter valid signature here")