diff --git a/common/protob/messages-cardano.proto b/common/protob/messages-cardano.proto index 4c604ba57..c5a0dc04f 100644 --- a/common/protob/messages-cardano.proto +++ b/common/protob/messages-cardano.proto @@ -116,17 +116,19 @@ message CardanoPublicKey { * @next Failure */ message CardanoSignTx { - repeated CardanoTxInputType inputs = 1; // inputs to be used in transaction - repeated CardanoTxOutputType outputs = 2; // outputs to be used in transaction - // optional uint32 transactions_count = 3; // left as a comment so we know to skip the id 3 in the future - required uint32 protocol_magic = 5; // network's protocol magic - required uint64 fee = 6; // transaction fee - added in shelley - optional uint64 ttl = 7; // transaction ttl - added in shelley - required uint32 network_id = 8; // network id - mainnet or testnet - repeated CardanoTxCertificateType certificates = 9; // transaction certificates - added in shelley - repeated CardanoTxWithdrawalType withdrawals = 10; // transaction withdrawals - added in shelley - optional bytes metadata = 11; // transaction metadata - added in shelley - optional uint64 validity_interval_start = 12; // transaction validity start - added in allegra + repeated CardanoTxInputType inputs = 1; // inputs to be used in transaction + repeated CardanoTxOutputType outputs = 2; // outputs to be used in transaction + // optional uint32 transactions_count = 3; // left as a comment so we know to skip the id 3 in the future + // optional uint32 network = 4; // replaced with protocol_magic + required uint32 protocol_magic = 5; // network's protocol magic + required uint64 fee = 6; // transaction fee - added in shelley + optional uint64 ttl = 7; // transaction ttl - added in shelley + required uint32 network_id = 8; // network id - mainnet or testnet + repeated CardanoTxCertificateType certificates = 9; // transaction certificates - added in shelley + repeated CardanoTxWithdrawalType withdrawals = 10; // transaction withdrawals - added in shelley + // optional bytes metadata = 11; // replaced in Mary era with auxiliary data below + optional uint64 validity_interval_start = 12; // transaction validity start - added in allegra + optional CardanoTxAuxiliaryDataType auxiliary_data = 13; // transaction auxiliary data /** * Structure representing cardano transaction input @@ -218,6 +220,18 @@ message CardanoSignTx { repeated uint32 path = 1; required uint64 amount = 2; } + + message CardanoCatalystRegistrationParametersType { + required bytes voting_public_key = 1; + repeated uint32 staking_path = 2; + required CardanoAddressParametersType reward_address_parameters = 3; + required uint64 nonce = 4; + } + + message CardanoTxAuxiliaryDataType { + optional bytes blob = 1; + optional CardanoCatalystRegistrationParametersType catalyst_registration_parameters = 2; + } } /** diff --git a/common/tests/fixtures/cardano/sign_tx.chunked.json b/common/tests/fixtures/cardano/sign_tx.chunked.json index 227657a3c..728e9e8c9 100644 --- a/common/tests/fixtures/cardano/sign_tx.chunked.json +++ b/common/tests/fixtures/cardano/sign_tx.chunked.json @@ -13,7 +13,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { diff --git a/common/tests/fixtures/cardano/sign_tx.failed.json b/common/tests/fixtures/cardano/sign_tx.failed.json index 8f96fbd48..afc2367d2 100644 --- a/common/tests/fixtures/cardano/sign_tx.failed.json +++ b/common/tests/fixtures/cardano/sign_tx.failed.json @@ -13,7 +13,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/44'/1815'/0'/0/1", @@ -41,7 +41,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/44'/1815'/0'/0/1", @@ -69,7 +69,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/44'/1815'/0'/0/1", @@ -97,7 +97,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/44'/1815'/0'/0/1", @@ -125,7 +125,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -153,7 +153,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -181,7 +181,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/44'/1815'/0'/0/1", @@ -214,7 +214,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -242,7 +242,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/44'/1815'/0'/0/1", @@ -270,7 +270,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -298,7 +298,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -326,7 +326,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -354,7 +354,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -382,7 +382,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -412,7 +412,7 @@ {"type": 0, "path": "m/1852'/1815'/0'/0/0"} ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -446,7 +446,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -474,7 +474,7 @@ "ttl": 10, "certificates": [], "withdrawals": [{"path": "m/1852'/1815'/0'/0/0", "amount": "1000"}], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -505,7 +505,7 @@ "path": "m/1852'/1815'/0'/2/0", "amount": "449999999199999999" }], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -525,7 +525,7 @@ } }, { - "description": "Metadata too large", + "description": "Auxiliary data blob is incomplete", "parameters": { "protocol_magic": 764824073, "network_id": 1, @@ -533,7 +533,9 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "a200a11864a118c843aa00ff01a119012c590202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "auxiliary_data": { + "blob": "a200a11864a118c843aa00ff01" + }, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -549,11 +551,11 @@ ] }, "result": { - "error_message": "Invalid metadata" + "error_message": "Invalid auxiliary data" } }, { - "description": "Metadata is a list", + "description": "Auxiliary data blob has leftover data", "parameters": { "protocol_magic": 764824073, "network_id": 1, @@ -561,7 +563,9 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "82a200a11864a118c843aa00ff01a119012c590100aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0A", + "auxiliary_data": { + "blob": "a200a11864a118c843aa00ff01a119012c590100aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa000000" + }, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -577,11 +581,11 @@ ] }, "result": { - "error_message": "Invalid metadata" + "error_message": "Invalid auxiliary data" } }, { - "description": "Metadata is incomplete", + "description": "transaction with catalyst registration containing byron reward address", "parameters": { "protocol_magic": 764824073, "network_id": 1, @@ -589,27 +593,37 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "a200a11864a118c843aa00ff01", + "auxiliary_data": { + "catalyst_registration_parameters": { + "voting_public_key": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "staking_path": "m/1852'/1815'/0'/2/0", + "nonce": 22634813, + "reward_address_parameters": { + "addressType": 8, + "path": "m/44'/1815'/0'/0/0" + } + } + }, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", - "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", "prev_index": 0 } ], "outputs": [ { - "address": "Ae2tdPwUPEZCanmBz5g2GEwFqKTKpNJcGYPKfDxoNeKZ8bRHr8366kseiK2", - "amount": "3003112" + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" } ] }, "result": { - "error_message": "Invalid metadata" + "error_message": "Invalid auxiliary data" } }, { - "description": "Metadata has leftover data", + "description": "transaction with both auxiliary data blob and catalyst registration", "parameters": { "protocol_magic": 764824073, "network_id": 1, @@ -617,23 +631,35 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "a200a11864a118c843aa00ff01a119012c590100aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa000000", + "auxiliary_data": { + "blob": "a200a11864a118c843aa00ff01a119012c590100aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "catalyst_registration_parameters": { + "voting_public_key": "38DA0B509D45BF6C87BD55594B92F97081D3923B8C1334B9B8D0BF13FC1C12D0", + "staking_path": "m/1852'/1815'/0'/2/0", + "reward_address_parameters": { + "addressType": 0, + "path": "m/1852'/1815'/0'/0/0", + "stakingPath": "m/1852'/1815'/0'/2/0" + }, + "nonce": 140 + } + }, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", - "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", "prev_index": 0 } ], "outputs": [ { - "address": "Ae2tdPwUPEZCanmBz5g2GEwFqKTKpNJcGYPKfDxoNeKZ8bRHr8366kseiK2", - "amount": "3003112" + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" } ] }, "result": { - "error_message": "Invalid metadata" + "error_message": "Invalid auxiliary data" } }, { @@ -645,7 +671,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"]], "inputs": [ { @@ -680,7 +706,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"]], "inputs": [ { @@ -720,7 +746,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"]], "inputs": [ { @@ -749,7 +775,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -792,7 +818,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", diff --git a/common/tests/fixtures/cardano/sign_tx.json b/common/tests/fixtures/cardano/sign_tx.json index 3badaea7b..e724650e2 100644 --- a/common/tests/fixtures/cardano/sign_tx.json +++ b/common/tests/fixtures/cardano/sign_tx.json @@ -13,7 +13,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -43,7 +43,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -78,7 +78,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -114,7 +114,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -159,7 +159,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -196,7 +196,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -233,7 +233,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -269,7 +269,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -305,7 +305,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -343,7 +343,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -383,7 +383,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -418,7 +418,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -454,7 +454,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -486,7 +486,7 @@ {"type": 1, "path": "m/1852'/1815'/0'/2/0"} ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -526,7 +526,7 @@ "amount": "1000" } ], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["YES"], ["YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -562,7 +562,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["YES"], ["YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -584,7 +584,7 @@ } }, { - "description": "transaction with metadata", + "description": "transaction with auxiliary data blob", "parameters": { "protocol_magic": 764824073, "network_id": 1, @@ -592,8 +592,10 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "a200a11864a118c843aa00ff01a119012c590100aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "input_flow": [["SWIPE", "YES"], ["SWIPE", "YES"]], + "auxiliary_data": { + "blob": "a200a11864a118c843aa00ff01a119012c590100aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }, + "input_flow": [["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]], "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -613,6 +615,47 @@ "serialized_tx": "83a500818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018182583901eb0baa5e570cffbe2934db29df0b6a3d7c0430ee65d4c3a7ab2fefb91bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff0102182a030a075820ea4c91860dd5ec5449f8f985d227946ff39086b17f10b5afb93d12ee87050b6aa100818258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c15840b2015772a91043aeb04b98111744a098afdade0db5e30206538d7f2814965a5800d45240137f4d0dc81845a71e67cda38beaf816a520d73c4decbf7cbf0f6d08a200a11864a118c843aa00ff01a119012c590100aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" } }, + { + "description": "transaction with catalyst registration", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "certificates": [], + "withdrawals": [], + "auxiliary_data": { + "catalyst_registration_parameters": { + "voting_public_key": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "staking_path": "m/1852'/1815'/0'/2/0", + "reward_address_parameters": { + "addressType": 0, + "path": "m/1852'/1815'/0'/0/0", + "stakingPath": "m/1852'/1815'/0'/2/0" + }, + "nonce": 22634813 + } + }, + "input_flow": [["SWIPE", "SWIPE", "YES"], ["SWIPE", "SWIPE", "SWIPE", "SWIPE", "SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]], + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ] + }, + "result": { + "tx_hash": "839a587109358e0aa81b8fb3d5fa74665fac303425ec544a4db7f6ba4e882dff", + "serialized_tx": "83a500818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018182583901eb0baa5e570cffbe2934db29df0b6a3d7c0430ee65d4c3a7ab2fefb91bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff0102182a030a075820a943e9166f1bb6d767b175384d3bd7d23645170df36fc1861fbf344135d8e120a100818258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c15840187ecd899e01390272a8d8289088199b3453945fa076819b5b5df60c325c10315477cc801044dfb553e780a300d79627ef5c09e64c6f953cc33bbc59152c900282a219ef64a40158201af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc025820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e0358390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277041a0159613d19ef65a101584074f27d877bbb4a5fc4f7c56869905c11f70bad0af3de24b23afaa1d024e750930f434ecc4b73e5d1723c2cb8548e8bf6098ac876487b3a6ed0891cb76994d40980" + } + }, { "description": "Testnet transaction", "parameters": { @@ -622,7 +665,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "YES"], ["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -662,7 +705,7 @@ "validity_interval_start": 47, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["YES"], ["SWIPE", "YES"], ["SWIPE", "SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -710,7 +753,7 @@ "validity_interval_start": 47, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"], ["SWIPE", "YES"], ["SWIPE", "SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -769,7 +812,7 @@ "fee": 42, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["YES"]], "inputs": [ { @@ -800,7 +843,7 @@ "fee": 42, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["YES"], ["YES"]], "inputs": [ { diff --git a/common/tests/fixtures/cardano/sign_tx.slip39.json b/common/tests/fixtures/cardano/sign_tx.slip39.json index 6be485b70..4e0d296a7 100644 --- a/common/tests/fixtures/cardano/sign_tx.slip39.json +++ b/common/tests/fixtures/cardano/sign_tx.slip39.json @@ -17,7 +17,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -47,7 +47,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["YES"], ["YES"], ["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]], "inputs": [ { @@ -82,7 +82,7 @@ "ttl": 10, "certificates": [], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["YES"], ["YES"], ["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]], "inputs": [ { 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 b0d4c19cb..dd33bb2be 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 @@ -35,7 +35,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", @@ -87,7 +87,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", @@ -136,7 +136,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", @@ -185,7 +185,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", @@ -238,7 +238,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", @@ -292,7 +292,7 @@ "amount": "1000" } ], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", @@ -340,7 +340,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "path": "m/1852'/1815'/0'/0/0", @@ -389,7 +389,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", @@ -437,7 +437,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "inputs": [ { "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", @@ -518,7 +518,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "SWIPE", "YES"]], "inputs": [ { 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 a1b4271b5..a3c93a4b8 100644 --- a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json +++ b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json @@ -67,7 +67,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "SWIPE", "YES"], ["SWIPE", "YES"], ["SWIPE", "YES"], ["YES"], ["YES"]], "inputs": [ { @@ -151,7 +151,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "SWIPE", "YES"], ["SWIPE", "YES"], ["SWIPE", "YES"], ["YES"], ["YES"]], "inputs": [ { @@ -236,7 +236,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "SWIPE", "YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"], ["YES"], ["YES"]], "inputs": [ { @@ -287,7 +287,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "SWIPE", "YES"], ["YES"], ["YES"], ["YES"], ["YES"]], "inputs": [ { @@ -338,7 +338,7 @@ } ], "withdrawals": [], - "metadata": "", + "auxiliary_data": null, "input_flow": [["SWIPE", "SWIPE", "YES"], ["YES"], ["YES"], ["YES"], ["YES"]], "inputs": [ { @@ -358,6 +358,93 @@ "tx_hash": "12921b4f8e77f815e0c8ed97c541fbd5ba38a6d3323f4ff1af0cb934b8ac6b39", "serialized_tx": "83a500818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018182581d60cb03849e268f989b5a843107bad7fa2908246986a8f3d643f8c184800102182a030a04818a03581cf61c42cbf7c8c53af3f520508212ad3e72f674f957fe23ff0acb49735820198890ad6c92e80fbdab554dda02da9fb49d001bbd96181f3e07f7a6ab0d06401a1dcd65001a1443fd00d81e820102581de03a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c49071181581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b427780f6a10081825820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e584027cab81902d04b2491d7aa2bf57bd9db59d33c2df1502dae0412d5225c6b0b8f7b057de6a7e7eae25016ed6ea1f6e6239fb36a285216c6ee4a3cb3376287a300f6" } + }, + { + "description": "Sample stake pool registration certificate with auxiliary data", + "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": { + "type": 0, + "blob": "a200a11864a118c843aa00ff01a119012c590100aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }, + "input_flow": [["SWIPE", "SWIPE", "YES"], ["SWIPE", "YES"], ["SWIPE", "YES"], ["YES"], ["YES"], ["YES"]], + "inputs": [ + { + "path": null, + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ] + }, + "result": { + "tx_hash": "880fafab19a36407e9af300c2905e2f6bc8a8debd8b625005f56994d242ba460", + "serialized_tx": "83a600818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018182583901eb0baa5e570cffbe2934db29df0b6a3d7c0430ee65d4c3a7ab2fefb91bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff0102182a030a04818a03581cf61c42cbf7c8c53af3f520508212ad3e72f674f957fe23ff0acb49735820198890ad6c92e80fbdab554dda02da9fb49d001bbd96181f3e07f7a6ab0d06401a1dcd65001a1443fd00d81e820102581de13a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c49071182581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277581c3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c4907118584001904d244c0a8000150b80d01200000a3852e8a00003473700384001904d2f650b80d01200000a3852e8a00003473700384001904d244c0a80001f683011904d26d7777772e746573742e7465737482026e7777772e74657374322e74657374827568747470733a2f2f7777772e746573742e746573745820914c57c1f12bbf4a82b12d977d4f274674856a11ed4b9b95bd70f5d41c5064a6075820ea4c91860dd5ec5449f8f985d227946ff39086b17f10b5afb93d12ee87050b6aa10081825820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e584073dbc58bd6f6bc0d91a2b5852706dde05da7acbfde035481b88b1219518ea8609dc045ea3309b1ffb01830ec64578e80c70db37a1041e72d52649be20ff80009a200a11864a118c843aa00ff01a119012c590100aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } } ] } diff --git a/core/src/apps/cardano/README.md b/core/src/apps/cardano/README.md index 02b0faa76..fc52f89bc 100644 --- a/core/src/apps/cardano/README.md +++ b/core/src/apps/cardano/README.md @@ -20,8 +20,6 @@ REVIEWER = Jan Matejek , Tomas Susanka None: + if not auxiliary_data: + return + + fields_provided = 0 + if auxiliary_data.blob: + fields_provided += 1 + _validate_auxiliary_data_blob(auxiliary_data.blob) + if auxiliary_data.catalyst_registration_parameters: + fields_provided += 1 + _validate_catalyst_registration_parameters( + keychain, + auxiliary_data.catalyst_registration_parameters, + protocol_magic, + network_id, + ) + + if fields_provided != 1: + raise INVALID_AUXILIARY_DATA + + +def _validate_auxiliary_data_blob(auxiliary_data_blob: bytes) -> None: + try: + # validation to prevent CBOR injection and invalid CBOR + # we don't validate data format, just that it's a valid CBOR + cbor.decode(auxiliary_data_blob) + except Exception: + raise INVALID_AUXILIARY_DATA + + +def _validate_catalyst_registration_parameters( + keychain: seed.Keychain, + catalyst_registration_parameters: CardanoCatalystRegistrationParametersType, + protocol_magic: int, + network_id: int, +) -> None: + if ( + len(catalyst_registration_parameters.voting_public_key) + != CATALYST_VOTING_PUBLIC_KEY_LENGTH + ): + raise INVALID_AUXILIARY_DATA + + if not SCHEMA_STAKING_ANY_ACCOUNT.match( + catalyst_registration_parameters.staking_path + ): + raise INVALID_AUXILIARY_DATA + + address_parameters = catalyst_registration_parameters.reward_address_parameters + if address_parameters.address_type == CardanoAddressType.BYRON: + raise INVALID_AUXILIARY_DATA + + # try to derive the address to validate it + derive_address_bytes(keychain, address_parameters, protocol_magic, network_id) + + +async def show_auxiliary_data( + ctx: wire.Context, + keychain: seed.Keychain, + auxiliary_data: CardanoTxAuxiliaryDataType | None, + protocol_magic: int, + network_id: int, +) -> None: + if not auxiliary_data: + return + + if auxiliary_data.catalyst_registration_parameters: + await _show_catalyst_registration( + ctx, + keychain, + auxiliary_data.catalyst_registration_parameters, + protocol_magic, + network_id, + ) + + auxiliary_data_bytes = get_auxiliary_data_cbor( + keychain, auxiliary_data, protocol_magic, network_id + ) + + auxiliary_data_hash = hash_auxiliary_data(bytes(auxiliary_data_bytes)) + await show_auxiliary_data_hash(ctx, auxiliary_data_hash) + + +async def _show_catalyst_registration( + ctx: wire.Context, + keychain: seed.Keychain, + catalyst_registration_parameters: CardanoCatalystRegistrationParametersType, + protocol_magic: int, + network_id: int, +) -> None: + public_key = catalyst_registration_parameters.voting_public_key + encoded_public_key = bech32.encode(HRP_JORMUN_PUBLIC_KEY, public_key) + staking_path = catalyst_registration_parameters.staking_path + reward_address = derive_human_readable_address( + keychain, + catalyst_registration_parameters.reward_address_parameters, + protocol_magic, + network_id, + ) + nonce = catalyst_registration_parameters.nonce + + await confirm_catalyst_registration( + ctx, encoded_public_key, staking_path, reward_address, nonce + ) + + +def get_auxiliary_data_cbor( + keychain: seed.Keychain, + auxiliary_data: CardanoTxAuxiliaryDataType, + protocol_magic: int, + network_id: int, +) -> bytes: + if auxiliary_data.blob: + return auxiliary_data.blob + elif auxiliary_data.catalyst_registration_parameters: + cborized_catalyst_registration = _cborize_catalyst_registration( + keychain, + auxiliary_data.catalyst_registration_parameters, + protocol_magic, + network_id, + ) + return cbor.encode(_wrap_metadata(cborized_catalyst_registration)) + else: + raise INVALID_AUXILIARY_DATA + + +def _cborize_catalyst_registration( + keychain: seed.Keychain, + catalyst_registration_parameters: CardanoCatalystRegistrationParametersType, + protocol_magic: int, + network_id: int, +) -> CatalystRegistration: + staking_node = keychain.derive(catalyst_registration_parameters.staking_path) + staking_key = remove_ed25519_prefix(staking_node.public_key()) + + catalyst_registration_payload: CatalystRegistrationPayload = { + 1: catalyst_registration_parameters.voting_public_key, + 2: staking_key, + 3: derive_address_bytes( + keychain, + catalyst_registration_parameters.reward_address_parameters, + protocol_magic, + network_id, + ), + 4: catalyst_registration_parameters.nonce, + } + + catalyst_registration_payload_signature = ( + _create_catalyst_registration_payload_signature( + keychain, + catalyst_registration_payload, + catalyst_registration_parameters.staking_path, + ) + ) + catalyst_registration_signature = {1: catalyst_registration_payload_signature} + + return { + METADATA_KEY_CATALYST_REGISTRATION: catalyst_registration_payload, + METADATA_KEY_CATALYST_REGISTRATION_SIGNATURE: catalyst_registration_signature, + } + + +def _create_catalyst_registration_payload_signature( + keychain: seed.Keychain, + catalyst_registration_payload: CatalystRegistrationPayload, + path: list[int], +) -> bytes: + node = keychain.derive(path) + + encoded_catalyst_registration = cbor.encode( + {METADATA_KEY_CATALYST_REGISTRATION: catalyst_registration_payload} + ) + + catalyst_registration_hash = hashlib.blake2b( + data=encoded_catalyst_registration, + outlen=CATALYST_REGISTRATION_HASH_SIZE, + ).digest() + + return ed25519.sign_ext( + node.private_key(), node.private_key_ext(), catalyst_registration_hash + ) + + +def _wrap_metadata(metadata: dict) -> tuple[dict, tuple]: + """ + A new structure of metadata is used after Cardano Mary era. The metadata + is wrapped in a tuple and auxiliary_scripts may follow it. Cardano + tooling uses this new format of "wrapped" metadata even if no + auxiliary_scripts are included. So we do the same here. + + https://github.com/input-output-hk/cardano-ledger-specs/blob/f7deb22be14d31b535f56edc3ca542c548244c67/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L212 + """ + return metadata, () + + +def hash_auxiliary_data(auxiliary_data: bytes) -> bytes: + return hashlib.blake2b( + data=auxiliary_data, outlen=AUXILIARY_DATA_HASH_SIZE + ).digest() diff --git a/core/src/apps/cardano/helpers/__init__.py b/core/src/apps/cardano/helpers/__init__.py index 3d1e34742..31b6b11c3 100644 --- a/core/src/apps/cardano/helpers/__init__.py +++ b/core/src/apps/cardano/helpers/__init__.py @@ -5,7 +5,7 @@ NETWORK_MISMATCH = wire.ProcessError("Output address network mismatch!") INVALID_CERTIFICATE = wire.ProcessError("Invalid certificate") INVALID_WITHDRAWAL = wire.ProcessError("Invalid withdrawal") INVALID_TOKEN_BUNDLE_OUTPUT = wire.ProcessError("Invalid token bundle in output") -INVALID_METADATA = wire.ProcessError("Invalid metadata") +INVALID_AUXILIARY_DATA = wire.ProcessError("Invalid auxiliary data") INVALID_STAKE_POOL_REGISTRATION_TX_STRUCTURE = wire.ProcessError( "Stakepool registration transaction cannot contain other certificates nor withdrawals" ) diff --git a/core/src/apps/cardano/helpers/bech32.py b/core/src/apps/cardano/helpers/bech32.py index 3850b633f..4a35e29be 100644 --- a/core/src/apps/cardano/helpers/bech32.py +++ b/core/src/apps/cardano/helpers/bech32.py @@ -2,10 +2,13 @@ from trezor.crypto import bech32 HRP_SEPARATOR = "1" +# CIP-0005 prefixes - https://github.com/cardano-foundation/CIPs/blob/master/CIP-0005/CIP-0005.md HRP_ADDRESS = "addr" HRP_TESTNET_ADDRESS = "addr_test" HRP_REWARD_ADDRESS = "stake" HRP_TESTNET_REWARD_ADDRESS = "stake_test" +# Jormungandr public key prefix - https://github.com/input-output-hk/voting-tools-lib/blob/18dae637e80db72444476606ab264b973bcf1a9d/src/Cardano/API/Extended.hs#L226 +HRP_JORMUN_PUBLIC_KEY = "ed25519_pk" def encode(hrp: str, data: bytes) -> str: diff --git a/core/src/apps/cardano/layout.py b/core/src/apps/cardano/layout.py index 6106244b3..f21d225eb 100644 --- a/core/src/apps/cardano/layout.py +++ b/core/src/apps/cardano/layout.py @@ -215,7 +215,6 @@ async def confirm_transaction( protocol_magic: int, ttl: int | None, validity_interval_start: int | None, - has_metadata: bool, is_network_id_verifiable: bool, ) -> None: pages: list[ui.Component] = [] @@ -235,12 +234,6 @@ async def confirm_transaction( page2.normal("TTL: %s" % format_optional_int(ttl)) pages.append(page2) - if has_metadata: - page3 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) - page3.normal("Transaction contains") - page3.normal("metadata") - pages.append(page3) - await require_hold_to_confirm(ctx, Paginated(pages)) @@ -393,6 +386,69 @@ async def confirm_withdrawal( await require_confirm(ctx, page1) +async def confirm_catalyst_registration( + ctx: wire.Context, + public_key: str, + staking_path: list[int], + reward_address: str, + nonce: int, +) -> None: + pages: list[ui.Component] = [] + + page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) + page1.bold("Catalyst voting key") + page1.bold("registration") + pages.append(page1) + + page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) + page2.normal("Voting public key:") + page2.bold(*chunks(public_key, 17)) + pages.append(page2) + + page3 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) + page3.normal("Staking key for") + page3.normal("account %s:" % format_account_number(staking_path)) + page3.bold(address_n_to_str(staking_path)) + pages.append(page3) + + page4 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) + page4.normal("Rewards go to:") + + lines_per_page = 5 + lines_used_on_first_page = 1 + address_lines = list(chunks(reward_address, 17)) + + for address_line in address_lines[: lines_per_page - lines_used_on_first_page]: + page4.bold(address_line) + pages.append(page4) + + pages.extend( + _paginate_lines( + address_lines, + lines_per_page - lines_used_on_first_page, + "Confirm transaction", + ui.ICON_SEND, + 5, + ) + ) + + last_page = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) + last_page.normal("Nonce: %s" % nonce) + pages.append(last_page) + + await require_confirm(ctx, Paginated(pages)) + + +async def show_auxiliary_data_hash( + ctx: wire.Context, auxiliary_data_hash: bytes +) -> None: + page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) + page1.normal("Auxiliary data hash:") + page1.bold(hexlify(auxiliary_data_hash).decode()) + + await require_confirm(ctx, page1) + + async def show_address( ctx: wire.Context, address: str, diff --git a/core/src/apps/cardano/sign_tx.py b/core/src/apps/cardano/sign_tx.py index ba58ee0e0..26f81b6f6 100644 --- a/core/src/apps/cardano/sign_tx.py +++ b/core/src/apps/cardano/sign_tx.py @@ -18,10 +18,15 @@ from .address import ( get_address_bytes_unsafe, validate_output_address, ) +from .auxiliary_data import ( + get_auxiliary_data_cbor, + hash_auxiliary_data, + show_auxiliary_data, + validate_auxiliary_data, +) from .byron_address import get_address_attributes from .certificates import cborize_certificate, validate_certificate from .helpers import ( - INVALID_METADATA, INVALID_STAKE_POOL_REGISTRATION_TX_STRUCTURE, INVALID_STAKEPOOL_REGISTRATION_TX_INPUTS, INVALID_TOKEN_BUNDLE_OUTPUT, @@ -83,9 +88,7 @@ if False: CborizedSignedTx = tuple[dict, dict, Optional[cbor.Raw]] TxHash = bytes -METADATA_HASH_SIZE = 32 MINTING_POLICY_ID_LENGTH = 28 -MAX_METADATA_LENGTH = 500 MAX_ASSET_NAME_LENGTH = 32 MAX_TX_CHUNK_SIZE = 256 @@ -132,7 +135,9 @@ async def _sign_ordinary_tx( _validate_outputs(keychain, msg.outputs, msg.protocol_magic, msg.network_id) _validate_certificates(msg.certificates, msg.protocol_magic, msg.network_id) _validate_withdrawals(msg.withdrawals) - _validate_metadata(msg.metadata) + validate_auxiliary_data( + keychain, msg.auxiliary_data, msg.protocol_magic, msg.network_id + ) # display the transaction in UI await _show_standard_tx(ctx, keychain, msg) @@ -160,7 +165,9 @@ async def _sign_stake_pool_registration_tx( _ensure_no_signing_inputs(msg.inputs) _validate_outputs(keychain, msg.outputs, msg.protocol_magic, msg.network_id) _validate_certificates(msg.certificates, msg.protocol_magic, msg.network_id) - _validate_metadata(msg.metadata) + validate_auxiliary_data( + keychain, msg.auxiliary_data, msg.protocol_magic, msg.network_id + ) await _show_stake_pool_registration_tx(ctx, keychain, msg) @@ -274,23 +281,6 @@ def _validate_withdrawals(withdrawals: list[CardanoTxWithdrawalType]) -> None: raise INVALID_WITHDRAWAL -def _validate_metadata(metadata: bytes | None) -> None: - if not metadata: - return - - if len(metadata) > MAX_METADATA_LENGTH: - raise INVALID_METADATA - - try: - # this also raises an error if there's some data remaining - decoded = cbor.decode(metadata) - except Exception: - raise INVALID_METADATA - - if not isinstance(decoded, dict): - raise INVALID_METADATA - - def _cborize_signed_tx( keychain: seed.Keychain, msg: CardanoSignTx ) -> tuple[CborizedSignedTx, TxHash]: @@ -306,11 +296,14 @@ def _cborize_signed_tx( msg.protocol_magic, ) - metadata = None - if msg.metadata: - metadata = cbor.Raw(bytes(msg.metadata)) + auxiliary_data = None + if msg.auxiliary_data: + auxiliary_data_cbor = get_auxiliary_data_cbor( + keychain, msg.auxiliary_data, msg.protocol_magic, msg.network_id + ) + auxiliary_data = cbor.Raw(auxiliary_data_cbor) - return (tx_body, witnesses, metadata), tx_hash + return (tx_body, witnesses, auxiliary_data), tx_hash def _cborize_tx_body(keychain: seed.Keychain, msg: CardanoSignTx) -> dict: @@ -340,8 +333,11 @@ def _cborize_tx_body(keychain: seed.Keychain, msg: CardanoSignTx) -> dict: # tx_body[6] is for protocol updates, which we don't support - if msg.metadata: - tx_body[7] = _hash_metadata(bytes(msg.metadata)) + if msg.auxiliary_data: + auxiliary_data_cbor = get_auxiliary_data_cbor( + keychain, msg.auxiliary_data, msg.protocol_magic, msg.network_id + ) + tx_body[7] = hash_auxiliary_data(bytes(auxiliary_data_cbor)) if msg.validity_interval_start: tx_body[8] = msg.validity_interval_start @@ -432,10 +428,6 @@ def _cborize_withdrawals( return result -def _hash_metadata(metadata: bytes) -> bytes: - return hashlib.blake2b(data=metadata, outlen=METADATA_HASH_SIZE).digest() - - def _hash_tx_body(tx_body: dict) -> bytes: tx_body_cbor_chunks = cbor.encode_streamed(tx_body) @@ -573,7 +565,10 @@ async def _show_standard_tx( for withdrawal in msg.withdrawals: await confirm_withdrawal(ctx, withdrawal) - has_metadata = bool(msg.metadata) + await show_auxiliary_data( + ctx, keychain, msg.auxiliary_data, msg.protocol_magic, msg.network_id + ) + await confirm_transaction( ctx=ctx, amount=total_amount, @@ -581,7 +576,6 @@ async def _show_standard_tx( protocol_magic=msg.protocol_magic, ttl=msg.ttl, validity_interval_start=msg.validity_interval_start, - has_metadata=has_metadata, is_network_id_verifiable=is_network_id_verifiable, ) @@ -616,6 +610,9 @@ async def _show_stake_pool_registration_tx( await confirm_transaction_network_ttl( ctx, msg.protocol_magic, msg.ttl, msg.validity_interval_start ) + await show_auxiliary_data( + ctx, keychain, msg.auxiliary_data, msg.protocol_magic, msg.network_id + ) await confirm_stake_pool_registration_final(ctx) diff --git a/core/src/trezor/messages/CardanoCatalystRegistrationParametersType.py b/core/src/trezor/messages/CardanoCatalystRegistrationParametersType.py new file mode 100644 index 000000000..87733d3b9 --- /dev/null +++ b/core/src/trezor/messages/CardanoCatalystRegistrationParametersType.py @@ -0,0 +1,37 @@ +# Automatically generated by pb2py +# fmt: off +import protobuf as p + +from .CardanoAddressParametersType import CardanoAddressParametersType + +if __debug__: + try: + from typing import Dict, List, Optional # noqa: F401 + from typing_extensions import Literal # noqa: F401 + except ImportError: + pass + + +class CardanoCatalystRegistrationParametersType(p.MessageType): + + def __init__( + self, + *, + voting_public_key: bytes, + reward_address_parameters: CardanoAddressParametersType, + nonce: int, + staking_path: Optional[List[int]] = None, + ) -> None: + self.staking_path = staking_path if staking_path is not None else [] + self.voting_public_key = voting_public_key + self.reward_address_parameters = reward_address_parameters + self.nonce = nonce + + @classmethod + def get_fields(cls) -> Dict: + return { + 1: ('voting_public_key', p.BytesType, p.FLAG_REQUIRED), + 2: ('staking_path', p.UVarintType, p.FLAG_REPEATED), + 3: ('reward_address_parameters', CardanoAddressParametersType, p.FLAG_REQUIRED), + 4: ('nonce', p.UVarintType, p.FLAG_REQUIRED), + } diff --git a/core/src/trezor/messages/CardanoSignTx.py b/core/src/trezor/messages/CardanoSignTx.py index a665d9e5f..cbcf0f43d 100644 --- a/core/src/trezor/messages/CardanoSignTx.py +++ b/core/src/trezor/messages/CardanoSignTx.py @@ -2,6 +2,7 @@ # fmt: off import protobuf as p +from .CardanoTxAuxiliaryDataType import CardanoTxAuxiliaryDataType from .CardanoTxCertificateType import CardanoTxCertificateType from .CardanoTxInputType import CardanoTxInputType from .CardanoTxOutputType import CardanoTxOutputType @@ -29,8 +30,8 @@ class CardanoSignTx(p.MessageType): certificates: Optional[List[CardanoTxCertificateType]] = None, withdrawals: Optional[List[CardanoTxWithdrawalType]] = None, ttl: Optional[int] = None, - metadata: Optional[bytes] = None, validity_interval_start: Optional[int] = None, + auxiliary_data: Optional[CardanoTxAuxiliaryDataType] = None, ) -> None: self.inputs = inputs if inputs is not None else [] self.outputs = outputs if outputs is not None else [] @@ -40,8 +41,8 @@ class CardanoSignTx(p.MessageType): self.fee = fee self.network_id = network_id self.ttl = ttl - self.metadata = metadata self.validity_interval_start = validity_interval_start + self.auxiliary_data = auxiliary_data @classmethod def get_fields(cls) -> Dict: @@ -54,6 +55,6 @@ class CardanoSignTx(p.MessageType): 8: ('network_id', p.UVarintType, p.FLAG_REQUIRED), 9: ('certificates', CardanoTxCertificateType, p.FLAG_REPEATED), 10: ('withdrawals', CardanoTxWithdrawalType, p.FLAG_REPEATED), - 11: ('metadata', p.BytesType, None), 12: ('validity_interval_start', p.UVarintType, None), + 13: ('auxiliary_data', CardanoTxAuxiliaryDataType, None), } diff --git a/core/src/trezor/messages/CardanoTxAuxiliaryDataType.py b/core/src/trezor/messages/CardanoTxAuxiliaryDataType.py index 47e99c566..23c127ffe 100644 --- a/core/src/trezor/messages/CardanoTxAuxiliaryDataType.py +++ b/core/src/trezor/messages/CardanoTxAuxiliaryDataType.py @@ -2,13 +2,14 @@ # fmt: off import protobuf as p -from .CardanoTxMetadataType import CardanoTxMetadataType +from .CardanoCatalystRegistrationParametersType import ( + CardanoCatalystRegistrationParametersType, +) if __debug__: try: from typing import Dict, List, Optional # noqa: F401 from typing_extensions import Literal # noqa: F401 - EnumTypeCardanoAuxiliaryDataType = Literal[0, 1] except ImportError: pass @@ -18,18 +19,15 @@ class CardanoTxAuxiliaryDataType(p.MessageType): def __init__( self, *, - type: EnumTypeCardanoAuxiliaryDataType, blob: Optional[bytes] = None, - metadata: Optional[CardanoTxMetadataType] = None, + catalyst_registration_parameters: Optional[CardanoCatalystRegistrationParametersType] = None, ) -> None: - self.type = type self.blob = blob - self.metadata = metadata + self.catalyst_registration_parameters = catalyst_registration_parameters @classmethod def get_fields(cls) -> Dict: return { - 1: ('type', p.EnumType("CardanoAuxiliaryDataType", (0, 1,)), p.FLAG_REQUIRED), - 2: ('blob', p.BytesType, None), - 3: ('metadata', CardanoTxMetadataType, None), + 1: ('blob', p.BytesType, None), + 2: ('catalyst_registration_parameters', CardanoCatalystRegistrationParametersType, None), } diff --git a/python/src/trezorlib/cardano.py b/python/src/trezorlib/cardano.py index 89e22a2af..ccbde9104 100644 --- a/python/src/trezorlib/cardano.py +++ b/python/src/trezorlib/cardano.py @@ -38,6 +38,12 @@ REQUIRED_FIELDS_POOL_PARAMETERS = ( REQUIRED_FIELDS_WITHDRAWAL = ("path", "amount") REQUIRED_FIELDS_TOKEN_GROUP = ("policy_id", "tokens") REQUIRED_FIELDS_TOKEN = ("asset_name_bytes", "amount") +REQUIRED_FIELDS_CATALYST_REGISTRATION = ( + "voting_public_key", + "staking_path", + "nonce", + "reward_address_parameters", +) INCOMPLETE_OUTPUT_ERROR_MESSAGE = "The output is missing some fields" @@ -118,7 +124,7 @@ def create_output(output) -> messages.CardanoTxOutputType: if contains_address: address = output["address"] else: - address_parameters = _create_change_output_address_parameters(output) + address_parameters = _create_address_parameters_internal(output) if "token_bundle" in output: token_bundle = _create_token_bundle(output["token_bundle"]) @@ -163,24 +169,24 @@ def _create_tokens(tokens) -> List[messages.CardanoTokenType]: return result -def _create_change_output_address_parameters( - output, +def _create_address_parameters_internal( + address_parameters, ) -> messages.CardanoAddressParametersType: - if "path" not in output: + if "path" not in address_parameters: raise ValueError(INCOMPLETE_OUTPUT_ERROR_MESSAGE) staking_key_hash_bytes = None - if "stakingKeyHash" in output: - staking_key_hash_bytes = bytes.fromhex(output.get("stakingKeyHash")) + if "stakingKeyHash" in address_parameters: + staking_key_hash_bytes = bytes.fromhex(address_parameters.get("stakingKeyHash")) return create_address_parameters( - int(output["addressType"]), - tools.parse_path(output["path"]), - tools.parse_path(output.get("stakingPath")), + int(address_parameters["addressType"]), + tools.parse_path(address_parameters["path"]), + tools.parse_path(address_parameters.get("stakingPath")), staking_key_hash_bytes, - output.get("blockIndex"), - output.get("txIndex"), - output.get("certificateIndex"), + address_parameters.get("blockIndex"), + address_parameters.get("txIndex"), + address_parameters.get("certificateIndex"), ) @@ -315,6 +321,49 @@ def create_withdrawal(withdrawal) -> messages.CardanoTxWithdrawalType: ) +def create_auxiliary_data(auxiliary_data) -> messages.CardanoTxAuxiliaryDataType: + if auxiliary_data is None: + return None + + AUXILIARY_DATA_MISSING_FIELDS_ERROR = ValueError( + "Auxiliary data is missing some fields" + ) + + # include all provided fields so we can test validation in FW + blob = None + if "blob" in auxiliary_data: + blob = bytes.fromhex(auxiliary_data["blob"]) + + catalyst_registration_parameters = None + if "catalyst_registration_parameters" in auxiliary_data: + catalyst_registration = auxiliary_data["catalyst_registration_parameters"] + if not all( + k in catalyst_registration for k in REQUIRED_FIELDS_CATALYST_REGISTRATION + ): + raise AUXILIARY_DATA_MISSING_FIELDS_ERROR + + catalyst_registration_parameters = ( + messages.CardanoCatalystRegistrationParametersType( + voting_public_key=bytes.fromhex( + catalyst_registration["voting_public_key"] + ), + staking_path=tools.parse_path(catalyst_registration["staking_path"]), + nonce=catalyst_registration["nonce"], + reward_address_parameters=_create_address_parameters_internal( + catalyst_registration["reward_address_parameters"] + ), + ) + ) + + if blob is None and catalyst_registration_parameters is None: + raise AUXILIARY_DATA_MISSING_FIELDS_ERROR + + return messages.CardanoTxAuxiliaryDataType( + blob=blob, + catalyst_registration_parameters=catalyst_registration_parameters, + ) + + # ====== Client functions ====== # @@ -351,9 +400,9 @@ def sign_tx( validity_interval_start: Optional[int], certificates: List[messages.CardanoTxCertificateType] = (), withdrawals: List[messages.CardanoTxWithdrawalType] = (), - metadata: bytes = None, protocol_magic: int = PROTOCOL_MAGICS["mainnet"], network_id: int = NETWORK_IDS["mainnet"], + auxiliary_data: messages.CardanoTxAuxiliaryDataType = None, ) -> messages.CardanoSignedTx: response = client.call( messages.CardanoSignTx( @@ -364,9 +413,9 @@ def sign_tx( validity_interval_start=validity_interval_start, certificates=certificates, withdrawals=withdrawals, - metadata=metadata, protocol_magic=protocol_magic, network_id=network_id, + auxiliary_data=auxiliary_data, ) ) diff --git a/python/src/trezorlib/cli/cardano.py b/python/src/trezorlib/cli/cardano.py index 362192553..f5cad0f3b 100644 --- a/python/src/trezorlib/cli/cardano.py +++ b/python/src/trezorlib/cli/cardano.py @@ -67,9 +67,7 @@ def sign_tx(client, file, protocol_magic, network_id, testnet): cardano.create_withdrawal(withdrawal) for withdrawal in transaction.get("withdrawals", ()) ] - metadata = None - if "metadata" in transaction: - metadata = bytes.fromhex(transaction["metadata"]) + auxiliary_data = cardano.create_auxiliary_data(transaction.get("auxiliary_data")) signed_transaction = cardano.sign_tx( client, @@ -80,9 +78,9 @@ def sign_tx(client, file, protocol_magic, network_id, testnet): validity_interval_start, certificates, withdrawals, - metadata, protocol_magic, network_id, + auxiliary_data, ) return { diff --git a/python/src/trezorlib/messages/CardanoCatalystRegistrationParametersType.py b/python/src/trezorlib/messages/CardanoCatalystRegistrationParametersType.py new file mode 100644 index 000000000..6af79bfbb --- /dev/null +++ b/python/src/trezorlib/messages/CardanoCatalystRegistrationParametersType.py @@ -0,0 +1,37 @@ +# Automatically generated by pb2py +# fmt: off +from .. import protobuf as p + +from .CardanoAddressParametersType import CardanoAddressParametersType + +if __debug__: + try: + from typing import Dict, List, Optional # noqa: F401 + from typing_extensions import Literal # noqa: F401 + except ImportError: + pass + + +class CardanoCatalystRegistrationParametersType(p.MessageType): + + def __init__( + self, + *, + voting_public_key: bytes, + reward_address_parameters: CardanoAddressParametersType, + nonce: int, + staking_path: Optional[List[int]] = None, + ) -> None: + self.staking_path = staking_path if staking_path is not None else [] + self.voting_public_key = voting_public_key + self.reward_address_parameters = reward_address_parameters + self.nonce = nonce + + @classmethod + def get_fields(cls) -> Dict: + return { + 1: ('voting_public_key', p.BytesType, p.FLAG_REQUIRED), + 2: ('staking_path', p.UVarintType, p.FLAG_REPEATED), + 3: ('reward_address_parameters', CardanoAddressParametersType, p.FLAG_REQUIRED), + 4: ('nonce', p.UVarintType, p.FLAG_REQUIRED), + } diff --git a/python/src/trezorlib/messages/CardanoSignTx.py b/python/src/trezorlib/messages/CardanoSignTx.py index 6c08308d8..d50e0010f 100644 --- a/python/src/trezorlib/messages/CardanoSignTx.py +++ b/python/src/trezorlib/messages/CardanoSignTx.py @@ -2,6 +2,7 @@ # fmt: off from .. import protobuf as p +from .CardanoTxAuxiliaryDataType import CardanoTxAuxiliaryDataType from .CardanoTxCertificateType import CardanoTxCertificateType from .CardanoTxInputType import CardanoTxInputType from .CardanoTxOutputType import CardanoTxOutputType @@ -29,8 +30,8 @@ class CardanoSignTx(p.MessageType): certificates: Optional[List[CardanoTxCertificateType]] = None, withdrawals: Optional[List[CardanoTxWithdrawalType]] = None, ttl: Optional[int] = None, - metadata: Optional[bytes] = None, validity_interval_start: Optional[int] = None, + auxiliary_data: Optional[CardanoTxAuxiliaryDataType] = None, ) -> None: self.inputs = inputs if inputs is not None else [] self.outputs = outputs if outputs is not None else [] @@ -40,8 +41,8 @@ class CardanoSignTx(p.MessageType): self.fee = fee self.network_id = network_id self.ttl = ttl - self.metadata = metadata self.validity_interval_start = validity_interval_start + self.auxiliary_data = auxiliary_data @classmethod def get_fields(cls) -> Dict: @@ -54,6 +55,6 @@ class CardanoSignTx(p.MessageType): 8: ('network_id', p.UVarintType, p.FLAG_REQUIRED), 9: ('certificates', CardanoTxCertificateType, p.FLAG_REPEATED), 10: ('withdrawals', CardanoTxWithdrawalType, p.FLAG_REPEATED), - 11: ('metadata', p.BytesType, None), 12: ('validity_interval_start', p.UVarintType, None), + 13: ('auxiliary_data', CardanoTxAuxiliaryDataType, None), } diff --git a/python/src/trezorlib/messages/CardanoTxAuxiliaryDataType.py b/python/src/trezorlib/messages/CardanoTxAuxiliaryDataType.py index 931be3aad..ccc4c9280 100644 --- a/python/src/trezorlib/messages/CardanoTxAuxiliaryDataType.py +++ b/python/src/trezorlib/messages/CardanoTxAuxiliaryDataType.py @@ -2,13 +2,12 @@ # fmt: off from .. import protobuf as p -from .CardanoTxMetadataType import CardanoTxMetadataType +from .CardanoCatalystRegistrationParametersType import CardanoCatalystRegistrationParametersType if __debug__: try: from typing import Dict, List, Optional # noqa: F401 from typing_extensions import Literal # noqa: F401 - EnumTypeCardanoAuxiliaryDataType = Literal[0, 1] except ImportError: pass @@ -18,18 +17,15 @@ class CardanoTxAuxiliaryDataType(p.MessageType): def __init__( self, *, - type: EnumTypeCardanoAuxiliaryDataType, blob: Optional[bytes] = None, - metadata: Optional[CardanoTxMetadataType] = None, + catalyst_registration_parameters: Optional[CardanoCatalystRegistrationParametersType] = None, ) -> None: - self.type = type self.blob = blob - self.metadata = metadata + self.catalyst_registration_parameters = catalyst_registration_parameters @classmethod def get_fields(cls) -> Dict: return { - 1: ('type', p.EnumType("CardanoAuxiliaryDataType", (0, 1,)), p.FLAG_REQUIRED), - 2: ('blob', p.BytesType, None), - 3: ('metadata', CardanoTxMetadataType, None), + 1: ('blob', p.BytesType, None), + 2: ('catalyst_registration_parameters', CardanoCatalystRegistrationParametersType, None), } diff --git a/python/src/trezorlib/messages/__init__.py b/python/src/trezorlib/messages/__init__.py index 5a0f143d4..e39608a70 100644 --- a/python/src/trezorlib/messages/__init__.py +++ b/python/src/trezorlib/messages/__init__.py @@ -26,6 +26,7 @@ from .CardanoAddress import CardanoAddress from .CardanoAddressParametersType import CardanoAddressParametersType from .CardanoAssetGroupType import CardanoAssetGroupType from .CardanoBlockchainPointerType import CardanoBlockchainPointerType +from .CardanoCatalystRegistrationParametersType import CardanoCatalystRegistrationParametersType from .CardanoGetAddress import CardanoGetAddress from .CardanoGetPublicKey import CardanoGetPublicKey from .CardanoPoolMetadataType import CardanoPoolMetadataType @@ -38,6 +39,7 @@ from .CardanoSignedTx import CardanoSignedTx from .CardanoSignedTxChunk import CardanoSignedTxChunk from .CardanoSignedTxChunkAck import CardanoSignedTxChunkAck from .CardanoTokenType import CardanoTokenType +from .CardanoTxAuxiliaryDataType import CardanoTxAuxiliaryDataType from .CardanoTxCertificateType import CardanoTxCertificateType from .CardanoTxInputType import CardanoTxInputType from .CardanoTxOutputType import CardanoTxOutputType diff --git a/tests/device_tests/cardano/test_sign_tx.py b/tests/device_tests/cardano/test_sign_tx.py index ce0060b6c..ba310dffa 100644 --- a/tests/device_tests/cardano/test_sign_tx.py +++ b/tests/device_tests/cardano/test_sign_tx.py @@ -38,6 +38,7 @@ def test_cardano_sign_tx(client, parameters, result): outputs = [cardano.create_output(o) for o in parameters["outputs"]] certificates = [cardano.create_certificate(c) for c in parameters["certificates"]] withdrawals = [cardano.create_withdrawal(w) for w in parameters["withdrawals"]] + auxiliary_data = cardano.create_auxiliary_data(parameters["auxiliary_data"]) input_flow = parameters.get("input_flow", ()) @@ -60,9 +61,9 @@ def test_cardano_sign_tx(client, parameters, result): validity_interval_start=parameters.get("validity_interval_start"), certificates=certificates, withdrawals=withdrawals, - metadata=bytes.fromhex(parameters["metadata"]), protocol_magic=parameters["protocol_magic"], network_id=parameters["network_id"], + auxiliary_data=auxiliary_data, ) assert response.tx_hash.hex() == result["tx_hash"] assert response.serialized_tx.hex() == result["serialized_tx"] @@ -76,6 +77,7 @@ def test_cardano_sign_tx_failed(client, parameters, result): outputs = [cardano.create_output(o) for o in parameters["outputs"]] certificates = [cardano.create_certificate(c) for c in parameters["certificates"]] withdrawals = [cardano.create_withdrawal(w) for w in parameters["withdrawals"]] + auxiliary_data = cardano.create_auxiliary_data(parameters["auxiliary_data"]) input_flow = parameters.get("input_flow", ()) @@ -92,9 +94,9 @@ def test_cardano_sign_tx_failed(client, parameters, result): validity_interval_start=parameters.get("validity_interval_start"), certificates=certificates, withdrawals=withdrawals, - metadata=bytes.fromhex(parameters["metadata"]), protocol_magic=parameters["protocol_magic"], network_id=parameters["network_id"], + auxiliary_data=auxiliary_data, ) @@ -104,6 +106,7 @@ def test_cardano_sign_tx_with_multiple_chunks(client, parameters, result): outputs = [cardano.create_output(o) for o in parameters["outputs"]] certificates = [cardano.create_certificate(c) for c in parameters["certificates"]] withdrawals = [cardano.create_withdrawal(w) for w in parameters["withdrawals"]] + auxiliary_data = cardano.create_auxiliary_data(parameters["auxiliary_data"]) input_flow = parameters.get("input_flow", ()) @@ -133,9 +136,9 @@ def test_cardano_sign_tx_with_multiple_chunks(client, parameters, result): validity_interval_start=parameters.get("validity_interval_start"), certificates=certificates, withdrawals=withdrawals, - metadata=bytes.fromhex(parameters["metadata"]), protocol_magic=parameters["protocol_magic"], network_id=parameters["network_id"], + auxiliary_data=auxiliary_data, ) assert response.tx_hash.hex() == result["tx_hash"] assert response.serialized_tx.hex() == result["serialized_tx"] diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index cdc86519b..8b588919e 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -9,6 +9,7 @@ "cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_multiasset_output]": "d0a58ab8b68fcd9f1191f309de52efb6be9157383357f5f9c0e0d116fccc08e4", "cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_no_ttl-validity_start]": "db76676358164a3b3dab5148f09ba5515d079212366b79c44f95e2ba613abc71", "cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate]": "f56482d4a0f2c07fe04291a7d9c29ed4aedfd31e6a80fed1563d80e3a4c4005c", +"cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate_wi-336f4a44": "6acd2406b1013917c859482bce3ae9b457f406537734398037e20784116c18f2", "cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate_wi-d3427614": "629ccaa5b660247843b366582c1bc505831c1800e028474a784b0f8b35fc473a", "cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_with_zero_margin]": "802c6f1fcf232cf05ed64868d39913449918bc70fda39fcf9735f2d5db51ef3f", "cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_o-0c37e6dc": "a9bbc7137d32d71acc1b4d4b7c19aacf7ec8b63c06fe53c16759bf81f5d0ad96", @@ -20,9 +21,10 @@ "cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_on_testnet]": "998043271c02cb725b27ba335efebf4895365d602b84df0fe04e26fa3c0bd3fa", "cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction0]": "7178cb7c264c15ab13152a87fe14c39fbdfa8571c166ddcda6e7c65680bbc784", "cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction1]": "fcd2bfb85ff1b0ec7a204b2d525c8adf4204afbdcc726d4485820ff36ded4b2c", +"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_auxiliary_data_blob]": "75934c7942a85a1adfaafb44570e102c57c3e66d45bb73cd09df269145ac0212", "cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_base_address_change_output_p-3c7243e1": "32458c03d03f4cfc2d83369a7b4a766a7b410452cb27682d5959a09a78d19b90", "cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_base_address_change_output_s-20438873": "e1dba216b8ff68de35ff87c1c430bc5170d4a9a3c09047d8f9f7e12982f93139", -"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_metadata]": "466a7245ae2d643bc35061321e28ff6d80cbe42faabb10ea613cfc92fee31c06", +"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_catalyst_registration]": "e3b4acd594c894b139a6e66b33fc9cfb81c759a4777524019d1502dc4a46f8c1", "cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration]": "555219b1572cd91037379ebd95e2a979c5e0486148cb0c00f837277820cb4cbe", "cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_and_withdrawal]": "7d7915b4300974d5f45a8308da218b7e4bac938a2d033a6db2b6dccdbec5e4d8", "cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_with_ac-9ca046f0": "e5b8662ef9abe58a835d6d5765e413ee1dc63cc870e2c6627f9da6a93c5ead9f", @@ -30,6 +32,8 @@ "cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certifica-e7bd462a": "5a983375390be55cb4fca80a58546cc333148101a02ccfc8c80e1a64b9f47b57", "cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certificate]": "367088bed7ede0e6f317d3662f990b4300f93fcff2ccd6309c6c4f50fd8da6f9", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[all_tx_inputs_must_be_external_(without_path)]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", +"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[auxiliary_data_blob_has_leftover_data]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", +"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[auxiliary_data_blob_is_incomplete]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_invalid_pool_size]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_non_staking_path]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_path_larger_than_100]": "ffae5d78193ba3e989f025b67c544ce77ac4fde9d547e4588a9fe6f90354a4c2", @@ -41,10 +45,6 @@ "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[mainnet_protocol_magic_with_testnet_network_id]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[mainnet_transaction_with_testnet_output]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[margin_higher_than_1]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", -"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[metadata_has_leftover_data]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", -"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[metadata_is_a_list]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", -"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[metadata_is_incomplete]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", -"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[metadata_too_large]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[missing_owner_with_path]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_address_has_invalid_crc]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_address_is_a_valid_cbor_but_inv-ea3da215": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", @@ -62,6 +62,8 @@ "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[stake_deregistration_account_larger_than_100]": "ffae5d78193ba3e989f025b67c544ce77ac4fde9d547e4588a9fe6f90354a4c2", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[testnet_protocol_magic_with_mainnet_network_id]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[testnet_transaction_with_mainnet_output]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", +"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[transaction_with_both_auxiliary_data_b-64274ac4": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", +"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[transaction_with_catalyst_registration-11533421": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[two_owners_with_path]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[unsupported_address_type]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_amount_is_too_large]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",