From 2262602967748e54b8aff97e9f0b6b1d6a703391 Mon Sep 17 00:00:00 2001 From: David Misiak Date: Thu, 21 Oct 2021 19:43:10 +0200 Subject: [PATCH] feat(cardano): add support for plutus transactions --- common/protob/messages-cardano.proto | 23 + common/protob/messages.proto | 2 + .../fixtures/cardano/sign_tx.failed.json | 200 +++++ common/tests/fixtures/cardano/sign_tx.json | 64 ++ .../cardano/sign_tx.multisig.failed.json | 103 +++ .../fixtures/cardano/sign_tx.multisig.json | 33 +- .../cardano/sign_tx.plutus.failed.json | 136 +++ .../fixtures/cardano/sign_tx.plutus.json | 788 ++++++++++++++++++ .../fixtures/cardano/sign_tx.slip39.json | 6 + ...ign_tx_stake_pool_registration.failed.json | 315 +++++++ .../sign_tx_stake_pool_registration.json | 12 + core/src/apps/cardano/README.md | 42 +- core/src/apps/cardano/certificates.py | 8 +- core/src/apps/cardano/helpers/__init__.py | 2 + core/src/apps/cardano/helpers/bech32.py | 1 + core/src/apps/cardano/helpers/utils.py | 9 +- core/src/apps/cardano/layout.py | 103 ++- core/src/apps/cardano/sign_tx.py | 175 +++- core/src/trezor/enums/CardanoTxSigningMode.py | 1 + core/src/trezor/enums/MessageType.py | 2 + core/src/trezor/enums/__init__.py | 3 + core/src/trezor/messages.py | 36 + core/tests/test_apps.cardano.certificate.py | 30 + python/src/trezorlib/cardano.py | 77 +- python/src/trezorlib/cli/cardano.py | 10 + python/src/trezorlib/messages.py | 43 + tests/device_tests/cardano/test_sign_tx.py | 20 +- 27 files changed, 2176 insertions(+), 68 deletions(-) create mode 100644 common/tests/fixtures/cardano/sign_tx.plutus.failed.json create mode 100644 common/tests/fixtures/cardano/sign_tx.plutus.json diff --git a/common/protob/messages-cardano.proto b/common/protob/messages-cardano.proto index f7e5c6496d..8409bb3611 100644 --- a/common/protob/messages-cardano.proto +++ b/common/protob/messages-cardano.proto @@ -68,6 +68,7 @@ enum CardanoTxSigningMode { ORDINARY_TRANSACTION = 0; POOL_REGISTRATION_AS_OWNER = 1; MULTISIG_TRANSACTION = 2; + PLUTUS_TRANSACTION = 3; } enum CardanoTxWitnessType { @@ -207,6 +208,8 @@ message CardanoSignTxInit { required CardanoDerivationType derivation_type = 14; optional bool include_network_id = 15 [default=false]; // network id included as tx body item optional bytes script_data_hash = 16; + required uint32 collateral_inputs_count = 17; + required uint32 required_signers_count = 18; } /** @@ -348,6 +351,24 @@ message CardanoTxMint { required uint32 asset_groups_count = 1; } +/** + * Request: Transaction collateral input data + * @next CardanoTxItemAck + */ +message CardanoTxCollateralInput { + required bytes prev_hash = 1; + required uint32 prev_index = 2; +} + +/** + * Request: Transaction required signer + * @next CardanoTxItemAck + */ +message CardanoTxRequiredSigner { + optional bytes key_hash = 1; + repeated uint32 key_path = 2; +} + /** * Response: Acknowledgement of the last transaction item received * @next CardanoTxInput @@ -361,6 +382,8 @@ message CardanoTxMint { * @next CardanoTxAuxiliaryData * @next CardanoTxWitnessRequest * @next CardanoTxMint + * @next CardanoTxCollateralInput + * @next CardanoTxRequiredSigner */ message CardanoTxItemAck { } diff --git a/common/protob/messages.proto b/common/protob/messages.proto index d8d4583a01..218c574cf5 100644 --- a/common/protob/messages.proto +++ b/common/protob/messages.proto @@ -278,6 +278,8 @@ enum MessageType { MessageType_CardanoGetNativeScriptHash = 330 [(wire_in) = true]; MessageType_CardanoNativeScriptHash = 331 [(wire_out) = true]; MessageType_CardanoTxMint = 332 [(wire_in) = true]; + MessageType_CardanoTxCollateralInput = 333 [(wire_in) = true]; + MessageType_CardanoTxRequiredSigner = 334 [(wire_in) = true]; // Ripple MessageType_RippleGetAddress = 400 [(wire_in) = true]; diff --git a/common/tests/fixtures/cardano/sign_tx.failed.json b/common/tests/fixtures/cardano/sign_tx.failed.json index f7dfd8b16c..054bf8b3e0 100644 --- a/common/tests/fixtures/cardano/sign_tx.failed.json +++ b/common/tests/fixtures/cardano/sign_tx.failed.json @@ -29,6 +29,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -62,6 +64,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -95,6 +99,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -128,6 +134,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -161,6 +169,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -194,6 +204,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -227,6 +239,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -265,6 +279,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -298,6 +314,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -331,6 +349,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -364,6 +384,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -397,6 +419,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -430,6 +454,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -463,6 +489,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -496,6 +524,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -532,6 +562,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -570,6 +602,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -608,6 +642,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -646,6 +682,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -685,6 +723,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -724,6 +764,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -762,6 +804,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -800,6 +844,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -838,6 +884,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -876,6 +924,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -915,6 +965,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -950,6 +1002,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -993,6 +1047,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1038,6 +1094,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1072,6 +1130,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1106,6 +1166,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1142,6 +1204,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1175,6 +1239,8 @@ ], "mint": [], "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f", + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1183,6 +1249,86 @@ "error_message": "Invalid script data hash" } }, + { + "description": "Collateral input is present", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "3003112" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "required_signers": [], + "signing_mode": "ORDINARY_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "error_message": "Invalid tx signing request" + } + }, + { + "description": "Required signer is present", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "3003112" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [ + { + "key_hash": "3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c490711" + } + ], + "signing_mode": "ORDINARY_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "error_message": "Invalid tx signing request" + } + }, { "description": "Change output path larger than 100", "parameters": { @@ -1214,6 +1360,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1253,6 +1401,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1292,6 +1442,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1325,6 +1477,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1363,6 +1517,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1411,6 +1567,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1464,6 +1622,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1511,6 +1671,8 @@ } ], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1563,6 +1725,8 @@ } ], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1615,6 +1779,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1677,6 +1843,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1728,6 +1896,8 @@ } ], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1789,6 +1959,8 @@ } ], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1822,6 +1994,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [ { @@ -1859,6 +2033,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [ { @@ -1898,6 +2074,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1979,6 +2157,8 @@ } ], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [ { @@ -2017,6 +2197,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [ { @@ -2106,6 +2288,8 @@ } ], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [ { @@ -2149,6 +2333,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -2187,6 +2373,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -2225,6 +2413,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -2269,6 +2459,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -2313,6 +2505,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -2356,6 +2550,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -2393,6 +2589,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -2427,6 +2625,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false diff --git a/common/tests/fixtures/cardano/sign_tx.json b/common/tests/fixtures/cardano/sign_tx.json index 2291dcf573..8a5753d391 100644 --- a/common/tests/fixtures/cardano/sign_tx.json +++ b/common/tests/fixtures/cardano/sign_tx.json @@ -29,6 +29,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -75,6 +77,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -122,6 +126,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -178,6 +184,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -243,6 +251,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -291,6 +301,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -339,6 +351,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -386,6 +400,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -435,6 +451,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -481,6 +499,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -527,6 +547,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -568,6 +590,8 @@ "outputs": [], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -619,6 +643,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -671,6 +697,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -728,6 +756,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -781,6 +811,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -830,6 +862,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -882,6 +916,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -937,6 +973,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -996,6 +1034,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1068,6 +1108,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1110,6 +1152,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1161,6 +1205,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1214,6 +1260,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1262,6 +1310,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1401,6 +1451,8 @@ }, "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1517,6 +1569,8 @@ } ], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [ { @@ -1568,6 +1622,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": true @@ -1610,6 +1666,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1651,6 +1709,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1692,6 +1752,8 @@ ], "mint": [], "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -1830,6 +1892,8 @@ } ], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false diff --git a/common/tests/fixtures/cardano/sign_tx.multisig.failed.json b/common/tests/fixtures/cardano/sign_tx.multisig.failed.json index 2ef944e56d..c43d2a22d0 100644 --- a/common/tests/fixtures/cardano/sign_tx.multisig.failed.json +++ b/common/tests/fixtures/cardano/sign_tx.multisig.failed.json @@ -33,6 +33,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -74,6 +76,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -119,6 +123,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -168,6 +174,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -209,6 +217,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -241,6 +251,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -279,6 +291,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -315,6 +329,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -403,6 +419,8 @@ } ], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -414,6 +432,91 @@ "result": { "error_message": "Invalid witness request" } + }, + { + "description": "Multisig transaction with a collateral input", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1w9rhu54nz94k9l5v6d9rzfs47h7dv7xffcwkekuxcx3evnqpvuxu0", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [ + { + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "required_signers": [], + "signing_mode": "MULTISIG_TRANSACTION", + "additional_witness_requests": [ + { + "path": "m/1854'/1815'/0'/0/0" + } + ], + "include_network_id": false + }, + "result": { + "error_message": "Invalid tx signing request" + } + }, + { + "description": "Multisig transaction with a required signer", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1w9rhu54nz94k9l5v6d9rzfs47h7dv7xffcwkekuxcx3evnqpvuxu0", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [ + { + "key_hash": "3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c490711" + } + ], + "signing_mode": "MULTISIG_TRANSACTION", + "additional_witness_requests": [ + { + "path": "m/1854'/1815'/0'/0/0" + } + ], + "include_network_id": false + }, + "result": { + "error_message": "Invalid tx signing request" + } } ] } diff --git a/common/tests/fixtures/cardano/sign_tx.multisig.json b/common/tests/fixtures/cardano/sign_tx.multisig.json index e0f16a6c92..0bd06e6e59 100644 --- a/common/tests/fixtures/cardano/sign_tx.multisig.json +++ b/common/tests/fixtures/cardano/sign_tx.multisig.json @@ -80,6 +80,8 @@ } ], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -138,6 +140,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -192,6 +196,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -250,6 +256,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -313,6 +321,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -395,6 +405,11 @@ ] } ] + }, + { + "address": "addr1w9rhu54nz94k9l5v6d9rzfs47h7dv7xffcwkekuxcx3evnqpvuxu0", + "amount": "1", + "datum_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7" } ], "mint": [ @@ -412,7 +427,9 @@ ] } ], - "script_data_hash": null, + "script_data_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -425,27 +442,27 @@ "path": "m/1855'/1815'/0'" } ], - "include_network_id": false + "include_network_id": true }, "result": { - "tx_hash": "2be64c04ea3f5bac3c224ec47a4157ade91fc6ab4fd6b83ce3d57b2e9186720b", + "tx_hash": "c3637e34529fae17dbbb90c58307df0cf3b818f4c034860fff362d1ea864cca4", "witnesses": [ { "type": 1, "pub_key": "b10be5c0d11ad8292bbe69e220ca0cfbe154610b3041a8e72f9d515c226ab3b1", - "signature": "38a56a46b21caef91742ffafdec202ed96809c3070c9bfd51db5c750d77edbfb8514d9cd2255ab5a857dd8a63706ae0ca29e390fba6af7a906b186aed117b809", + "signature": "58bc9f1c39f2cd4248ad79a5f6a4733a6e751e86b09163e468b92ec1079590f6052f30f9a782812ba1b553f1c5f22cad807af97494cf8a0a26bf123bc2f60202", "chain_code": null }, { "type": 1, "pub_key": "f2ef4ecd21ad28a8d270ca7be7e96c87f60dc821e13c0d0c5870344e9693637c", - "signature": "0c9071c421fe207ac1d9102643eac8ddf5ff29238782956b5706b9f1f084dfc5c087b4ceda6d079f8bb6438d3b556d3ac97565a87a8ec33f11856408b0480400", + "signature": "8b3e5b1b013d7456c1b0d67a334af725e3e1d3ea9a4a8ff05889314691f797cb49fff2cc10764133bce154db5e0eb91e4c1982cf53e6578648cf1f251f37020a", "chain_code": null }, { "type": 1, "pub_key": "b75258e4f61eb7b313d8554c2fe10673cf214ca2d762bfd53ec3b7846e2ee872", - "signature": "85bf1bc71c04c72ae8184885b9d5eadd49b2c27bd332a42bc42c35b49429509350795bbdb716a95946b7c30cb62f20e1d39e4be3df5625a141f3e3c2e3526e02", + "signature": "cb3daca29e217a9f0c7e5ad47b0d07827ce8937d252ba6e32415f4613e8e6675e1b3964d28b354d338bae623bba1c30bf47a37818b56602a6e7ba7ff081aa605", "chain_code": null } ] @@ -476,6 +493,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { @@ -520,6 +539,8 @@ ], "mint": [], "script_data_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [ { diff --git a/common/tests/fixtures/cardano/sign_tx.plutus.failed.json b/common/tests/fixtures/cardano/sign_tx.plutus.failed.json new file mode 100644 index 0000000000..df42a175f5 --- /dev/null +++ b/common/tests/fixtures/cardano/sign_tx.plutus.failed.json @@ -0,0 +1,136 @@ +{ + "setup": { + "mnemonic": "all all all all all all all all all all all all", + "passphrase": "" + }, + "tests": [ + { + "description": "Collateral input prev hash has incorrect length", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "Ae2tdPwUPEZCanmBz5g2GEwFqKTKpNJcGYPKfDxoNeKZ8bRHr8366kseiK2", + "amount": "3003112" + } + ], + "mint": [], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c338421016", + "prev_index": 0 + } + ], + "required_signers": [], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "error_message": "Invalid collateral input" + } + }, + { + "description": "Plutus transaction with output containing address parameters", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "addressType": 0, + "path": "m/1852'/1815'/0'/0/0", + "stakingPath": "m/1852'/1815'/0'/2/0", + "amount": "7120787" + } + ], + "mint": [], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "error_message": "Invalid output" + } + }, + { + "description": "Required signer with both key path and key hash", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [ + { + "key_path": "m/1852'/1815'/0'/0/1", + "key_hash": "3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c490711" + } + ], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "error_message": "Invalid required signer" + } + } + ] + } diff --git a/common/tests/fixtures/cardano/sign_tx.plutus.json b/common/tests/fixtures/cardano/sign_tx.plutus.json new file mode 100644 index 0000000000..ced8565a02 --- /dev/null +++ b/common/tests/fixtures/cardano/sign_tx.plutus.json @@ -0,0 +1,788 @@ +{ + "setup": { + "mnemonic": "all all all all all all all all all all all all", + "passphrase": "" + }, + "tests": [ + { + "description": "Simple Plutus transaction", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "tx_hash": "598dc85bc03cc682ee7ce8b4db798d836a0840429cae7fc62fe388e727a669a2", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "7b347ee79f28881cc13f233035e1641981e766f8abf3e8dd826dd0ab7cd56d3e4ada1d935dbbb04947642397be5daca9b8ad214d3383744eeb421b30cb5ab804", + "chain_code": null + } + ] + } + }, + { + "description": "Simple Plutus transaction with required signers", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [ + { + "key_path": "m/1852'/1815'/0'/0/1" + }, + { + "key_path": "m/1854'/1815'/0'/0/0" + }, + { + "key_path": "m/1855'/1815'/0'" + }, + { + "key_hash": "3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c490711" + } + ], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "tx_hash": "ff4a515636b38ed2b2b37f64501f75f04a25d05349b5b84c07f319b6f86372f4", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "d1673535de3120907e23f0df01553ddd3072b3212e0936c68d2352ccafcda6a7ce1798351706a3d475ad715ae13008ba45cfdf6b5e65fa963dea9c3a0e003207", + "chain_code": null + }, + { + "type": 1, + "pub_key": "36a8ef21d5b98fdf23a27325cf643deaac35e912c835e35037f23d1061ae5b16", + "signature": "71658f91b1f22e9ba5ea5aa3cf8a29294bf9ebbc2681aa0a83171ffbe8ddba9c291f879a02096948c0c99f2098355a023246656ebe5131f4a48d5be80ea92d01", + "chain_code": null + }, + { + "type": 1, + "pub_key": "b10be5c0d11ad8292bbe69e220ca0cfbe154610b3041a8e72f9d515c226ab3b1", + "signature": "cb1c210bc406ce9530d385617b48ec8be37e7b0f1403964237cf4790d065508c53f8542be9817018d242d8b3cec59de0e42726ca8c1335f9b166a99acb698306", + "chain_code": null + }, + { + "type": 1, + "pub_key": "b75258e4f61eb7b313d8554c2fe10673cf214ca2d762bfd53ec3b7846e2ee872", + "signature": "46084ff13573185716863a71e565cfd16edb677db6ae01e64db0490cd05098bd66b8d75187a06c867c183b78bfdf7478e34be2ee46bf262e07b834d091dd0009", + "chain_code": null + } + ] + } + }, + { + "description": "Simple Plutus transaction with additional witness requests", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [ + { + "path": "m/1852'/1815'/0'/0/1" + }, + { + "path": "m/1854'/1815'/0'/0/0" + }, + { + "path": "m/1855'/1815'/0'" + } + ], + "include_network_id": false + }, + "result": { + "tx_hash": "598dc85bc03cc682ee7ce8b4db798d836a0840429cae7fc62fe388e727a669a2", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "7b347ee79f28881cc13f233035e1641981e766f8abf3e8dd826dd0ab7cd56d3e4ada1d935dbbb04947642397be5daca9b8ad214d3383744eeb421b30cb5ab804", + "chain_code": null + }, + { + "type": 1, + "pub_key": "36a8ef21d5b98fdf23a27325cf643deaac35e912c835e35037f23d1061ae5b16", + "signature": "7251c488f172fb4a3c06b24abd7d636f8ee18548c3dd06c505a4c84ebc02c5734859e8231c62bcb56cd3635b23bcf948d66598f26a6fe2ce946b8d203268620e", + "chain_code": null + }, + { + "type": 1, + "pub_key": "b10be5c0d11ad8292bbe69e220ca0cfbe154610b3041a8e72f9d515c226ab3b1", + "signature": "e90ad831eb5a312f112e22562aa28039c8b6fddff00264835f866fcad550ff62e9feb190b2662a374d31d4ac0596a4d5e177da25519645ae4ff8164ca614e008", + "chain_code": null + }, + { + "type": 1, + "pub_key": "b75258e4f61eb7b313d8554c2fe10673cf214ca2d762bfd53ec3b7846e2ee872", + "signature": "1efbaa626bef7482238639c211fbb4aa7aa638ef17cde400ea88dc33ff71e427920d030a71b78e1188838f18804903e98d402402d5a0e693e44416edc2c55701", + "chain_code": null + } + ] + } + }, + { + "description": "Plutus transaction without script data hash and collateral inputs", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [ + { + "key_path": "m/1852'/1815'/0'/0/1" + } + ], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "tx_hash": "3fbf931170d2ed6df95a35572d850b40bab4b350763872cb9110f93e9ce8668b", + "witnesses": [ + { + "type": 1, + "pub_key": "36a8ef21d5b98fdf23a27325cf643deaac35e912c835e35037f23d1061ae5b16", + "signature": "4825580aca1d9486960092b4410c05bac533a5682f97153a2992d15aa98390460136705fdb35c394d6906e48ae4023b12ce780b9cc3530cfa4756b4160512207", + "chain_code": null + } + ] + } + }, + { + "description": "Plutus transaction with an ordinary input", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + }, + { + "path": "m/1852'/1815'/0'/0/2", + "prev_hash": "991af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dc", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [ + { + "key_path": "m/1852'/1815'/0'/0/1" + } + ], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "tx_hash": "08bd557131d89c5008cf79f7bdf9c47d27ad7c00b3a1a19dfecedd7c1f7508d8", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "65d13326aa2a1ef0c68ca6a3e6571147f136e2136e2454755d0184da059f4885b1ff4c8a6247d21e5bfdadb1d2dbf05e45b786323272ab907bd17bf7ab48bc04", + "chain_code": null + }, + { + "type": 1, + "pub_key": "36a8ef21d5b98fdf23a27325cf643deaac35e912c835e35037f23d1061ae5b16", + "signature": "ab5713ad075a7dd567c08b05fa8627a9a1708cffe00117b026fe3adaf84f30a60120dfbbdf39f8dc74b7c02a392390f2b2652b45db2bb291e3ab8235ea53a80e", + "chain_code": null + }, + { + "type": 1, + "pub_key": "e90d7b0a6cf831b0042d37961dd528842860e77914e715bcece676c75353b812", + "signature": "ee6f84e3ba2134ff17d6574f03ce6d495a3aa5bb73db9cafe600b047bab62387f2ed814a61e80d03f2bcb938aa6b4f70632612ed6adf5d99e7c45662da0c150d", + "chain_code": null + } + ] + } + }, + { + "description": "Plutus transaction with token minting", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "validity_interval_start": 47, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "2000000", + "token_bundle": [ + { + "policy_id": "95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39", + "tokens": [ + { + "asset_name_bytes": "74652474436f696e", + "amount": "7878754" + } + ] + }, + { + "policy_id": "96a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39", + "tokens": [ + { + "asset_name_bytes": "74652474436f696e", + "amount": "7878754" + }, + { + "asset_name_bytes": "75652474436f696e", + "amount": "1234" + } + ] + } + ] + } + ], + "mint": [ + { + "policy_id": "95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39", + "tokens": [ + { + "asset_name_bytes": "74652474436f696e", + "mint_amount": "7878754" + }, + { + "asset_name_bytes": "75652474436f696e", + "mint_amount": "-7878754" + } + ] + }, + { + "policy_id": "96a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39", + "tokens": [ + { + "asset_name_bytes": "74652474436f696e", + "mint_amount": "7878754" + }, + { + "asset_name_bytes": "75652474436f696e", + "mint_amount": "-1234" + } + ] + } + ], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [ + { + "key_path": "m/1852'/1815'/0'/0/1" + } + ], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [ + { + "path": "m/1855'/1815'/0'" + } + ], + "include_network_id": false + }, + "result": { + "tx_hash": "f1ff85026488d1ea60950d9d1819ee00a012560074cd60435f2510e917d86a7f", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "2649f1010679a14ec63c4d72c96bb46e78d7940c88a4f56c2b99c4fea9b5e8d6234f01b312e7ddc69a7ee0c474b71afe5f83ccdb3d041f5f0a5d8d66bd18970c", + "chain_code": null + }, + { + "type": 1, + "pub_key": "36a8ef21d5b98fdf23a27325cf643deaac35e912c835e35037f23d1061ae5b16", + "signature": "9a4959b3bbe3bb91477bd80e20492bf778342574be61152af2d991a2febb7cbe497d4b3d03ebe7f864db3a866ebb183bce5f92b50a234ef5e00e72c0d4be7e08", + "chain_code": null + }, + { + "type": 1, + "pub_key": "b75258e4f61eb7b313d8554c2fe10673cf214ca2d762bfd53ec3b7846e2ee872", + "signature": "af3530c4e2d48be647b29edbde10525954c0875285e2f593bd99798451e687d5dd9f84b49f10aa060b67399b766ee140b0107528b7f243a0adbb4b47d2a83007", + "chain_code": null + } + ] + } + }, + { + "description": "Plutus transaction with stake registration certificate", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [ + { + "type": 0, + "script_hash": "29fb5fd4aa8cadd6705acc8263cee0fc62edca5ac38db593fec2f9fd" + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [ + { + "key_path": "m/1852'/1815'/0'/0/1" + } + ], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "tx_hash": "0c4a8ec4a0e6718d81a391d09bbc7d48e14f879c94b7e48a35092ef532ebf597", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "f699c20b23ebc2cd8371d5df81edaf6c1057f69e9c3df68f7a2a8fe30cf95516256ea894610beead8a831f6af8e832c131a2deb08eea4441848cfbc57dddd007", + "chain_code": null + }, + { + "type": 1, + "pub_key": "36a8ef21d5b98fdf23a27325cf643deaac35e912c835e35037f23d1061ae5b16", + "signature": "876bf1ce1d8c1aa8fb830e7fcaff1289d8e29cda0529468823fdaaac38be4c95b04b72c8669eb062ef27b816d677c7f00a4d9f4b427d932d4de93bcf1f32460a", + "chain_code": null + } + ] + } + }, + { + "description": "Plutus transaction with stake registration and stake delegation certificates", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [ + { + "type": 0, + "script_hash": "29fb5fd4aa8cadd6705acc8263cee0fc62edca5ac38db593fec2f9fd" + }, + { + "type": 2, + "pool": "f61c42cbf7c8c53af3f520508212ad3e72f674f957fe23ff0acb4973", + "script_hash": "29fb5fd4aa8cadd6705acc8263cee0fc62edca5ac38db593fec2f9fd" + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [ + { + "key_path": "m/1852'/1815'/0'/0/1" + }, + { + "key_path": "m/1854'/1815'/0'/2/0" + } + ], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "tx_hash": "53d7a7ee887178a08ac70ff2088f8bfbafc7b6bcd5a54e79a686b013455d5e25", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "0911d01cc22dfeff461b899f16788689deed54ec5b5433abdbabeafe135b90d142497d8dbefad35ece9a188da318b3d930121d7b1e4630211c38d65f895ee506", + "chain_code": null + }, + { + "type": 1, + "pub_key": "36a8ef21d5b98fdf23a27325cf643deaac35e912c835e35037f23d1061ae5b16", + "signature": "a3ad8674b341277b4f4e88eb1257164cc50dda61a5ef6d3c19eb3f24d24d91933fd87349d2234bcbf630c60f6cc519f05075082daca429fb1743025a5dd1130b", + "chain_code": null + }, + { + "type": 1, + "pub_key": "f2ef4ecd21ad28a8d270ca7be7e96c87f60dc821e13c0d0c5870344e9693637c", + "signature": "16bf0b97bca3012d8f715ea4c00657abcde5fb71d44cbfb18ca10750ae8ce6769de6efc94595e674592844d718d0a3252d7ea2db408a8fe4c2e0b08eb2af4d06", + "chain_code": null + } + ] + } + }, + { + "description": "Plutus transaction with stake deregistration", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [ + { + "type": 1, + "script_hash": "29fb5fd4aa8cadd6705acc8263cee0fc62edca5ac38db593fec2f9fd" + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [ + { + "key_path": "m/1852'/1815'/0'/0/1" + }, + { + "key_path": "m/1854'/1815'/0'/2/0" + } + ], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "tx_hash": "c55ef20e0c8da066bab5221a5c010c32d90905753b0257576e34d7e639f65c9d", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "e8f09ff2ff8507fdfa4d33525b15b93f443e15d95b67db57524a08d799a061b4615196cba47760ff39819c6c3d1c524f5a4e247460d8fcef5c3a13d261d7670f", + "chain_code": null + }, + { + "type": 1, + "pub_key": "36a8ef21d5b98fdf23a27325cf643deaac35e912c835e35037f23d1061ae5b16", + "signature": "b3de1a866d8cb7d6e3ec96a4d4b5f45322def1fc75ae5f0ff53b6eb2dbd85340b358a71be82ff810c6ac716eb37650eb83132327ff18cb00326e770481e1b10b", + "chain_code": null + }, + { + "type": 1, + "pub_key": "f2ef4ecd21ad28a8d270ca7be7e96c87f60dc821e13c0d0c5870344e9693637c", + "signature": "7b558ae9bf5dcc7cb85f991d494291d483204c28e1d50590d99af8b2bce3482d4a59f665f3b9105ac38b87aca29c53c484f062daf882e40ce0fed683839e1c04", + "chain_code": null + } + ] + } + }, + { + "description": "Plutus transaction with stake deregistration and withdrawal", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [ + { + "type": 1, + "script_hash": "29fb5fd4aa8cadd6705acc8263cee0fc62edca5ac38db593fec2f9fd" + } + ], + "withdrawals": [ + { + "amount": "1000", + "script_hash": "29fb5fd4aa8cadd6705acc8263cee0fc62edca5ac38db593fec2f9fd" + } + ], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [ + { + "key_path": "m/1852'/1815'/0'/0/1" + }, + { + "key_path": "m/1854'/1815'/0'/2/0" + } + ], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "tx_hash": "b3ccc29173719973363988763826eb853cb314df8dde07fcf82dab9961d47c25", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "be0437f0452d9d7d494ad78d277f5414b062741f4cdc2debe50b2e26dfbdf5cca2644b734e112c53a843233dc5c2f13ab6f5aebb09ae1cf20d2d2f3d56d32b0a", + "chain_code": null + }, + { + "type": 1, + "pub_key": "36a8ef21d5b98fdf23a27325cf643deaac35e912c835e35037f23d1061ae5b16", + "signature": "2d3a8ff9251a72f5162ca910e1097fce2c1d0407f5199389126b3521540ad044cc585e9bf830f895a9f523379c0280e2d85d019d648653b31711486dc89e7107", + "chain_code": null + }, + { + "type": 1, + "pub_key": "f2ef4ecd21ad28a8d270ca7be7e96c87f60dc821e13c0d0c5870344e9693637c", + "signature": "bbf0616344629b0bbbc5f05ca5c6382ecc3e4eb629bdd798cdb4a25affd3024201bb697ef4086e1e7ab1793642b4888d78e6935daf97db22a736978bbd249f0f", + "chain_code": null + } + ] + } + }, + { + "description": "Plutus transaction with output datum hash", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + }, + { + "address": "addr1w9rhu54nz94k9l5v6d9rzfs47h7dv7xffcwkekuxcx3evnqpvuxu0", + "amount": "1", + "datum_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7" + } + ], + "mint": [], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "tx_hash": "bb4d26c40c67d23ca74bb2e4ad28f586567b99907b86c0337fb7d8f4cde90100", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "24fcbbb8985feef3c54b86fdfded2fd2d324e1dc79a1e891bdf97d9c6115f28eef54eca387a95f34a73b87e705d9336a6582835620052e95f43403ae49f8cc08", + "chain_code": null + } + ] + } + } + ] +} diff --git a/common/tests/fixtures/cardano/sign_tx.slip39.json b/common/tests/fixtures/cardano/sign_tx.slip39.json index 696cc9c931..1eb0784eb8 100644 --- a/common/tests/fixtures/cardano/sign_tx.slip39.json +++ b/common/tests/fixtures/cardano/sign_tx.slip39.json @@ -33,6 +33,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -79,6 +81,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -125,6 +129,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false diff --git a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.failed.json b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.failed.json index 2e8853fb3f..2efef42567 100644 --- a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.failed.json +++ b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.failed.json @@ -50,6 +50,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -107,6 +109,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -161,6 +165,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -215,6 +221,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -290,6 +298,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -327,6 +337,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -386,6 +398,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -440,6 +454,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -493,6 +509,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -546,6 +564,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -633,6 +653,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -720,6 +742,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -807,6 +831,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [], "include_network_id": false @@ -815,6 +841,95 @@ "error_message": "Invalid certificate" } }, + { + "description": "With PLUTUS_TRANSACTION signing mode", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [ + { + "type": 3, + "pool_parameters": { + "pool_id": "f61c42cbf7c8c53af3f520508212ad3e72f674f957fe23ff0acb4973", + "vrf_key_hash": "198890ad6c92e80fbdab554dda02da9fb49d001bbd96181f3e07f7a6ab0d0640", + "pledge": 500000000, + "cost": 340000000, + "margin": { + "numerator": 1, + "denominator": 2 + }, + "reward_account": "stake1uya87zwnmax0v6nnn8ptqkl6ydx4522kpsc3l3wmf3yswygwx45el", + "owners": [ + { + "staking_key_path": "m/1852'/1815'/0'/2/0" + }, + { + "staking_key_hash": "3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c490711" + } + ], + "relays": [ + { + "type": 0, + "ipv4_address": "192.168.0.1", + "ipv6_address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "port": 1234 + }, + { + "type": 0, + "ipv6_address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "port": 1234 + }, + { + "type": 0, + "ipv4_address": "192.168.0.1", + "port": 1234 + }, + { + "type": 1, + "host_name": "www.test.test", + "port": 1234 + }, + { + "type": 2, + "host_name": "www.test2.test" + } + ], + "metadata": { + "url": "https://www.test.test", + "hash": "914c57c1f12bbf4a82b12d977d4f274674856a11ed4b9b95bd70f5d41c5064a6" + } + } + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": null, + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "error_message": "Invalid certificate" + } + }, { "description": "Sample stake pool registration certificate with 1854 additional witness request", "parameters": { @@ -894,6 +1009,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [ { @@ -985,6 +1102,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [ { @@ -1103,6 +1222,8 @@ } ], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [ { @@ -1196,6 +1317,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -1284,6 +1407,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -1371,6 +1496,196 @@ ], "mint": [], "script_data_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "collateral_inputs": [], + "required_signers": [], + "signing_mode": "POOL_REGISTRATION_AS_OWNER", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "error_message": "Invalid tx signing request" + } + }, + { + "description": "Sample stake pool registration certificate with collateral input", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [ + { + "type": 3, + "pool_parameters": { + "pool_id": "f61c42cbf7c8c53af3f520508212ad3e72f674f957fe23ff0acb4973", + "vrf_key_hash": "198890ad6c92e80fbdab554dda02da9fb49d001bbd96181f3e07f7a6ab0d0640", + "pledge": 500000000, + "cost": 340000000, + "margin": { + "numerator": 1, + "denominator": 2 + }, + "reward_account": "stake1uya87zwnmax0v6nnn8ptqkl6ydx4522kpsc3l3wmf3yswygwx45el", + "owners": [ + { + "staking_key_path": "m/1852'/1815'/0'/2/0" + }, + { + "staking_key_hash": "3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c490711" + } + ], + "relays": [ + { + "type": 0, + "ipv4_address": "192.168.0.1", + "ipv6_address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "port": 1234 + }, + { + "type": 0, + "ipv6_address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "port": 1234 + }, + { + "type": 0, + "ipv4_address": "192.168.0.1", + "port": 1234 + }, + { + "type": 1, + "host_name": "www.test.test", + "port": 1234 + }, + { + "type": 2, + "host_name": "www.test2.test" + } + ], + "metadata": { + "url": "https://www.test.test", + "hash": "914c57c1f12bbf4a82b12d977d4f274674856a11ed4b9b95bd70f5d41c5064a6" + } + } + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": null, + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1w9rhu54nz94k9l5v6d9rzfs47h7dv7xffcwkekuxcx3evnqpvuxu0", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [ + { + "path": null, + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "required_signers": [], + "signing_mode": "POOL_REGISTRATION_AS_OWNER", + "additional_witness_requests": [], + "include_network_id": false + }, + "result": { + "error_message": "Invalid tx signing request" + } + }, + { + "description": "Sample stake pool registration certificate with required signer", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [ + { + "type": 3, + "pool_parameters": { + "pool_id": "f61c42cbf7c8c53af3f520508212ad3e72f674f957fe23ff0acb4973", + "vrf_key_hash": "198890ad6c92e80fbdab554dda02da9fb49d001bbd96181f3e07f7a6ab0d0640", + "pledge": 500000000, + "cost": 340000000, + "margin": { + "numerator": 1, + "denominator": 2 + }, + "reward_account": "stake1uya87zwnmax0v6nnn8ptqkl6ydx4522kpsc3l3wmf3yswygwx45el", + "owners": [ + { + "staking_key_path": "m/1852'/1815'/0'/2/0" + }, + { + "staking_key_hash": "3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c490711" + } + ], + "relays": [ + { + "type": 0, + "ipv4_address": "192.168.0.1", + "ipv6_address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "port": 1234 + }, + { + "type": 0, + "ipv6_address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "port": 1234 + }, + { + "type": 0, + "ipv4_address": "192.168.0.1", + "port": 1234 + }, + { + "type": 1, + "host_name": "www.test.test", + "port": 1234 + }, + { + "type": 2, + "host_name": "www.test2.test" + } + ], + "metadata": { + "url": "https://www.test.test", + "hash": "914c57c1f12bbf4a82b12d977d4f274674856a11ed4b9b95bd70f5d41c5064a6" + } + } + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": null, + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1w9rhu54nz94k9l5v6d9rzfs47h7dv7xffcwkekuxcx3evnqpvuxu0", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [ + { + "key_hash": "3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c490711" + } + ], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false diff --git a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json index c0362f7a6b..9e32bb7c5b 100644 --- a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json +++ b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json @@ -83,6 +83,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -178,6 +180,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -274,6 +278,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -336,6 +342,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -398,6 +406,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false @@ -495,6 +505,8 @@ ], "mint": [], "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], "include_network_id": false diff --git a/core/src/apps/cardano/README.md b/core/src/apps/cardano/README.md index b18d5d5eb7..6053c7440d 100644 --- a/core/src/apps/cardano/README.md +++ b/core/src/apps/cardano/README.md @@ -18,6 +18,8 @@ REVIEWER = Jan Matejek , Tomas Susanka { asset_name => asset_amount }}]] - # uint(1), array(2) + # outputs [address, [ada_amount, { policy_id => { asset_name => asset_amount }}], datum_hash?] + # uint(1), array(3) 1: [ # multi asset output # array(2), bytes(57), uint(1234), map(1), bytes(28), map(1), bytes(8), uint(4321) @@ -330,6 +347,9 @@ a900818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b70001 # output containing only ADA [address, ada_amount] # array(2), bytes(57), uint(4444) [h'018...', 4444], + # output with datum_hash [address, ada_amount, datum_hash] + # array(3), bytes(29), uint(3142), bytes(32) + [h'714...', 3142, h'3b4...'], ] # fee diff --git a/core/src/apps/cardano/certificates.py b/core/src/apps/cardano/certificates.py index 45f9670bf2..a2eca64889 100644 --- a/core/src/apps/cardano/certificates.py +++ b/core/src/apps/cardano/certificates.py @@ -8,14 +8,10 @@ from trezor.enums import ( from apps.common import cbor -from .address import ( - get_address_bytes_unsafe, - get_public_key_hash, - validate_reward_address, -) +from .address import get_address_bytes_unsafe, validate_reward_address from .helpers import ADDRESS_KEY_HASH_SIZE, INVALID_CERTIFICATE, LOVELACE_MAX_SUPPLY from .helpers.paths import SCHEMA_STAKING_ANY_ACCOUNT -from .helpers.utils import validate_stake_credential +from .helpers.utils import get_public_key_hash, validate_stake_credential if TYPE_CHECKING: from typing import Any diff --git a/core/src/apps/cardano/helpers/__init__.py b/core/src/apps/cardano/helpers/__init__.py index 1455be8a8e..471a3d671d 100644 --- a/core/src/apps/cardano/helpers/__init__.py +++ b/core/src/apps/cardano/helpers/__init__.py @@ -21,6 +21,8 @@ INVALID_NATIVE_SCRIPT = wire.ProcessError("Invalid native script") INVALID_TOKEN_BUNDLE_MINT = wire.ProcessError("Invalid mint token bundle") INVALID_OUTPUT_DATUM_HASH = wire.ProcessError("Invalid output datum hash") INVALID_SCRIPT_DATA_HASH = wire.ProcessError("Invalid script data hash") +INVALID_COLLATERAL_INPUT = wire.ProcessError("Invalid collateral input") +INVALID_REQUIRED_SIGNER = wire.ProcessError("Invalid required signer") LOVELACE_MAX_SUPPLY = 45_000_000_000 * 1_000_000 INPUT_PREV_HASH_SIZE = 32 diff --git a/core/src/apps/cardano/helpers/bech32.py b/core/src/apps/cardano/helpers/bech32.py index 46ebe07ae7..fdfecdbe8f 100644 --- a/core/src/apps/cardano/helpers/bech32.py +++ b/core/src/apps/cardano/helpers/bech32.py @@ -12,6 +12,7 @@ HRP_JORMUN_PUBLIC_KEY = "ed25519_pk" HRP_SCRIPT_HASH = "script" HRP_KEY_HASH = "addr_vkh" HRP_SHARED_KEY_HASH = "addr_shared_vkh" +HRP_REQUIRED_SIGNER_KEY_HASH = "req_signer_vkh" HRP_OUTPUT_DATUM_HASH = "datum" HRP_SCRIPT_DATA_HASH = "script_data" diff --git a/core/src/apps/cardano/helpers/utils.py b/core/src/apps/cardano/helpers/utils.py index bf43ef06cc..a0ddfdc7d8 100644 --- a/core/src/apps/cardano/helpers/utils.py +++ b/core/src/apps/cardano/helpers/utils.py @@ -76,6 +76,10 @@ def format_key_hash(key_hash: bytes, is_shared_key: bool) -> str: return bech32.encode(hrp, key_hash) +def format_required_signer_key_hash(required_signer_key_hash: bytes) -> str: + return bech32.encode(bech32.HRP_REQUIRED_SIGNER_KEY_HASH, required_signer_key_hash) + + def format_output_datum_hash(output_datum_hash: bytes) -> str: return bech32.encode(bech32.HRP_OUTPUT_DATUM_HASH, output_datum_hash) @@ -112,7 +116,10 @@ def validate_stake_credential( if not SCHEMA_STAKING_ANY_ACCOUNT.match(path): raise error elif script_hash: - if signing_mode != CardanoTxSigningMode.MULTISIG_TRANSACTION: + if signing_mode not in ( + CardanoTxSigningMode.MULTISIG_TRANSACTION, + CardanoTxSigningMode.PLUTUS_TRANSACTION, + ): raise error if len(script_hash) != SCRIPT_HASH_SIZE: raise error diff --git a/core/src/apps/cardano/layout.py b/core/src/apps/cardano/layout.py index cc66b5ed27..1f1583e185 100644 --- a/core/src/apps/cardano/layout.py +++ b/core/src/apps/cardano/layout.py @@ -32,6 +32,7 @@ from .helpers.utils import ( format_key_hash, format_optional_int, format_output_datum_hash, + format_required_signer_key_hash, format_script_data_hash, format_script_hash, format_stake_pool_id, @@ -44,6 +45,9 @@ if TYPE_CHECKING: from trezor.messages import ( CardanoNativeScript, CardanoTxCertificate, + CardanoTxCollateralInput, + CardanoTxInput, + CardanoTxRequiredSigner, CardanoTxWithdrawal, CardanoPoolParametersType, CardanoPoolOwner, @@ -201,6 +205,27 @@ async def show_transaction_signing_mode( larger_vspace=True, br_code=ButtonRequestType.Other, ) + elif signing_mode == CardanoTxSigningMode.PLUTUS_TRANSACTION: + await confirm_metadata( + ctx, + "confirm_signing_mode", + title="Confirm transaction", + content="Confirming a Plutus transaction - loss of collateral is possible. Check all items carefully.", + br_code=ButtonRequestType.Other, + ) + + +async def confirm_input(ctx: wire.Context, input: CardanoTxInput) -> None: + await confirm_properties( + ctx, + "confirm_input", + title="Confirm transaction", + props=[ + ("Input ID:", input.prev_hash), + ("Input index:", str(input.prev_index)), + ], + br_code=ButtonRequestType.Other, + ) async def confirm_sending( @@ -334,6 +359,17 @@ async def show_warning_tx_output_contains_tokens(ctx: wire.Context) -> None: ) +async def show_warning_tx_contains_mint(ctx: wire.Context) -> None: + await confirm_metadata( + ctx, + "confirm_tokens", + title="Confirm transaction", + content="The transaction contains minting or burning of tokens.", + larger_vspace=True, + br_code=ButtonRequestType.Other, + ) + + async def show_warning_tx_output_contains_datum_hash( ctx: wire.Context, datum_hash: bytes ) -> None: @@ -362,6 +398,26 @@ async def show_warning_tx_output_no_datum_hash(ctx: wire.Context) -> None: ) +async def show_warning_no_script_data_hash(ctx: wire.Context) -> None: + await confirm_metadata( + ctx, + "confirm_no_script_data_hash", + title="Confirm transaction", + content="The transaction contains no script data hash. Plutus script will not be able to run.", + br_code=ButtonRequestType.Other, + ) + + +async def show_warning_no_collateral_inputs(ctx: wire.Context) -> None: + await confirm_metadata( + ctx, + "confirm_no_collateral_inputs", + title="Confirm transaction", + content="The transaction contains no collateral inputs. Plutus script will not be able to run.", + br_code=ButtonRequestType.Other, + ) + + async def confirm_witness_request( ctx: wire.Context, witness_path: list[int], @@ -637,17 +693,6 @@ async def show_auxiliary_data_hash( ) -async def show_warning_tx_contains_mint(ctx: wire.Context) -> None: - await confirm_metadata( - ctx, - "confirm_tokens", - title="Confirm transaction", - content="The transaction contains\nminting or burning of\ntokens.", - larger_vspace=True, - br_code=ButtonRequestType.Other, - ) - - async def confirm_token_minting( ctx: wire.Context, policy_id: bytes, token: CardanoToken ) -> None: @@ -694,6 +739,42 @@ async def confirm_script_data_hash(ctx: wire.Context, script_data_hash: bytes) - ) +async def confirm_collateral_input( + ctx: wire.Context, collateral_input: CardanoTxCollateralInput +) -> None: + await confirm_properties( + ctx, + "confirm_collateral_input", + title="Confirm transaction", + props=[ + ("Collateral input ID:", collateral_input.prev_hash), + ("Collateral input index:", str(collateral_input.prev_index)), + ], + br_code=ButtonRequestType.Other, + ) + + +async def confirm_required_signer( + ctx: wire.Context, required_signer: CardanoTxRequiredSigner +) -> None: + assert ( + required_signer.key_hash is not None or required_signer.key_path + ) # _validate_required_signer + formatted_signer = ( + format_required_signer_key_hash(required_signer.key_hash) + if required_signer.key_hash is not None + else address_n_to_str(required_signer.key_path) + ) + + await confirm_properties( + ctx, + "confirm_required_signer", + title="Confirm transaction", + props=[("Required signer", formatted_signer)], + br_code=ButtonRequestType.Other, + ) + + async def show_cardano_address( ctx: wire.Context, address_parameters: CardanoAddressParametersType, diff --git a/core/src/apps/cardano/sign_tx.py b/core/src/apps/cardano/sign_tx.py index 6f340c3856..816c82b8de 100644 --- a/core/src/apps/cardano/sign_tx.py +++ b/core/src/apps/cardano/sign_tx.py @@ -21,11 +21,13 @@ from trezor.messages import ( CardanoTxAuxiliaryData, CardanoTxBodyHash, CardanoTxCertificate, + CardanoTxCollateralInput, CardanoTxHostAck, CardanoTxInput, CardanoTxItemAck, CardanoTxMint, CardanoTxOutput, + CardanoTxRequiredSigner, CardanoTxWithdrawal, CardanoTxWitnessRequest, CardanoTxWitnessResponse, @@ -60,10 +62,13 @@ from .certificates import ( validate_pool_relay, ) from .helpers import ( + ADDRESS_KEY_HASH_SIZE, INPUT_PREV_HASH_SIZE, + INVALID_COLLATERAL_INPUT, INVALID_INPUT, INVALID_OUTPUT, INVALID_OUTPUT_DATUM_HASH, + INVALID_REQUIRED_SIGNER, INVALID_SCRIPT_DATA_HASH, INVALID_STAKE_POOL_REGISTRATION_TX_STRUCTURE, INVALID_STAKEPOOL_REGISTRATION_TX_WITNESSES, @@ -92,9 +97,16 @@ from .helpers.paths import ( SCHEMA_STAKING_ANY_ACCOUNT, WITNESS_PATH_NAME, ) -from .helpers.utils import derive_public_key, validate_stake_credential +from .helpers.utils import ( + derive_public_key, + get_public_key_hash, + validate_stake_credential, +) from .layout import ( confirm_certificate, + confirm_collateral_input, + confirm_input, + confirm_required_signer, confirm_script_data_hash, confirm_sending, confirm_sending_token, @@ -108,6 +120,8 @@ from .layout import ( confirm_witness_request, show_credentials, show_transaction_signing_mode, + show_warning_no_collateral_inputs, + show_warning_no_script_data_hash, show_warning_path, show_warning_tx_contains_mint, show_warning_tx_network_unverifiable, @@ -115,7 +129,7 @@ from .layout import ( show_warning_tx_output_contains_tokens, show_warning_tx_output_no_datum_hash, ) -from .seed import is_byron_path, is_multisig_path, is_shelley_path +from .seed import is_byron_path, is_minting_path, is_multisig_path, is_shelley_path if TYPE_CHECKING: from typing import Any @@ -136,6 +150,8 @@ TX_BODY_KEY_AUXILIARY_DATA = const(7) TX_BODY_KEY_VALIDITY_INTERVAL_START = const(8) TX_BODY_KEY_MINT = const(9) TX_BODY_KEY_SCRIPT_DATA_HASH = const(11) +TX_BODY_KEY_COLLATERAL_INPUTS = const(13) +TX_BODY_KEY_REQUIRED_SIGNERS = const(14) TX_BODY_KEY_NETWORK_ID = const(15) POOL_REGISTRATION_CERTIFICATE_ITEMS_COUNT = 10 @@ -145,10 +161,10 @@ POOL_REGISTRATION_CERTIFICATE_ITEMS_COUNT = 10 async def sign_tx( ctx: wire.Context, msg: CardanoSignTxInit, keychain: seed.Keychain ) -> CardanoSignTxFinished: - is_network_id_verifiable = await _validate_tx_signing_request(ctx, msg) - await show_transaction_signing_mode(ctx, msg.signing_mode) + is_network_id_verifiable = await _validate_tx_signing_request(ctx, msg) + # inputs, outputs and fee are mandatory fields, count the number of optional fields present tx_body_map_item_count = 3 + sum( ( @@ -160,6 +176,8 @@ async def sign_tx( msg.minting_asset_groups_count > 0, msg.include_network_id, msg.script_data_hash is not None, + msg.collateral_inputs_count > 0, + msg.required_signers_count > 0, ) ) @@ -205,23 +223,30 @@ async def _validate_tx_signing_request( validate_network_info(msg.network_id, msg.protocol_magic) is_network_id_verifiable = _is_network_id_verifiable(msg) - if msg.signing_mode == CardanoTxSigningMode.ORDINARY_TRANSACTION: - if not is_network_id_verifiable: - await show_warning_tx_network_unverifiable(ctx) - elif msg.signing_mode == CardanoTxSigningMode.POOL_REGISTRATION_AS_OWNER: + if not is_network_id_verifiable: + await show_warning_tx_network_unverifiable(ctx) + + if msg.signing_mode == CardanoTxSigningMode.POOL_REGISTRATION_AS_OWNER: _validate_stake_pool_registration_tx_structure(msg) - elif msg.signing_mode == CardanoTxSigningMode.MULTISIG_TRANSACTION: - if not is_network_id_verifiable: - await show_warning_tx_network_unverifiable(ctx) - else: - raise INVALID_TX_SIGNING_REQUEST if msg.script_data_hash is not None and msg.signing_mode not in ( CardanoTxSigningMode.ORDINARY_TRANSACTION, CardanoTxSigningMode.MULTISIG_TRANSACTION, + CardanoTxSigningMode.PLUTUS_TRANSACTION, ): raise INVALID_TX_SIGNING_REQUEST + if msg.signing_mode == CardanoTxSigningMode.PLUTUS_TRANSACTION: + # these items should be present if a Plutus script should be executed + if msg.script_data_hash is None: + await show_warning_no_script_data_hash(ctx) + if msg.collateral_inputs_count == 0: + await show_warning_no_collateral_inputs(ctx) + else: + # these items are only allowed in PLUTUS_TRANSACTION + if msg.collateral_inputs_count != 0 or msg.required_signers_count != 0: + raise INVALID_TX_SIGNING_REQUEST + return is_network_id_verifiable @@ -234,7 +259,7 @@ async def _process_transaction( ) -> None: inputs_list: HashBuilderList[tuple[bytes, int]] = HashBuilderList(msg.inputs_count) with tx_dict.add(TX_BODY_KEY_INPUTS, inputs_list): - await _process_inputs(ctx, inputs_list, msg.inputs_count) + await _process_inputs(ctx, inputs_list, msg.inputs_count, msg.signing_mode) outputs_list: HashBuilderList = HashBuilderList(msg.outputs_count) with tx_dict.add(TX_BODY_KEY_OUTPUTS, outputs_list): @@ -306,6 +331,29 @@ async def _process_transaction( if msg.script_data_hash is not None: await _process_script_data_hash(ctx, tx_dict, msg.script_data_hash) + if msg.collateral_inputs_count > 0: + collateral_inputs_list: HashBuilderList[tuple[bytes, int]] = HashBuilderList( + msg.collateral_inputs_count + ) + with tx_dict.add(TX_BODY_KEY_COLLATERAL_INPUTS, collateral_inputs_list): + await _process_collateral_inputs( + ctx, + collateral_inputs_list, + msg.collateral_inputs_count, + ) + + if msg.required_signers_count > 0: + required_signers_list: HashBuilderList[bytes] = HashBuilderList( + msg.required_signers_count + ) + with tx_dict.add(TX_BODY_KEY_REQUIRED_SIGNERS, required_signers_list): + await _process_required_signers( + ctx, + keychain, + required_signers_list, + msg.required_signers_count, + ) + if msg.include_network_id: tx_dict.add(TX_BODY_KEY_NETWORK_ID, msg.network_id) @@ -318,6 +366,7 @@ async def _confirm_transaction( if msg.signing_mode in ( CardanoTxSigningMode.ORDINARY_TRANSACTION, CardanoTxSigningMode.MULTISIG_TRANSACTION, + CardanoTxSigningMode.PLUTUS_TRANSACTION, ): await confirm_transaction( ctx, @@ -332,18 +381,22 @@ async def _confirm_transaction( ctx, msg.protocol_magic, msg.ttl, msg.validity_interval_start ) else: - raise ValueError + raise RuntimeError # we didn't cover all signing modes async def _process_inputs( ctx: wire.Context, inputs_list: HashBuilderList[tuple[bytes, int]], inputs_count: int, + signing_mode: CardanoTxSigningMode, ) -> None: """Read, validate and serialize the inputs.""" for _ in range(inputs_count): input: CardanoTxInput = await ctx.call(CardanoTxItemAck(), CardanoTxInput) _validate_input(input) + if signing_mode == CardanoTxSigningMode.PLUTUS_TRANSACTION: + await confirm_input(ctx, input) + inputs_list.append((input.prev_hash, input.prev_index)) @@ -688,6 +741,45 @@ async def _process_script_data_hash( tx_body_builder_dict.add(TX_BODY_KEY_SCRIPT_DATA_HASH, script_data_hash) +async def _process_collateral_inputs( + ctx: wire.Context, + collateral_inputs_list: HashBuilderList[tuple[bytes, int]], + collateral_inputs_count: int, +) -> None: + """Read, validate, show and serialize the collateral inputs.""" + for _ in range(collateral_inputs_count): + collateral_input: CardanoTxCollateralInput = await ctx.call( + CardanoTxItemAck(), CardanoTxCollateralInput + ) + _validate_collateral_input(collateral_input) + await confirm_collateral_input(ctx, collateral_input) + + collateral_inputs_list.append( + (collateral_input.prev_hash, collateral_input.prev_index) + ) + + +async def _process_required_signers( + ctx: wire.Context, + keychain: seed.Keychain, + required_signers_list: HashBuilderList[bytes], + required_signers_count: int, +) -> None: + """Read, validate, show and serialize the required signers.""" + for _ in range(required_signers_count): + required_signer: CardanoTxRequiredSigner = await ctx.call( + CardanoTxItemAck(), CardanoTxRequiredSigner + ) + _validate_required_signer(required_signer) + await confirm_required_signer(ctx, required_signer) + + key_hash = required_signer.key_hash or get_public_key_hash( + keychain, required_signer.key_path + ) + + required_signers_list.append(key_hash) + + async def _process_witness_requests( ctx: wire.Context, keychain: seed.Keychain, @@ -784,6 +876,7 @@ def _validate_output( if address_parameters := output.address_parameters: if signing_mode != CardanoTxSigningMode.ORDINARY_TRANSACTION: + # change outputs are allowed only in ORDINARY_TRANSACTION raise INVALID_OUTPUT validate_output_address_parameters(address_parameters) @@ -797,6 +890,7 @@ def _validate_output( if signing_mode not in ( CardanoTxSigningMode.ORDINARY_TRANSACTION, CardanoTxSigningMode.MULTISIG_TRANSACTION, + CardanoTxSigningMode.PLUTUS_TRANSACTION, ): raise INVALID_OUTPUT if len(output.datum_hash) != OUTPUT_DATUM_HASH_SIZE: @@ -923,11 +1017,16 @@ async def _show_certificate( ctx, SCHEMA_STAKING, certificate.path, CERTIFICATE_PATH_NAME ) await confirm_certificate(ctx, certificate) - elif signing_mode == CardanoTxSigningMode.MULTISIG_TRANSACTION: + elif signing_mode in ( + CardanoTxSigningMode.MULTISIG_TRANSACTION, + CardanoTxSigningMode.PLUTUS_TRANSACTION, + ): assert certificate.script_hash # validate_certificate await confirm_certificate(ctx, certificate) elif signing_mode == CardanoTxSigningMode.POOL_REGISTRATION_AS_OWNER: await _show_stake_pool_registration_certificate(ctx, certificate) + else: + raise RuntimeError # we didn't cover all signing modes def _validate_withdrawal( @@ -963,6 +1062,29 @@ def _validate_script_data_hash(script_data_hash: bytes) -> None: raise INVALID_SCRIPT_DATA_HASH +def _validate_collateral_input(collateral_input: CardanoTxCollateralInput) -> None: + if len(collateral_input.prev_hash) != INPUT_PREV_HASH_SIZE: + raise INVALID_COLLATERAL_INPUT + + +def _validate_required_signer(required_signer: CardanoTxRequiredSigner) -> None: + if required_signer.key_hash and required_signer.key_path: + raise INVALID_REQUIRED_SIGNER + + if required_signer.key_hash: + if len(required_signer.key_hash) != ADDRESS_KEY_HASH_SIZE: + raise INVALID_REQUIRED_SIGNER + elif required_signer.key_path: + if not ( + is_shelley_path(required_signer.key_path) + or is_multisig_path(required_signer.key_path) + or is_minting_path(required_signer.key_path) + ): + raise INVALID_REQUIRED_SIGNER + else: + raise INVALID_REQUIRED_SIGNER + + def _derive_withdrawal_reward_address_bytes( keychain: seed.Keychain, withdrawal: CardanoTxWithdrawal, @@ -1072,6 +1194,17 @@ def _validate_witness_request( raise INVALID_WITNESS_REQUEST if is_minting and not transaction_has_token_minting: raise INVALID_WITNESS_REQUEST + elif signing_mode == CardanoTxSigningMode.PLUTUS_TRANSACTION: + if not ( + is_shelley_path(witness_request.path) + or is_multisig_path(witness_request.path) + or is_minting + ): + raise INVALID_WITNESS_REQUEST + # in PLUTUS_TRANSACTION, we allow minting witnesses even when transaction + # doesn't have token minting + else: + raise RuntimeError # we didn't cover all signing modes account_path_checker.add_witness_request(witness_request) @@ -1110,10 +1243,14 @@ async def _show_witness_request( await confirm_witness_request(ctx, witness_path) elif not is_payment and not is_staking: await _fail_or_warn_path(ctx, witness_path, WITNESS_PATH_NAME) - elif signing_mode == CardanoTxSigningMode.MULTISIG_TRANSACTION: - await confirm_witness_request(ctx, witness_path) - elif signing_mode == CardanoTxSigningMode.POOL_REGISTRATION_AS_OWNER: + elif signing_mode in ( + CardanoTxSigningMode.POOL_REGISTRATION_AS_OWNER, + CardanoTxSigningMode.MULTISIG_TRANSACTION, + CardanoTxSigningMode.PLUTUS_TRANSACTION, + ): await confirm_witness_request(ctx, witness_path) + else: + raise RuntimeError # we didn't cover all signing modes def _is_network_id_verifiable(msg: CardanoSignTxInit) -> bool: diff --git a/core/src/trezor/enums/CardanoTxSigningMode.py b/core/src/trezor/enums/CardanoTxSigningMode.py index 17aa27964d..7a8f355fa8 100644 --- a/core/src/trezor/enums/CardanoTxSigningMode.py +++ b/core/src/trezor/enums/CardanoTxSigningMode.py @@ -5,3 +5,4 @@ ORDINARY_TRANSACTION = 0 POOL_REGISTRATION_AS_OWNER = 1 MULTISIG_TRANSACTION = 2 +PLUTUS_TRANSACTION = 3 diff --git a/core/src/trezor/enums/MessageType.py b/core/src/trezor/enums/MessageType.py index 74ff942fa5..cf07ccfd0f 100644 --- a/core/src/trezor/enums/MessageType.py +++ b/core/src/trezor/enums/MessageType.py @@ -165,6 +165,8 @@ if not utils.BITCOIN_ONLY: CardanoGetNativeScriptHash = 330 CardanoNativeScriptHash = 331 CardanoTxMint = 332 + CardanoTxCollateralInput = 333 + CardanoTxRequiredSigner = 334 RippleGetAddress = 400 RippleAddress = 401 RippleSignTx = 402 diff --git a/core/src/trezor/enums/__init__.py b/core/src/trezor/enums/__init__.py index 2c47c98e96..ea26eded6f 100644 --- a/core/src/trezor/enums/__init__.py +++ b/core/src/trezor/enums/__init__.py @@ -183,6 +183,8 @@ if TYPE_CHECKING: CardanoGetNativeScriptHash = 330 CardanoNativeScriptHash = 331 CardanoTxMint = 332 + CardanoTxCollateralInput = 333 + CardanoTxRequiredSigner = 334 RippleGetAddress = 400 RippleAddress = 401 RippleSignTx = 402 @@ -379,6 +381,7 @@ if TYPE_CHECKING: ORDINARY_TRANSACTION = 0 POOL_REGISTRATION_AS_OWNER = 1 MULTISIG_TRANSACTION = 2 + PLUTUS_TRANSACTION = 3 class CardanoTxWitnessType(IntEnum): BYRON_WITNESS = 0 diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py index 422d4fe810..86556d0ab4 100644 --- a/core/src/trezor/messages.py +++ b/core/src/trezor/messages.py @@ -1333,6 +1333,8 @@ if TYPE_CHECKING: derivation_type: "CardanoDerivationType" include_network_id: "bool" script_data_hash: "bytes | None" + collateral_inputs_count: "int" + required_signers_count: "int" def __init__( self, @@ -1349,6 +1351,8 @@ if TYPE_CHECKING: witness_requests_count: "int", minting_asset_groups_count: "int", derivation_type: "CardanoDerivationType", + collateral_inputs_count: "int", + required_signers_count: "int", ttl: "int | None" = None, validity_interval_start: "int | None" = None, include_network_id: "bool | None" = None, @@ -1608,6 +1612,38 @@ if TYPE_CHECKING: def is_type_of(cls, msg: protobuf.MessageType) -> TypeGuard["CardanoTxMint"]: return isinstance(msg, cls) + class CardanoTxCollateralInput(protobuf.MessageType): + prev_hash: "bytes" + prev_index: "int" + + def __init__( + self, + *, + prev_hash: "bytes", + prev_index: "int", + ) -> None: + pass + + @classmethod + def is_type_of(cls, msg: protobuf.MessageType) -> TypeGuard["CardanoTxCollateralInput"]: + return isinstance(msg, cls) + + class CardanoTxRequiredSigner(protobuf.MessageType): + key_hash: "bytes | None" + key_path: "list[int]" + + def __init__( + self, + *, + key_path: "list[int] | None" = None, + key_hash: "bytes | None" = None, + ) -> None: + pass + + @classmethod + def is_type_of(cls, msg: protobuf.MessageType) -> TypeGuard["CardanoTxRequiredSigner"]: + return isinstance(msg, cls) + class CardanoTxItemAck(protobuf.MessageType): @classmethod diff --git a/core/tests/test_apps.cardano.certificate.py b/core/tests/test_apps.cardano.certificate.py index 3eb257f6b4..69ebc233d9 100644 --- a/core/tests/test_apps.cardano.certificate.py +++ b/core/tests/test_apps.cardano.certificate.py @@ -31,6 +31,15 @@ class TestCardanoCertificate(unittest.TestCase): ), CardanoTxSigningMode.MULTISIG_TRANSACTION, ), + ( + CardanoTxCertificate( + type=CardanoCertificateType.STAKE_REGISTRATION, + script_hash=unhexlify( + "29fb5fd4aa8cadd6705acc8263cee0fc62edca5ac38db593fec2f9fd" + ), + ), + CardanoTxSigningMode.PLUTUS_TRANSACTION, + ), ( CardanoTxCertificate( type=CardanoCertificateType.STAKE_DELEGATION, @@ -53,6 +62,18 @@ class TestCardanoCertificate(unittest.TestCase): ), CardanoTxSigningMode.MULTISIG_TRANSACTION, ), + ( + CardanoTxCertificate( + type=CardanoCertificateType.STAKE_DELEGATION, + script_hash=unhexlify( + "29fb5fd4aa8cadd6705acc8263cee0fc62edca5ac38db593fec2f9fd" + ), + pool=unhexlify( + "f61c42cbf7c8c53af3f520508212ad3e72f674f957fe23ff0acb4973" + ), + ), + CardanoTxSigningMode.PLUTUS_TRANSACTION, + ), ( CardanoTxCertificate( type=CardanoCertificateType.STAKE_DEREGISTRATION, @@ -69,6 +90,15 @@ class TestCardanoCertificate(unittest.TestCase): ), CardanoTxSigningMode.MULTISIG_TRANSACTION, ), + ( + CardanoTxCertificate( + type=CardanoCertificateType.STAKE_DEREGISTRATION, + script_hash=unhexlify( + "29fb5fd4aa8cadd6705acc8263cee0fc62edca5ac38db593fec2f9fd" + ), + ), + CardanoTxSigningMode.PLUTUS_TRANSACTION, + ), ( CardanoTxCertificate( type=CardanoCertificateType.STAKE_POOL_REGISTRATION, diff --git a/python/src/trezorlib/cardano.py b/python/src/trezorlib/cardano.py index 2861f9cb08..b4bf7b8e4e 100644 --- a/python/src/trezorlib/cardano.py +++ b/python/src/trezorlib/cardano.py @@ -36,12 +36,6 @@ if TYPE_CHECKING: from .client import TrezorClient from .protobuf import MessageType -SIGNING_MODE_IDS = { - "ORDINARY_TRANSACTION": messages.CardanoTxSigningMode.ORDINARY_TRANSACTION, - "POOL_REGISTRATION_AS_OWNER": messages.CardanoTxSigningMode.POOL_REGISTRATION_AS_OWNER, - "MULTISIG_TRANSACTION": messages.CardanoTxSigningMode.MULTISIG_TRANSACTION, -} - PROTOCOL_MAGICS = {"mainnet": 764824073, "testnet": 42} NETWORK_IDS = {"mainnet": 1, "testnet": 0} @@ -71,6 +65,7 @@ INVALID_OUTPUT_TOKEN_BUNDLE_ENTRY = "The output's token_bundle entry is invalid" INVALID_MINT_TOKEN_BUNDLE_ENTRY = "The mint token_bundle entry is invalid" InputWithPath = Tuple[messages.CardanoTxInput, List[int]] +CollateralInputWithPath = Tuple[messages.CardanoTxCollateralInput, List[int]] AssetGroupWithTokens = Tuple[messages.CardanoAssetGroup, List[messages.CardanoToken]] OutputWithAssetGroups = Tuple[messages.CardanoTxOutput, List[AssetGroupWithTokens]] OutputItem = Union[ @@ -541,6 +536,29 @@ def parse_script_data_hash(script_data_hash: Optional[str]) -> Optional[bytes]: return parse_optional_bytes(script_data_hash) +def parse_collateral_input(collateral_input: dict) -> CollateralInputWithPath: + if not all(k in collateral_input for k in REQUIRED_FIELDS_INPUT): + raise ValueError("The collateral input is missing some fields") + + path = tools.parse_path(collateral_input.get("path", "")) + return ( + messages.CardanoTxCollateralInput( + prev_hash=bytes.fromhex(collateral_input["prev_hash"]), + prev_index=collateral_input["prev_index"], + ), + path, + ) + + +def parse_required_signer(required_signer: dict) -> messages.CardanoTxRequiredSigner: + key_hash = parse_optional_bytes(required_signer.get("key_hash")) + key_path = tools.parse_path(required_signer.get("key_path", "")) + return messages.CardanoTxRequiredSigner( + key_hash=key_hash, + key_path=key_path, + ) + + def parse_additional_witness_request( additional_witness_request: dict, ) -> Path: @@ -554,6 +572,8 @@ def _get_witness_requests( inputs: Sequence[InputWithPath], certificates: Sequence[CertificateWithPoolOwnersAndRelays], withdrawals: Sequence[messages.CardanoTxWithdrawal], + collateral_inputs: Sequence[CollateralInputWithPath], + required_signers: Sequence[messages.CardanoTxRequiredSigner], additional_witness_requests: Sequence[Path], signing_mode: messages.CardanoTxSigningMode, ) -> List[messages.CardanoTxWitnessRequest]: @@ -587,7 +607,16 @@ def _get_witness_requests( if withdrawal.path: paths.add(tuple(withdrawal.path)) - # add additional_witness_requests in all cases + # gather Plutus-related paths + if signing_mode == messages.CardanoTxSigningMode.PLUTUS_TRANSACTION: + for _, path in collateral_inputs: + if path: + paths.add(tuple(path)) + for required_signer in required_signers: + if required_signer.key_path: + paths.add(tuple(required_signer.key_path)) + + # add additional_witness_requests in all cases (because of minting) for additional_witness_request in additional_witness_requests: paths.add(tuple(additional_witness_request)) @@ -620,12 +649,21 @@ def _get_certificate_items( def _get_mint_items(mint: Sequence[AssetGroupWithTokens]) -> Iterator[MintItem]: + if not mint: + return yield messages.CardanoTxMint(asset_groups_count=len(mint)) for asset_group, tokens in mint: yield asset_group yield from tokens +def _get_collateral_input_items( + collateral_inputs: Sequence[CollateralInputWithPath], +) -> Iterator[messages.CardanoTxCollateralInput]: + for collateral_input, _ in collateral_inputs: + yield collateral_input + + # ====== Client functions ====== # @@ -693,6 +731,8 @@ def sign_tx( auxiliary_data: Optional[messages.CardanoTxAuxiliaryData] = None, mint: Sequence[AssetGroupWithTokens] = (), script_data_hash: Optional[bytes] = None, + collateral_inputs: Sequence[CollateralInputWithPath] = (), + required_signers: Sequence[messages.CardanoTxRequiredSigner] = (), additional_witness_requests: Sequence[Path] = (), derivation_type: messages.CardanoDerivationType = messages.CardanoDerivationType.ICARUS, include_network_id: bool = False, @@ -700,7 +740,13 @@ def sign_tx( UNEXPECTED_RESPONSE_ERROR = exceptions.TrezorException("Unexpected response") witness_requests = _get_witness_requests( - inputs, certificates, withdrawals, additional_witness_requests, signing_mode + inputs, + certificates, + withdrawals, + collateral_inputs, + required_signers, + additional_witness_requests, + signing_mode, ) response = client.call( @@ -718,6 +764,8 @@ def sign_tx( has_auxiliary_data=auxiliary_data is not None, minting_asset_groups_count=len(mint), script_data_hash=script_data_hash, + collateral_inputs_count=len(collateral_inputs), + required_signers_count=len(required_signers), witness_requests_count=len(witness_requests), derivation_type=derivation_type, include_network_id=include_network_id, @@ -756,11 +804,14 @@ def sign_tx( if not isinstance(response, messages.CardanoTxItemAck): raise UNEXPECTED_RESPONSE_ERROR - if mint: - for mint_item in _get_mint_items(mint): - response = client.call(mint_item) - if not isinstance(response, messages.CardanoTxItemAck): - raise UNEXPECTED_RESPONSE_ERROR + for tx_item in chain( + _get_mint_items(mint), + _get_collateral_input_items(collateral_inputs), + required_signers, + ): + response = client.call(tx_item) + if not isinstance(response, messages.CardanoTxItemAck): + raise UNEXPECTED_RESPONSE_ERROR sign_tx_response["witnesses"] = [] for witness_request in witness_requests: diff --git a/python/src/trezorlib/cli/cardano.py b/python/src/trezorlib/cli/cardano.py index 85004dd049..b7d01c8036 100644 --- a/python/src/trezorlib/cli/cardano.py +++ b/python/src/trezorlib/cli/cardano.py @@ -90,6 +90,14 @@ def sign_tx( script_data_hash = cardano.parse_script_data_hash( transaction.get("script_data_hash") ) + collateral_inputs = [ + cardano.parse_collateral_input(collateral_input) + for collateral_input in transaction.get("collateral_inputs", ()) + ] + required_signers = [ + cardano.parse_required_signer(required_signer) + for required_signer in transaction.get("required_signers", ()) + ] additional_witness_requests = [ cardano.parse_additional_witness_request(p) for p in transaction["additional_witness_requests"] @@ -111,6 +119,8 @@ def sign_tx( auxiliary_data, mint, script_data_hash, + collateral_inputs, + required_signers, additional_witness_requests, derivation_type=derivation_type, include_network_id=include_network_id, diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py index 1b894b3ca3..e1305b8490 100644 --- a/python/src/trezorlib/messages.py +++ b/python/src/trezorlib/messages.py @@ -191,6 +191,8 @@ class MessageType(IntEnum): CardanoGetNativeScriptHash = 330 CardanoNativeScriptHash = 331 CardanoTxMint = 332 + CardanoTxCollateralInput = 333 + CardanoTxRequiredSigner = 334 RippleGetAddress = 400 RippleAddress = 401 RippleSignTx = 402 @@ -403,6 +405,7 @@ class CardanoTxSigningMode(IntEnum): ORDINARY_TRANSACTION = 0 POOL_REGISTRATION_AS_OWNER = 1 MULTISIG_TRANSACTION = 2 + PLUTUS_TRANSACTION = 3 class CardanoTxWitnessType(IntEnum): @@ -2246,6 +2249,8 @@ class CardanoSignTxInit(protobuf.MessageType): 14: protobuf.Field("derivation_type", "CardanoDerivationType", repeated=False, required=True), 15: protobuf.Field("include_network_id", "bool", repeated=False, required=False), 16: protobuf.Field("script_data_hash", "bytes", repeated=False, required=False), + 17: protobuf.Field("collateral_inputs_count", "uint32", repeated=False, required=True), + 18: protobuf.Field("required_signers_count", "uint32", repeated=False, required=True), } def __init__( @@ -2263,6 +2268,8 @@ class CardanoSignTxInit(protobuf.MessageType): witness_requests_count: "int", minting_asset_groups_count: "int", derivation_type: "CardanoDerivationType", + collateral_inputs_count: "int", + required_signers_count: "int", ttl: Optional["int"] = None, validity_interval_start: Optional["int"] = None, include_network_id: Optional["bool"] = False, @@ -2280,6 +2287,8 @@ class CardanoSignTxInit(protobuf.MessageType): self.witness_requests_count = witness_requests_count self.minting_asset_groups_count = minting_asset_groups_count self.derivation_type = derivation_type + self.collateral_inputs_count = collateral_inputs_count + self.required_signers_count = required_signers_count self.ttl = ttl self.validity_interval_start = validity_interval_start self.include_network_id = include_network_id @@ -2573,6 +2582,40 @@ class CardanoTxMint(protobuf.MessageType): self.asset_groups_count = asset_groups_count +class CardanoTxCollateralInput(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 333 + FIELDS = { + 1: protobuf.Field("prev_hash", "bytes", repeated=False, required=True), + 2: protobuf.Field("prev_index", "uint32", repeated=False, required=True), + } + + def __init__( + self, + *, + prev_hash: "bytes", + prev_index: "int", + ) -> None: + self.prev_hash = prev_hash + self.prev_index = prev_index + + +class CardanoTxRequiredSigner(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 334 + FIELDS = { + 1: protobuf.Field("key_hash", "bytes", repeated=False, required=False), + 2: protobuf.Field("key_path", "uint32", repeated=True, required=False), + } + + def __init__( + self, + *, + key_path: Optional[Sequence["int"]] = None, + key_hash: Optional["bytes"] = None, + ) -> None: + self.key_path: Sequence["int"] = key_path if key_path is not None else [] + self.key_hash = key_hash + + class CardanoTxItemAck(protobuf.MessageType): MESSAGE_WIRE_TYPE = 313 diff --git a/tests/device_tests/cardano/test_sign_tx.py b/tests/device_tests/cardano/test_sign_tx.py index f5f9153814..d71c393d19 100644 --- a/tests/device_tests/cardano/test_sign_tx.py +++ b/tests/device_tests/cardano/test_sign_tx.py @@ -33,6 +33,7 @@ pytestmark = [ "cardano/sign_tx_stake_pool_registration.json", "cardano/sign_tx.json", "cardano/sign_tx.multisig.json", + "cardano/sign_tx.plutus.json", "cardano/sign_tx.slip39.json", ) def test_cardano_sign_tx(client: Client, parameters, result): @@ -46,6 +47,12 @@ def test_cardano_sign_tx(client: Client, parameters, result): auxiliary_data = cardano.parse_auxiliary_data(parameters["auxiliary_data"]) mint = cardano.parse_mint(parameters["mint"]) script_data_hash = cardano.parse_script_data_hash(parameters["script_data_hash"]) + collateral_inputs = [ + cardano.parse_collateral_input(i) for i in parameters["collateral_inputs"] + ] + required_signers = [ + cardano.parse_required_signer(s) for s in parameters["required_signers"] + ] additional_witness_requests = [ cardano.parse_additional_witness_request(p) for p in parameters["additional_witness_requests"] @@ -74,6 +81,8 @@ def test_cardano_sign_tx(client: Client, parameters, result): auxiliary_data=auxiliary_data, mint=mint, script_data_hash=script_data_hash, + collateral_inputs=collateral_inputs, + required_signers=required_signers, additional_witness_requests=additional_witness_requests, include_network_id=parameters["include_network_id"], ) @@ -81,9 +90,10 @@ def test_cardano_sign_tx(client: Client, parameters, result): @parametrize_using_common_fixtures( + "cardano/sign_tx_stake_pool_registration.failed.json", "cardano/sign_tx.failed.json", "cardano/sign_tx.multisig.failed.json", - "cardano/sign_tx_stake_pool_registration.failed.json", + "cardano/sign_tx.plutus.failed.json", ) def test_cardano_sign_tx_failed(client: Client, parameters, result): client.init_device(new_session=True, derive_cardano=True) @@ -96,6 +106,12 @@ def test_cardano_sign_tx_failed(client: Client, parameters, result): auxiliary_data = cardano.parse_auxiliary_data(parameters["auxiliary_data"]) mint = cardano.parse_mint(parameters["mint"]) script_data_hash = cardano.parse_script_data_hash(parameters["script_data_hash"]) + collateral_inputs = [ + cardano.parse_collateral_input(i) for i in parameters["collateral_inputs"] + ] + required_signers = [ + cardano.parse_required_signer(s) for s in parameters["required_signers"] + ] additional_witness_requests = [ cardano.parse_additional_witness_request(p) for p in parameters["additional_witness_requests"] @@ -125,6 +141,8 @@ def test_cardano_sign_tx_failed(client: Client, parameters, result): auxiliary_data=auxiliary_data, mint=mint, script_data_hash=script_data_hash, + collateral_inputs=collateral_inputs, + required_signers=required_signers, additional_witness_requests=additional_witness_requests, include_network_id=parameters["include_network_id"], )