mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-14 11:39:03 +00:00
Add multiasset sending and min validity to Cardano transactions
(cherry picked from commit e4c406822c
)
This commit is contained in:
parent
013f36981d
commit
ffa96205fb
@ -126,6 +126,8 @@ message CardanoSignTx {
|
||||
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
|
||||
|
||||
/**
|
||||
* Structure representing cardano transaction input
|
||||
*/
|
||||
@ -144,6 +146,17 @@ message CardanoSignTx {
|
||||
// repeated uint32 address_n = 2; // moved to address_parameters
|
||||
optional uint64 amount = 3; // amount to spend
|
||||
optional CardanoAddressParametersType address_parameters = 4; // parameters used to derive the address
|
||||
repeated CardanoAssetGroupType token_bundle = 5; // custom assets - added in mary
|
||||
}
|
||||
|
||||
message CardanoAssetGroupType {
|
||||
required bytes policy_id = 1; // asset group policy id
|
||||
repeated CardanoTokenType tokens = 2; // asset name-amount pair
|
||||
}
|
||||
|
||||
message CardanoTokenType {
|
||||
required bytes asset_name_bytes = 1; // asset name as bytestring (may be either ascii string or hash)
|
||||
required uint64 amount = 2; // asset amount
|
||||
}
|
||||
|
||||
/**
|
||||
|
199
common/tests/fixtures/cardano/sign_tx.failed.json
vendored
199
common/tests/fixtures/cardano/sign_tx.failed.json
vendored
@ -635,6 +635,205 @@
|
||||
"result": {
|
||||
"error_message": "Invalid metadata"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Too many tokens in output",
|
||||
"parameters": {
|
||||
"protocol_magic": 764824073,
|
||||
"network_id": 1,
|
||||
"fee": 42,
|
||||
"ttl": 10,
|
||||
"certificates": [],
|
||||
"withdrawals": [],
|
||||
"metadata": "",
|
||||
"inputs": [
|
||||
{
|
||||
"path": "m/1852'/1815'/0'/0/0",
|
||||
"prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7",
|
||||
"prev_index": 0
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"address": "Ae2tdPwUPEZCanmBz5g2GEwFqKTKpNJcGYPKfDxoNeKZ8bRHr8366kseiK2",
|
||||
"amount": "3003112",
|
||||
"token_bundle": [
|
||||
{
|
||||
"policy_id": "95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39",
|
||||
"tokens": [
|
||||
{
|
||||
"asset_name_bytes": "01aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "7878754"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "1234"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "03aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "1234"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "04aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "1234"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "05aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "1234"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "06aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "1234"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "07aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "1234"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "08aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "1234"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "09aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "1234"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"policy_id": "75a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39",
|
||||
"tokens": [
|
||||
{
|
||||
"asset_name_bytes": "10aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "47"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "11aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "47"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "12aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "47"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "13aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "47"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "14aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "47"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "15aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "47"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "16aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "47"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "17aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"amount": "47"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"error_message": "Maximum tx output size"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Repeated asset name in multiasset token group",
|
||||
"parameters": {
|
||||
"protocol_magic": 764824073,
|
||||
"network_id": 1,
|
||||
"fee": 42,
|
||||
"ttl": 10,
|
||||
"certificates": [],
|
||||
"withdrawals": [],
|
||||
"metadata": "",
|
||||
"inputs": [
|
||||
{
|
||||
"path": "m/1852'/1815'/0'/0/0",
|
||||
"prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7",
|
||||
"prev_index": 0
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"address": "Ae2tdPwUPEZCanmBz5g2GEwFqKTKpNJcGYPKfDxoNeKZ8bRHr8366kseiK2",
|
||||
"amount": "3003112",
|
||||
"token_bundle": [
|
||||
{
|
||||
"policy_id": "95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39",
|
||||
"tokens": [
|
||||
{
|
||||
"asset_name_bytes": "74652474436f696e",
|
||||
"amount": "7878754"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "74652474436f696e",
|
||||
"amount": "1234"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"error_message": "Invalid token bundle in output"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Repeated policyId in multiasset output",
|
||||
"parameters": {
|
||||
"protocol_magic": 764824073,
|
||||
"network_id": 1,
|
||||
"fee": 42,
|
||||
"ttl": 10,
|
||||
"certificates": [],
|
||||
"withdrawals": [],
|
||||
"metadata": "",
|
||||
"inputs": [
|
||||
{
|
||||
"path": "m/1852'/1815'/0'/0/0",
|
||||
"prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7",
|
||||
"prev_index": 0
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"address": "Ae2tdPwUPEZCanmBz5g2GEwFqKTKpNJcGYPKfDxoNeKZ8bRHr8366kseiK2",
|
||||
"amount": "3003112",
|
||||
"token_bundle": [
|
||||
{
|
||||
"policy_id": "95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39",
|
||||
"tokens": [
|
||||
{
|
||||
"asset_name_bytes": "74652474436f696e",
|
||||
"amount": "7878754"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"policy_id": "95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39",
|
||||
"tokens": [
|
||||
{
|
||||
"asset_name_bytes": "74652474436f696f",
|
||||
"amount": "7878754"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"error_message": "Invalid token bundle in output"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
140
common/tests/fixtures/cardano/sign_tx.json
vendored
140
common/tests/fixtures/cardano/sign_tx.json
vendored
@ -541,6 +541,146 @@
|
||||
"tx_hash": "47cf79f20c6c62edb4162b3b232a57afc1bd0b57c7fd8389555276408a004776",
|
||||
"serialized_tx": "83a400818258201af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc00018382582f82d818582583581cc817d85b524e3d073795819a25cdbb84cff6aa2bbb3a081980d248cba10242182a001a0fb6fc611a002dd2e882581d60cb03849e268f989b5a843107bad7fa2908246986a8f3d643f8c184800182582f82d818582583581c98c3a558f39d1d993cc8770e8825c70a6d0f5a9eb243501c4526c29da10242182a001aa8566c011a000f424002182a030aa1028184582089053545a6c254b0d9b1464e48d2b5fcf91d4e25c128afb1fcfc61d0843338ea5840cc11adf81cb3c3b75a438325f8577666f5cbb4d5d6b73fa6dbbcf5ab36897df34eecacdb54c3bc3ce7fc594ebb2c7aa4db4700f4290facad9b611a035af8710a582026308151516f3b0e02bb1638142747863c520273ce9bd3e5cd91e1d46fe2a63545a10242182af6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Mary era transaction with multiasset output",
|
||||
"parameters": {
|
||||
"protocol_magic": 764824073,
|
||||
"network_id": 1,
|
||||
"fee": 42,
|
||||
"ttl": 10,
|
||||
"validity_interval_start": 47,
|
||||
"certificates": [],
|
||||
"withdrawals": [],
|
||||
"metadata": "",
|
||||
"input_flow": [["YES"], ["YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]],
|
||||
"inputs": [
|
||||
{
|
||||
"path": "m/1852'/1815'/0'/0/0",
|
||||
"prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7",
|
||||
"prev_index": 0
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r",
|
||||
"amount": "1234",
|
||||
"token_bundle": [
|
||||
{
|
||||
"policy_id": "95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39",
|
||||
"tokens": [
|
||||
{
|
||||
"asset_name_bytes": "74652474436f696e",
|
||||
"amount": "7878754"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"addressType": 0,
|
||||
"path": "m/1852'/1815'/0'/0/0",
|
||||
"stakingPath": "m/1852'/1815'/0'/2/0",
|
||||
"amount": "7120787"
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"tx_hash": "b7269ddc59e4094a6581c653e0d5dc1e553e3a5fb6ffae47d3d094dff1cfe87b",
|
||||
"serialized_tx": "83a500818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018282583901eb0baa5e570cffbe2934db29df0b6a3d7c0430ee65d4c3a7ab2fefb91bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff821904d2a1581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a14874652474436f696e1a007838628258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a006ca79302182a030a08182fa100818258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c15840e9ab9920f24f7fdf10c90c9c1794cd9efea03dd4b3add405e5f9ffb61874d2704d376269649f8f5c57ec69b2df74fa94f73191fbeb21987b4b887743af454c06f6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Mary era transaction with different policies and tokens",
|
||||
"parameters": {
|
||||
"protocol_magic": 764824073,
|
||||
"network_id": 1,
|
||||
"fee": 42,
|
||||
"ttl": 10,
|
||||
"validity_interval_start": 47,
|
||||
"certificates": [],
|
||||
"withdrawals": [],
|
||||
"metadata": "",
|
||||
"input_flow": [["YES"], ["YES"], ["YES"], ["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "SWIPE", "YES"], ["YES"]],
|
||||
"inputs": [
|
||||
{
|
||||
"path": "m/1852'/1815'/0'/0/0",
|
||||
"prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7",
|
||||
"prev_index": 0
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r",
|
||||
"amount": "1234",
|
||||
"token_bundle": [
|
||||
{
|
||||
"policy_id": "95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39",
|
||||
"tokens": [
|
||||
{
|
||||
"asset_name_bytes": "74652474436f696e",
|
||||
"amount": "7878754"
|
||||
},
|
||||
{
|
||||
"asset_name_bytes": "456c204e69c3b16f",
|
||||
"amount": "1234"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"policy_id": "75a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39",
|
||||
"tokens": [
|
||||
{
|
||||
"asset_name_bytes": "7564247542686911",
|
||||
"amount": "47"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"addressType": 0,
|
||||
"path": "m/1852'/1815'/0'/0/0",
|
||||
"stakingPath": "m/1852'/1815'/0'/2/0",
|
||||
"amount": "7120787"
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"tx_hash": "0b929def7bd9f44f5602f809bc0f9be30521f6b93d625525cf33b956993bfb22",
|
||||
"serialized_tx": "83a500818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018282583901eb0baa5e570cffbe2934db29df0b6a3d7c0430ee65d4c3a7ab2fefb91bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff821904d2a2581c75a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a1487564247542686911182f581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a248456c204e69c3b16f1904d24874652474436f696e1a007838628258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a006ca79302182a030a08182fa100818258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c158408751e397bd9610735a92e65eab02c04aa61507f425e53c0119ddc06047bfac279439ee2bf6e0d572defa9e5649a1ea1fc2b8144041ab4970f39cd6850d4d670ef6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Mary era transaction with no TTL/validity start",
|
||||
"parameters": {
|
||||
"protocol_magic": 764824073,
|
||||
"network_id": 1,
|
||||
"fee": 42,
|
||||
"certificates": [],
|
||||
"withdrawals": [],
|
||||
"metadata": "",
|
||||
"input_flow": [["YES"]],
|
||||
"inputs": [
|
||||
{
|
||||
"path": "m/1852'/1815'/0'/0/0",
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"tx_hash": "b621e22f7cb9aac1a70a3362fde88bdfd31fc100e20f3f3c24a7b853536b4f50",
|
||||
"serialized_tx": "83a300818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b70001818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a006ca79302182aa100818258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1584088c35c125664935117d9aa1173cae5f01967b02f6b716b1a135570b2fee74728f2f3e39d56b748302c36e2407d7bfefc4054ca1e60dd857e461734ae41d00500f6"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
# Cardano
|
||||
|
||||
MAINTAINER = Gabriel Kerekeš <gabriel.kerekes@vacuumlabs.com>
|
||||
MAINTAINER = Rafael Korbaš <rafael.korbas@vacuumlabs.com>
|
||||
|
||||
ORIGINAL AUTHOR = Juraj Muravský <juraj.muravsky@vacuumlabs.com>
|
||||
|
||||
SHELLEY UPDATE AUTHOR = Gabriel Kerekeš <gabriel.kerekes@vacuumlabs.com>
|
||||
|
||||
REVIEWER = Jan Matejek <jan.matejek@satoshilabs.com>, Tomas Susanka <tomas.susanka@satoshilabs.com>
|
||||
|
||||
-----
|
||||
@ -13,15 +11,16 @@ REVIEWER = Jan Matejek <jan.matejek@satoshilabs.com>, Tomas Susanka <tomas.susan
|
||||
## Useful links
|
||||
|
||||
[Cardano documentation](https://docs.cardano.org/en/latest/) - official documentation.
|
||||
[Cardano developer documentation](https://developers.cardano.org/) - official developer documentation.
|
||||
[Delegation Design Spec](https://hydra.iohk.io/build/2006688/download/1/delegation_design_spec.pdf) - contains information about delegation (addresses, certificates, withdrawals, ...).
|
||||
[Shelley CDDL spec](https://github.com/input-output-hk/cardano-ledger-specs/blob/460ee17d22cacb3ac4d90536ebe90500a356a1c9/shelley/chain-and-ledger/shelley-spec-ledger-test/cddl-files/shelley.cddl).
|
||||
[Multi Asset CDDL spec](https://github.com/input-output-hk/cardano-ledger-specs/blob/097890495cbb0e8b62106bcd090a5721c3f4b36f/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl).
|
||||
[Byron address format](https://github.com/input-output-hk/cardano-wallet/wiki/About-Address-Format---Byron).
|
||||
[The Shelley 1852' purpose and staking path](https://github.com/input-output-hk/implementation-decisions/blob/e2d1bed5e617f0907bc5e12cf1c3f3302a4a7c42/text/1852-hd-chimeric.md).
|
||||
[cbor.me](http://cbor.me/) - very useful tool for CBOR inspection.
|
||||
|
||||
## Important notes
|
||||
|
||||
Unfortunately we are aware of the fact that currently at most ~14 inputs are supported per transaction. We suspect this is due to the memory heavy CBOR implementation. This should be fixed in the near future.
|
||||
Unfortunately we are aware of the fact that currently at most ~14 inputs are supported per transaction. To resolve this, the cardano app will have to be rewritten to support transaction streaming.
|
||||
|
||||
Cardano requires a custom `seed.py` file and `Keychain` class. This is because the original Cardano derivation schemes don't separate seed generation from key tree derivation and also because we need to support both Byron (44') and Shelley (1852') purposes. More on this can be found [here](https://github.com/satoshilabs/slips/blob/master/slip-0023.md) and [here](https://github.com/input-output-hk/implementation-decisions/blob/e2d1bed5e617f0907bc5e12cf1c3f3302a4a7c42/text/1852-hd-chimeric.md).
|
||||
|
||||
@ -93,7 +92,7 @@ Testnet: `stake_test1uqfz49rtntfa9h0s98f6s28sg69weemgjhc4e8hm66d5yac643znq`
|
||||
|
||||
Transactions don't have a distinct type. Every transaction may transfer funds, post a certificate, withdraw funds or do all at once (to a point).
|
||||
|
||||
_Unfortunately we are aware of the fact that currently at most ~14 inputs are supported per transaction. We suspect this is due to the memory heavy CBOR implementation. This should be fixed in the near future._
|
||||
_Unfortunately we are aware of the fact that currently at most ~14 inputs are supported per transaction. This should be resolved when the cardano app is updated to support transaction streaming._
|
||||
|
||||
#### Witnesses
|
||||
|
||||
@ -105,7 +104,29 @@ They only need to contain the public key (not the extended public key) and the s
|
||||
_Byron witnesses_:
|
||||
In order to be able to properly verify them, Byron witnesses need to contain the public key, signature, chain code and address attributes (which are empty on mainnet or contain the protocol magic on testnet).
|
||||
|
||||
More on witness structure can be found [here](https://github.com/input-output-hk/cardano-ledger-specs/blob/460ee17d22cacb3ac4d90536ebe90500a356a1c9/shelley/chain-and-ledger/shelley-spec-ledger-test/cddl-files/shelley.cddl#L213).
|
||||
More on witness structure can be found [here](https://github.com/input-output-hk/cardano-ledger-specs/blob/097890495cbb0e8b62106bcd090a5721c3f4b36f/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L219).
|
||||
|
||||
#### Multi Asset support
|
||||
|
||||
_Multi Asset support has been added in the Cardano Mary era_
|
||||
|
||||
_Quote from [developer docs](https://developers.cardano.org/en/development-environments/native-tokens/multi-asset-tokens-explainer/):_
|
||||
> This feature extends the existing accounting infrastructure defined in the ledger model, which is designed for processing ada-only transactions, to accommodate transactions that simultaneously use a range of assets. These assets include ada and a variety of user-define custom token types.
|
||||
|
||||
Transaction outputs may include custom tokens on top of ADA tokens:
|
||||
```
|
||||
1: [
|
||||
[
|
||||
address, [
|
||||
ADA_amount, {
|
||||
policy_id: {
|
||||
asset_name: asset_amount
|
||||
}}]]]
|
||||
```
|
||||
|
||||
Please see the transaction below for more details.
|
||||
|
||||
**The serialized transaction output size is currently limited to 512 bytes. This limitation is a mitigation measure to prevent sending large (especially change) outputs containing many tokens that Trezor would not be able to spend given that currently the full Cardano transaction is held in-memory. Once Cardano-transaction signing is refactored to be streamed, this limit can be lifted**
|
||||
|
||||
#### Certificates
|
||||
|
||||
@ -122,7 +143,7 @@ And these three which are not supported by Trezor at the moment:
|
||||
Stake key de-registration and delegation certificates both need to be witnessed by the corresponding staking key.
|
||||
|
||||
You can read more on certificates in the [delegation design spec](https://hydra.iohk.io/build/2006688/download/1/delegation_design_spec.pdf#subsection.3.4).
|
||||
Info about their structure can be found [here](https://github.com/input-output-hk/cardano-ledger-specs/blob/460ee17d22cacb3ac4d90536ebe90500a356a1c9/shelley/chain-and-ledger/shelley-spec-ledger-test/cddl-files/shelley.cddl#L102).
|
||||
Info about their structure can be found [here](https://github.com/input-output-hk/cardano-ledger-specs/blob/097890495cbb0e8b62106bcd090a5721c3f4b36f/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L102).
|
||||
|
||||
#### Withdrawals
|
||||
|
||||
@ -132,7 +153,7 @@ You can read more on withdrawals in the [delegation design spec](https://hydra.i
|
||||
|
||||
#### Metadata
|
||||
|
||||
Each transaction may contain metadata. Metadata format can be found [here](https://github.com/input-output-hk/cardano-ledger-specs/blob/460ee17d22cacb3ac4d90536ebe90500a356a1c9/shelley/chain-and-ledger/shelley-spec-ledger-test/cddl-files/shelley.cddl#L210). It's basically a CBOR serialized map and can contain numbers, bytes, strings or nested maps/lists.
|
||||
Each transaction may contain metadata. Metadata format can be found [here](https://github.com/input-output-hk/cardano-ledger-specs/blob/097890495cbb0e8b62106bcd090a5721c3f4b36f/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L212). It's basically a CBOR serialized map and can contain numbers, bytes, strings or nested maps/lists.
|
||||
|
||||
Due to memory limitations we currently enforce a maximum size of 500 bytes for metadata.
|
||||
|
||||
@ -145,12 +166,11 @@ Due to memory limitations we currently enforce a maximum size of 500 bytes for m
|
||||
You can use a combination of [cardano-node](https://github.com/input-output-hk/cardano-node) and cardano-cli (part of the cardano-node repo) to submit a transaction.
|
||||
|
||||
## Serialization format
|
||||
Cardano uses [CBOR](https://www.rfc-editor.org/info/rfc7049) as a serialization format. [Here](https://github.com/input-output-hk/cardano-ledger-specs/blob/460ee17d22cacb3ac4d90536ebe90500a356a1c9/shelley/chain-and-ledger/shelley-spec-ledger-test/cddl-files/shelley.cddl) is the [CDDL](https://tools.ietf.org/html/rfc8610) specification for Shelley.
|
||||
|
||||
Cardano uses [CBOR](https://www.rfc-editor.org/info/rfc7049) as a serialization format. [Here](https://github.com/input-output-hk/cardano-ledger-specs/blob/097890495cbb0e8b62106bcd090a5721c3f4b36f/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl) is the [CDDL](https://tools.ietf.org/html/rfc8610) specification for after Multi Asset support has been added.
|
||||
|
||||
#### Raw transaction example
|
||||
```
|
||||
83a600818258200d4a5315236df09f331158cae0f78d3df6cdb952a387bcd160dcb1bd2c708c6b00018182583900667ee84f714720123b92dd159bc306925020c460d464cea40eebc59f6c72a09118a3307789bc6d79e3b2149468f62df586085bcee687ca4d1b00000018fab759cd021a00030d40031a0007a120048182018200581cf228837e81c3baaa1879dbeff94e86fa5eba342aa05cd6d1c3bf23ed05a1581de06c72a09118a3307789bc6d79e3b2149468f62df586085bcee687ca4d1b00000001ad72b9d4a10082825820d198d009e0e482bc940331c3709c7ccdc1decbf0675e7c06380c1da3e129e7265840f62f02511ac77eebdbd87221a3bc9c93cf0971a13107ff41b6ea4ea14d720b361f41ab4994b91022763a10ebe1edf8174ca31ec2c7f56be72759d7e75303b603825820f1cea7b5d7f81e6e7858681634d957117ffe4e78bf9d475dbae9101baddda49858407ac236ad5684d22848a725246e83a043611c8ecebf04864d1b9fae6a33f23684790bc05d44a49b1c0a48df00151acafdcc93c29faf93663c9ed704cefd1a4b0df6
|
||||
83a700818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018282583901eb0baa5e570cffbe2934db29df0b6a3d7c0430ee65d4c3a7ab2fefb91bc428e4720702ebd5dab4fb175324c192dc9bb76cc5da956e3c8dff821904d2a1581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a14874652474436f696e1910e18258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b427719115c02182a030a048182008200581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b427705a1581de1122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771903e80814a10082825820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e5840c6e85c7eec254f765ddc119b1f40ef50944dcb1882822c3d61641785bbc312d1049ed0a92ded74745986f5d464d0d0caafc9f0c66285a056309d3d39cf19b20e8258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c158401feabb9e56bca7d3cb75f0942d1ebaec92f167193c70fb9b416e9ae3d3e0f368f49fde3f4a862eb6a02f9a27834d0b7c1f6dd689616809432c99f3ab7249ad0ef6
|
||||
```
|
||||
|
||||
#### The same transactions with structure description
|
||||
@ -163,27 +183,46 @@ Cardano uses [CBOR](https://www.rfc-editor.org/info/rfc7049) as a serialization
|
||||
{
|
||||
# inputs [id, index]
|
||||
# uint(0), array(1), array(2), bytes(32), uint(0)
|
||||
0: [[h'0D4...', 0]],
|
||||
0: [[h'3B4...', 0]],
|
||||
|
||||
# outputs [address, amount]
|
||||
# uint(1), array(1), array(2), bytes(57), uint(107285535181)
|
||||
1: [[h'006...', 107285535181]],
|
||||
# outputs [address, [ada_amount, { policy_id => { asset_name => asset_amount }}]]
|
||||
# uint(1), array(2)
|
||||
1: [
|
||||
# multi asset output
|
||||
# array(2), bytes(57), uint(1234), map(1), bytes(28), map(1), bytes(8), uint(4321)
|
||||
[
|
||||
h'01E...', [
|
||||
1234, {
|
||||
h'95A...': {
|
||||
h'74652474436F696E': 4321
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
# output containing only ADA [address, ada_amount]
|
||||
# array(2), bytes(57), uint(4444)
|
||||
[h'018...', 4444],
|
||||
]
|
||||
|
||||
# fee
|
||||
# uint(2), uint(200000)
|
||||
2: 200000,
|
||||
# uint(2), uint(42)
|
||||
2: 42,
|
||||
|
||||
# ttl
|
||||
# uint(3), uint(500000)
|
||||
3: 500000,
|
||||
# uint(3), uint(10)
|
||||
3: 10,
|
||||
|
||||
# certificates [[type, [keyhash/scripthash, keyhash]]]
|
||||
# uint(4), array(1), array(2), uint(1), array(2), uint(0), bytes(28)
|
||||
4: [[1,[0, h'F22...']]],
|
||||
# uint(4), array(1), array(2), uint(0), array(2), uint(0), bytes(28)
|
||||
4: [[0,[0, h'122...']]],
|
||||
|
||||
# withdrawal [reward_address: amount]
|
||||
# uint(5), map(1), bytes(29), uint(7204944340)
|
||||
5: {h'E06...': 7204944340}
|
||||
5: {h'E11...': 1000},
|
||||
|
||||
# validity_interval_start
|
||||
# uint(8), uint(20)
|
||||
8: 20
|
||||
},
|
||||
# witnesses
|
||||
# map(1)
|
||||
@ -192,9 +231,9 @@ Cardano uses [CBOR](https://www.rfc-editor.org/info/rfc7049) as a serialization
|
||||
# uint(0), array(2)
|
||||
0: [
|
||||
# array(2), bytes(32), bytes(64)
|
||||
[h'D19...', h'F62...'],
|
||||
[h'BC6...', h'C6E...'],
|
||||
# array(2), bytes(32), bytes(64)
|
||||
[h'F1C...', h'7AC...']
|
||||
[h'5D0...', h'1FE...']
|
||||
]
|
||||
},
|
||||
|
||||
|
@ -4,6 +4,7 @@ INVALID_ADDRESS = wire.ProcessError("Invalid address")
|
||||
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_STAKE_POOL_REGISTRATION_TX_STRUCTURE = wire.ProcessError(
|
||||
"Stakepool registration transaction cannot contain other certificates nor withdrawals"
|
||||
|
@ -1,7 +1,7 @@
|
||||
from apps.cardano.helpers.paths import ACCOUNT_PATH_INDEX, unharden
|
||||
|
||||
if False:
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
def variable_length_encode(number: int) -> bytes:
|
||||
@ -35,3 +35,10 @@ def format_account_number(path: List[int]) -> str:
|
||||
raise ValueError("Path is too short.")
|
||||
|
||||
return "#%d" % (unharden(path[ACCOUNT_PATH_INDEX]) + 1)
|
||||
|
||||
|
||||
def format_optional_int(number: Optional[int]) -> str:
|
||||
if number is None:
|
||||
return "n/a"
|
||||
|
||||
return str(number)
|
||||
|
@ -25,7 +25,7 @@ from .address import (
|
||||
pack_reward_address_bytes,
|
||||
)
|
||||
from .helpers import protocol_magics
|
||||
from .helpers.utils import format_account_number, to_account_path
|
||||
from .helpers.utils import format_account_number, format_optional_int, to_account_path
|
||||
|
||||
if False:
|
||||
from typing import List, Optional
|
||||
@ -35,6 +35,8 @@ if False:
|
||||
CardanoTxCertificateType,
|
||||
CardanoTxWithdrawalType,
|
||||
CardanoPoolParametersType,
|
||||
CardanoAssetGroupType,
|
||||
CardanoTokenType,
|
||||
)
|
||||
from trezor.messages.CardanoAddressParametersType import EnumTypeCardanoAddressType
|
||||
|
||||
@ -62,10 +64,22 @@ def format_coin_amount(amount: int) -> str:
|
||||
return "%s %s" % (format_amount(amount, 6), "ADA")
|
||||
|
||||
|
||||
async def confirm_sending(ctx: wire.Context, amount: int, to: str) -> None:
|
||||
def is_printable_ascii_bytestring(bytestr: bytes) -> bool:
|
||||
return all((32 < b < 127) for b in bytestr)
|
||||
|
||||
|
||||
async def confirm_sending(
|
||||
ctx: wire.Context,
|
||||
ada_amount: int,
|
||||
token_bundle: List[CardanoAssetGroupType],
|
||||
to: str,
|
||||
) -> None:
|
||||
for token_group in token_bundle:
|
||||
await confirm_sending_token_group(ctx, token_group)
|
||||
|
||||
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||
page1.normal("Confirm sending:")
|
||||
page1.bold(format_coin_amount(amount))
|
||||
page1.bold(format_coin_amount(ada_amount))
|
||||
page1.normal("to")
|
||||
|
||||
to_lines = list(chunks(to, 17))
|
||||
@ -76,6 +90,55 @@ async def confirm_sending(ctx: wire.Context, amount: int, to: str) -> None:
|
||||
await require_confirm(ctx, Paginated(pages))
|
||||
|
||||
|
||||
async def confirm_sending_token_group(
|
||||
ctx: wire.Context, token_group: CardanoAssetGroupType
|
||||
) -> None:
|
||||
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||
page1.bold("Policy id: ")
|
||||
page1.mono(hexlify(token_group.policy_id).decode())
|
||||
await require_confirm(ctx, page1)
|
||||
|
||||
for token_number, token in enumerate(token_group.tokens, 1):
|
||||
if is_printable_ascii_bytestring(token.asset_name_bytes):
|
||||
await confirm_sending_token_ascii(ctx, token, token_number)
|
||||
else:
|
||||
await confirm_sending_token_hex(ctx, token, token_number)
|
||||
|
||||
|
||||
async def confirm_sending_token_ascii(
|
||||
ctx: wire.Context, token: CardanoTokenType, token_number: int
|
||||
) -> None:
|
||||
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||
page1.normal("Asset #%s name (ASCII):" % (token_number))
|
||||
page1.bold(token.asset_name_bytes.decode("ascii"))
|
||||
page1.normal("Amount sent:")
|
||||
page1.bold(format_amount(token.amount, 0))
|
||||
await require_confirm(ctx, page1)
|
||||
|
||||
|
||||
async def confirm_sending_token_hex(
|
||||
ctx: wire.Context, token: CardanoTokenType, token_number: int
|
||||
) -> None:
|
||||
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||
page1.bold("Asset #%s name (hex):" % (token_number))
|
||||
page1.mono(hexlify(token.asset_name_bytes).decode())
|
||||
page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||
page2.normal("Amount sent:")
|
||||
page2.bold(format_amount(token.amount, 0))
|
||||
await require_confirm(ctx, Paginated([page1, page2]))
|
||||
|
||||
|
||||
async def show_warning_tx_output_contains_tokens(ctx: wire.Context) -> None:
|
||||
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||
page1.normal("The following")
|
||||
page1.normal("transaction output")
|
||||
page1.normal("contains tokens.")
|
||||
page1.br_half()
|
||||
page1.normal("Continue?")
|
||||
|
||||
await require_confirm(ctx, page1)
|
||||
|
||||
|
||||
async def show_warning_tx_no_staking_info(
|
||||
ctx: wire.Context, address_type: EnumTypeCardanoAddressType, amount: int
|
||||
) -> None:
|
||||
@ -156,7 +219,8 @@ async def confirm_transaction(
|
||||
amount: int,
|
||||
fee: int,
|
||||
protocol_magic: int,
|
||||
ttl: int,
|
||||
ttl: Optional[int],
|
||||
validity_interval_start: Optional[int],
|
||||
has_metadata: bool,
|
||||
is_network_id_verifiable: bool,
|
||||
) -> None:
|
||||
@ -173,8 +237,8 @@ async def confirm_transaction(
|
||||
if is_network_id_verifiable:
|
||||
page2.normal("Network:")
|
||||
page2.bold(protocol_magics.to_ui_string(protocol_magic))
|
||||
page2.normal("Transaction TTL:")
|
||||
page2.bold(str(ttl))
|
||||
page2.normal("Valid since: %s" % format_optional_int(validity_interval_start))
|
||||
page2.normal("TTL: %s" % format_optional_int(ttl))
|
||||
pages.append(page2)
|
||||
|
||||
if has_metadata:
|
||||
@ -295,12 +359,14 @@ async def confirm_stake_pool_metadata(
|
||||
await require_confirm(ctx, Paginated([page1, page2]))
|
||||
|
||||
|
||||
async def confirm_transaction_network_ttl(ctx, protocol_magic: int, ttl: int) -> None:
|
||||
async def confirm_transaction_network_ttl(
|
||||
ctx, protocol_magic: int, ttl: Optional[int], validity_interval_start: Optional[int]
|
||||
) -> None:
|
||||
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||
page1.normal("Network:")
|
||||
page1.bold(protocol_magics.to_ui_string(protocol_magic))
|
||||
page1.normal("Transaction TTL:")
|
||||
page1.bold(str(ttl))
|
||||
page1.normal("Valid since: %s" % format_optional_int(validity_interval_start))
|
||||
page1.normal("TTL: %s" % format_optional_int(ttl))
|
||||
|
||||
await require_confirm(ctx, page1)
|
||||
|
||||
|
@ -22,6 +22,7 @@ from .helpers import (
|
||||
INVALID_METADATA,
|
||||
INVALID_STAKE_POOL_REGISTRATION_TX_STRUCTURE,
|
||||
INVALID_STAKEPOOL_REGISTRATION_TX_INPUTS,
|
||||
INVALID_TOKEN_BUNDLE_OUTPUT,
|
||||
INVALID_WITHDRAWAL,
|
||||
LOVELACE_MAX_SUPPLY,
|
||||
network_ids,
|
||||
@ -49,6 +50,7 @@ from .layout import (
|
||||
show_warning_tx_different_staking_account,
|
||||
show_warning_tx_network_unverifiable,
|
||||
show_warning_tx_no_staking_info,
|
||||
show_warning_tx_output_contains_tokens,
|
||||
show_warning_tx_pointer_address,
|
||||
show_warning_tx_staking_key_hash,
|
||||
)
|
||||
@ -60,10 +62,17 @@ if False:
|
||||
from trezor.messages.CardanoTxInputType import CardanoTxInputType
|
||||
from trezor.messages.CardanoTxOutputType import CardanoTxOutputType
|
||||
from trezor.messages.CardanoTxWithdrawalType import CardanoTxWithdrawalType
|
||||
from typing import Dict, List, Tuple
|
||||
from trezor.messages.CardanoAssetGroupType import CardanoAssetGroupType
|
||||
from typing import Dict, List, Tuple, Union
|
||||
|
||||
CborizedTokenBundle = Dict[bytes, Dict[bytes, int]]
|
||||
CborizedTxOutput = Tuple[bytes, Union[int, Tuple[int, CborizedTokenBundle]]]
|
||||
|
||||
METADATA_HASH_SIZE = 32
|
||||
MINTING_POLICY_ID_LENGTH = 28
|
||||
MAX_METADATA_LENGTH = 500
|
||||
MAX_ASSET_NAME_LENGTH = 32
|
||||
MAX_TX_OUTPUT_SIZE = 512
|
||||
|
||||
|
||||
@seed.with_keychain
|
||||
@ -197,10 +206,64 @@ def _validate_outputs(
|
||||
"Each output must have an address field or address_parameters!"
|
||||
)
|
||||
|
||||
_validate_token_bundle(output.token_bundle)
|
||||
_validate_max_tx_output_size(keychain, output, protocol_magic, network_id)
|
||||
|
||||
if total_amount > LOVELACE_MAX_SUPPLY:
|
||||
raise wire.ProcessError("Total transaction amount is out of range!")
|
||||
|
||||
|
||||
def _validate_token_bundle(token_bundle: List[CardanoAssetGroupType]) -> None:
|
||||
seen_policy_ids = set()
|
||||
for token_group in token_bundle:
|
||||
policy_id = bytes(token_group.policy_id)
|
||||
|
||||
if len(policy_id) != MINTING_POLICY_ID_LENGTH:
|
||||
raise INVALID_TOKEN_BUNDLE_OUTPUT
|
||||
|
||||
if policy_id in seen_policy_ids:
|
||||
raise INVALID_TOKEN_BUNDLE_OUTPUT
|
||||
else:
|
||||
seen_policy_ids.add(policy_id)
|
||||
|
||||
if not token_group.tokens:
|
||||
raise INVALID_TOKEN_BUNDLE_OUTPUT
|
||||
|
||||
seen_asset_name_bytes = set()
|
||||
for token in token_group.tokens:
|
||||
asset_name_bytes = bytes(token.asset_name_bytes)
|
||||
if len(asset_name_bytes) > MAX_ASSET_NAME_LENGTH:
|
||||
raise INVALID_TOKEN_BUNDLE_OUTPUT
|
||||
|
||||
if asset_name_bytes in seen_asset_name_bytes:
|
||||
raise INVALID_TOKEN_BUNDLE_OUTPUT
|
||||
else:
|
||||
seen_asset_name_bytes.add(asset_name_bytes)
|
||||
|
||||
|
||||
def _validate_max_tx_output_size(
|
||||
keychain: seed.Keychain,
|
||||
output: CardanoTxOutputType,
|
||||
protocol_magic: int,
|
||||
network_id: int,
|
||||
) -> None:
|
||||
"""
|
||||
This limitation is a mitigation measure to prevent sending
|
||||
large (especially change) outputs containing many tokens that Trezor
|
||||
would not be able to spend reliably given that
|
||||
currently the full Cardano transaction is held in-memory.
|
||||
Once Cardano-transaction signing is refactored to be streamed, this
|
||||
limit can be lifted
|
||||
"""
|
||||
cborized_output = _cborize_output(keychain, output, protocol_magic, network_id)
|
||||
serialized_output = cbor.encode(cborized_output)
|
||||
|
||||
if len(serialized_output) > MAX_TX_OUTPUT_SIZE:
|
||||
raise wire.ProcessError(
|
||||
"Maximum tx output size (%s bytes) exceeded!" % MAX_TX_OUTPUT_SIZE
|
||||
)
|
||||
|
||||
|
||||
def _ensure_no_signing_inputs(inputs: List[CardanoTxInputType]):
|
||||
if any(i.address_n for i in inputs):
|
||||
raise INVALID_STAKEPOOL_REGISTRATION_TX_INPUTS
|
||||
@ -271,9 +334,11 @@ def _cborize_tx_body(keychain: seed.Keychain, msg: CardanoSignTx) -> Dict:
|
||||
0: inputs_for_cbor,
|
||||
1: outputs_for_cbor,
|
||||
2: msg.fee,
|
||||
3: msg.ttl,
|
||||
}
|
||||
|
||||
if msg.ttl:
|
||||
tx_body[3] = msg.ttl
|
||||
|
||||
if msg.certificates:
|
||||
certificates_for_cbor = _cborize_certificates(keychain, msg.certificates)
|
||||
tx_body[4] = certificates_for_cbor
|
||||
@ -289,6 +354,9 @@ def _cborize_tx_body(keychain: seed.Keychain, msg: CardanoSignTx) -> Dict:
|
||||
if msg.metadata:
|
||||
tx_body[7] = _hash_metadata(bytes(msg.metadata))
|
||||
|
||||
if msg.validity_interval_start:
|
||||
tx_body[8] = msg.validity_interval_start
|
||||
|
||||
return tx_body
|
||||
|
||||
|
||||
@ -301,19 +369,46 @@ def _cborize_outputs(
|
||||
outputs: List[CardanoTxOutputType],
|
||||
protocol_magic: int,
|
||||
network_id: int,
|
||||
) -> List[Tuple[bytes, int]]:
|
||||
result = []
|
||||
for output in outputs:
|
||||
amount = output.amount
|
||||
if output.address_parameters:
|
||||
address = derive_address_bytes(
|
||||
keychain, output.address_parameters, protocol_magic, network_id
|
||||
)
|
||||
else:
|
||||
# output address is validated in _validate_outputs before this happens
|
||||
address = get_address_bytes_unsafe(output.address)
|
||||
) -> List[CborizedTxOutput]:
|
||||
return [
|
||||
_cborize_output(keychain, output, protocol_magic, network_id)
|
||||
for output in outputs
|
||||
]
|
||||
|
||||
result.append((address, amount))
|
||||
|
||||
def _cborize_output(
|
||||
keychain: seed.Keychain,
|
||||
output: CardanoTxOutputType,
|
||||
protocol_magic: int,
|
||||
network_id: int,
|
||||
) -> CborizedTxOutput:
|
||||
amount = output.amount
|
||||
if output.address_parameters:
|
||||
address = derive_address_bytes(
|
||||
keychain, output.address_parameters, protocol_magic, network_id
|
||||
)
|
||||
else:
|
||||
# output address is validated in _validate_outputs before this happens
|
||||
address = get_address_bytes_unsafe(output.address)
|
||||
|
||||
if not output.token_bundle:
|
||||
return (address, amount)
|
||||
else:
|
||||
return (address, (amount, _cborize_token_bundle(output.token_bundle)))
|
||||
|
||||
|
||||
def _cborize_token_bundle(
|
||||
token_bundle: List[CardanoAssetGroupType],
|
||||
) -> CborizedTokenBundle:
|
||||
result = {}
|
||||
|
||||
for token_group in token_bundle:
|
||||
cborized_policy_id = bytes(token_group.policy_id)
|
||||
result[cborized_policy_id] = cborized_token_group = {}
|
||||
|
||||
for token in token_group.tokens:
|
||||
cborized_asset_name = bytes(token.asset_name_bytes)
|
||||
cborized_token_group[cborized_asset_name] = token.amount
|
||||
|
||||
return result
|
||||
|
||||
@ -481,6 +576,7 @@ async def _show_standard_tx(
|
||||
fee=msg.fee,
|
||||
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,
|
||||
)
|
||||
@ -500,7 +596,9 @@ async def _show_stake_pool_registration_tx(
|
||||
ctx, keychain, pool_parameters.owners, msg.network_id
|
||||
)
|
||||
await confirm_stake_pool_metadata(ctx, pool_parameters.metadata)
|
||||
await confirm_transaction_network_ttl(ctx, msg.protocol_magic, msg.ttl)
|
||||
await confirm_transaction_network_ttl(
|
||||
ctx, msg.protocol_magic, msg.ttl, msg.validity_interval_start
|
||||
)
|
||||
await confirm_stake_pool_registration_final(ctx)
|
||||
|
||||
|
||||
@ -525,7 +623,10 @@ async def _show_outputs(
|
||||
|
||||
total_amount += output.amount
|
||||
|
||||
await confirm_sending(ctx, output.amount, address)
|
||||
if len(output.token_bundle) > 0:
|
||||
await show_warning_tx_output_contains_tokens(ctx)
|
||||
|
||||
await confirm_sending(ctx, output.amount, output.token_bundle, address)
|
||||
|
||||
return total_amount
|
||||
|
||||
|
31
core/src/trezor/messages/CardanoAssetGroupType.py
Normal file
31
core/src/trezor/messages/CardanoAssetGroupType.py
Normal file
@ -0,0 +1,31 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .CardanoTokenType import CardanoTokenType
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
from typing import Dict, List # noqa: F401
|
||||
from typing_extensions import Literal # noqa: F401
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class CardanoAssetGroupType(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
policy_id: bytes,
|
||||
tokens: List[CardanoTokenType] = None,
|
||||
) -> None:
|
||||
self.tokens = tokens if tokens is not None else []
|
||||
self.policy_id = policy_id
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls) -> Dict:
|
||||
return {
|
||||
1: ('policy_id', p.BytesType, p.FLAG_REQUIRED),
|
||||
2: ('tokens', CardanoTokenType, p.FLAG_REPEATED),
|
||||
}
|
@ -30,6 +30,7 @@ class CardanoSignTx(p.MessageType):
|
||||
ttl: int = None,
|
||||
network_id: int = None,
|
||||
metadata: bytes = None,
|
||||
validity_interval_start: int = None,
|
||||
) -> None:
|
||||
self.inputs = inputs if inputs is not None else []
|
||||
self.outputs = outputs if outputs is not None else []
|
||||
@ -40,6 +41,7 @@ class CardanoSignTx(p.MessageType):
|
||||
self.ttl = ttl
|
||||
self.network_id = network_id
|
||||
self.metadata = metadata
|
||||
self.validity_interval_start = validity_interval_start
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls) -> Dict:
|
||||
@ -53,4 +55,5 @@ class CardanoSignTx(p.MessageType):
|
||||
9: ('certificates', CardanoTxCertificateType, p.FLAG_REPEATED),
|
||||
10: ('withdrawals', CardanoTxWithdrawalType, p.FLAG_REPEATED),
|
||||
11: ('metadata', p.BytesType, None),
|
||||
12: ('validity_interval_start', p.UVarintType, None),
|
||||
}
|
||||
|
29
core/src/trezor/messages/CardanoTokenType.py
Normal file
29
core/src/trezor/messages/CardanoTokenType.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
from typing import Dict, List # noqa: F401
|
||||
from typing_extensions import Literal # noqa: F401
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class CardanoTokenType(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
asset_name_bytes: bytes,
|
||||
amount: int,
|
||||
) -> None:
|
||||
self.asset_name_bytes = asset_name_bytes
|
||||
self.amount = amount
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls) -> Dict:
|
||||
return {
|
||||
1: ('asset_name_bytes', p.BytesType, p.FLAG_REQUIRED),
|
||||
2: ('amount', p.UVarintType, p.FLAG_REQUIRED),
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
import protobuf as p
|
||||
|
||||
from .CardanoAddressParametersType import CardanoAddressParametersType
|
||||
from .CardanoAssetGroupType import CardanoAssetGroupType
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
@ -17,10 +18,12 @@ class CardanoTxOutputType(p.MessageType):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
token_bundle: List[CardanoAssetGroupType] = None,
|
||||
address: str = None,
|
||||
amount: int = None,
|
||||
address_parameters: CardanoAddressParametersType = None,
|
||||
) -> None:
|
||||
self.token_bundle = token_bundle if token_bundle is not None else []
|
||||
self.address = address
|
||||
self.amount = amount
|
||||
self.address_parameters = address_parameters
|
||||
@ -31,4 +34,5 @@ class CardanoTxOutputType(p.MessageType):
|
||||
1: ('address', p.UnicodeType, None),
|
||||
3: ('amount', p.UVarintType, None),
|
||||
4: ('address_parameters', CardanoAddressParametersType, None),
|
||||
5: ('token_bundle', CardanoAssetGroupType, p.FLAG_REPEATED),
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
|
||||
from ipaddress import ip_address
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
from . import messages, tools
|
||||
from .tools import expect
|
||||
@ -36,9 +36,13 @@ REQUIRED_FIELDS_POOL_PARAMETERS = (
|
||||
"owners",
|
||||
)
|
||||
REQUIRED_FIELDS_WITHDRAWAL = ("path", "amount")
|
||||
REQUIRED_FIELDS_TOKEN_GROUP = ("policy_id", "tokens")
|
||||
REQUIRED_FIELDS_TOKEN = ("asset_name_bytes", "amount")
|
||||
|
||||
INCOMPLETE_OUTPUT_ERROR_MESSAGE = "The output is missing some fields"
|
||||
|
||||
INVALID_OUTPUT_TOKEN_BUNDLE_ENTRY = "The output's token_bundle entry is invalid"
|
||||
|
||||
ADDRESS_TYPES = (
|
||||
messages.CardanoAddressType.BYRON,
|
||||
messages.CardanoAddressType.BASE,
|
||||
@ -107,15 +111,61 @@ def create_output(output) -> messages.CardanoTxOutputType:
|
||||
if not (contains_address or contains_address_type):
|
||||
raise ValueError(INCOMPLETE_OUTPUT_ERROR_MESSAGE)
|
||||
|
||||
address = None
|
||||
address_parameters = None
|
||||
token_bundle = None
|
||||
|
||||
if contains_address:
|
||||
return messages.CardanoTxOutputType(
|
||||
address=output["address"], amount=int(output["amount"])
|
||||
)
|
||||
address = output["address"]
|
||||
else:
|
||||
return _create_change_output(output)
|
||||
address_parameters = _create_change_output_address_parameters(output)
|
||||
|
||||
if "token_bundle" in output:
|
||||
token_bundle = _create_token_bundle(output["token_bundle"])
|
||||
|
||||
return messages.CardanoTxOutputType(
|
||||
address=address,
|
||||
address_parameters=address_parameters,
|
||||
amount=int(output["amount"]),
|
||||
token_bundle=token_bundle,
|
||||
)
|
||||
|
||||
|
||||
def _create_change_output(output) -> messages.CardanoTxOutputType:
|
||||
def _create_token_bundle(token_bundle) -> List[messages.CardanoAssetGroupType]:
|
||||
result = []
|
||||
for token_group in token_bundle:
|
||||
if not all(k in token_group for k in REQUIRED_FIELDS_TOKEN_GROUP):
|
||||
raise ValueError(INVALID_OUTPUT_TOKEN_BUNDLE_ENTRY)
|
||||
|
||||
result.append(
|
||||
messages.CardanoAssetGroupType(
|
||||
policy_id=bytes.fromhex(token_group["policy_id"]),
|
||||
tokens=_create_tokens(token_group["tokens"]),
|
||||
)
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _create_tokens(tokens) -> List[messages.CardanoTokenType]:
|
||||
result = []
|
||||
for token in tokens:
|
||||
if not all(k in token for k in REQUIRED_FIELDS_TOKEN):
|
||||
raise ValueError(INVALID_OUTPUT_TOKEN_BUNDLE_ENTRY)
|
||||
|
||||
result.append(
|
||||
messages.CardanoTokenType(
|
||||
asset_name_bytes=bytes.fromhex(token["asset_name_bytes"]),
|
||||
amount=int(token["amount"]),
|
||||
)
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _create_change_output_address_parameters(
|
||||
output,
|
||||
) -> messages.CardanoAddressParametersType:
|
||||
if "path" not in output:
|
||||
raise ValueError(INCOMPLETE_OUTPUT_ERROR_MESSAGE)
|
||||
|
||||
@ -123,7 +173,7 @@ def _create_change_output(output) -> messages.CardanoTxOutputType:
|
||||
if "stakingKeyHash" in output:
|
||||
staking_key_hash_bytes = bytes.fromhex(output.get("stakingKeyHash"))
|
||||
|
||||
address_parameters = create_address_parameters(
|
||||
return create_address_parameters(
|
||||
int(output["addressType"]),
|
||||
tools.parse_path(output["path"]),
|
||||
tools.parse_path(output.get("stakingPath")),
|
||||
@ -133,10 +183,6 @@ def _create_change_output(output) -> messages.CardanoTxOutputType:
|
||||
output.get("certificateIndex"),
|
||||
)
|
||||
|
||||
return messages.CardanoTxOutputType(
|
||||
address_parameters=address_parameters, amount=int(output["amount"])
|
||||
)
|
||||
|
||||
|
||||
def create_certificate(certificate) -> messages.CardanoTxCertificateType:
|
||||
CERTIFICATE_MISSING_FIELDS_ERROR = ValueError(
|
||||
@ -301,7 +347,8 @@ def sign_tx(
|
||||
inputs: List[messages.CardanoTxInputType],
|
||||
outputs: List[messages.CardanoTxOutputType],
|
||||
fee: int,
|
||||
ttl: int,
|
||||
ttl: Optional[int],
|
||||
validity_interval_start: Optional[int],
|
||||
certificates: List[messages.CardanoTxCertificateType] = (),
|
||||
withdrawals: List[messages.CardanoTxWithdrawalType] = (),
|
||||
metadata: bytes = None,
|
||||
@ -314,6 +361,7 @@ def sign_tx(
|
||||
outputs=outputs,
|
||||
fee=fee,
|
||||
ttl=ttl,
|
||||
validity_interval_start=validity_interval_start,
|
||||
certificates=certificates,
|
||||
withdrawals=withdrawals,
|
||||
metadata=metadata,
|
||||
|
@ -57,7 +57,8 @@ def sign_tx(client, file, protocol_magic, network_id, testnet):
|
||||
inputs = [cardano.create_input(input) for input in transaction["inputs"]]
|
||||
outputs = [cardano.create_output(output) for output in transaction["outputs"]]
|
||||
fee = transaction["fee"]
|
||||
ttl = transaction["ttl"]
|
||||
ttl = transaction.get("ttl")
|
||||
validity_interval_start = transaction.get("validity_interval_start")
|
||||
certificates = [
|
||||
cardano.create_certificate(certificate)
|
||||
for certificate in transaction.get("certificates", ())
|
||||
@ -76,6 +77,7 @@ def sign_tx(client, file, protocol_magic, network_id, testnet):
|
||||
outputs,
|
||||
fee,
|
||||
ttl,
|
||||
validity_interval_start,
|
||||
certificates,
|
||||
withdrawals,
|
||||
metadata,
|
||||
|
31
python/src/trezorlib/messages/CardanoAssetGroupType.py
Normal file
31
python/src/trezorlib/messages/CardanoAssetGroupType.py
Normal file
@ -0,0 +1,31 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
from .. import protobuf as p
|
||||
|
||||
from .CardanoTokenType import CardanoTokenType
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
from typing import Dict, List # noqa: F401
|
||||
from typing_extensions import Literal # noqa: F401
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class CardanoAssetGroupType(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
policy_id: bytes,
|
||||
tokens: List[CardanoTokenType] = None,
|
||||
) -> None:
|
||||
self.tokens = tokens if tokens is not None else []
|
||||
self.policy_id = policy_id
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls) -> Dict:
|
||||
return {
|
||||
1: ('policy_id', p.BytesType, p.FLAG_REQUIRED),
|
||||
2: ('tokens', CardanoTokenType, p.FLAG_REPEATED),
|
||||
}
|
@ -30,6 +30,7 @@ class CardanoSignTx(p.MessageType):
|
||||
ttl: int = None,
|
||||
network_id: int = None,
|
||||
metadata: bytes = None,
|
||||
validity_interval_start: int = None,
|
||||
) -> None:
|
||||
self.inputs = inputs if inputs is not None else []
|
||||
self.outputs = outputs if outputs is not None else []
|
||||
@ -40,6 +41,7 @@ class CardanoSignTx(p.MessageType):
|
||||
self.ttl = ttl
|
||||
self.network_id = network_id
|
||||
self.metadata = metadata
|
||||
self.validity_interval_start = validity_interval_start
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls) -> Dict:
|
||||
@ -53,4 +55,5 @@ class CardanoSignTx(p.MessageType):
|
||||
9: ('certificates', CardanoTxCertificateType, p.FLAG_REPEATED),
|
||||
10: ('withdrawals', CardanoTxWithdrawalType, p.FLAG_REPEATED),
|
||||
11: ('metadata', p.BytesType, None),
|
||||
12: ('validity_interval_start', p.UVarintType, None),
|
||||
}
|
||||
|
29
python/src/trezorlib/messages/CardanoTokenType.py
Normal file
29
python/src/trezorlib/messages/CardanoTokenType.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
from .. import protobuf as p
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
from typing import Dict, List # noqa: F401
|
||||
from typing_extensions import Literal # noqa: F401
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class CardanoTokenType(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
asset_name_bytes: bytes,
|
||||
amount: int,
|
||||
) -> None:
|
||||
self.asset_name_bytes = asset_name_bytes
|
||||
self.amount = amount
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls) -> Dict:
|
||||
return {
|
||||
1: ('asset_name_bytes', p.BytesType, p.FLAG_REQUIRED),
|
||||
2: ('amount', p.UVarintType, p.FLAG_REQUIRED),
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
from .. import protobuf as p
|
||||
|
||||
from .CardanoAddressParametersType import CardanoAddressParametersType
|
||||
from .CardanoAssetGroupType import CardanoAssetGroupType
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
@ -17,10 +18,12 @@ class CardanoTxOutputType(p.MessageType):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
token_bundle: List[CardanoAssetGroupType] = None,
|
||||
address: str = None,
|
||||
amount: int = None,
|
||||
address_parameters: CardanoAddressParametersType = None,
|
||||
) -> None:
|
||||
self.token_bundle = token_bundle if token_bundle is not None else []
|
||||
self.address = address
|
||||
self.amount = amount
|
||||
self.address_parameters = address_parameters
|
||||
@ -31,4 +34,5 @@ class CardanoTxOutputType(p.MessageType):
|
||||
1: ('address', p.UnicodeType, None),
|
||||
3: ('amount', p.UVarintType, None),
|
||||
4: ('address_parameters', CardanoAddressParametersType, None),
|
||||
5: ('token_bundle', CardanoAssetGroupType, p.FLAG_REPEATED),
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ from .Cancel import Cancel
|
||||
from .CancelAuthorization import CancelAuthorization
|
||||
from .CardanoAddress import CardanoAddress
|
||||
from .CardanoAddressParametersType import CardanoAddressParametersType
|
||||
from .CardanoAssetGroupType import CardanoAssetGroupType
|
||||
from .CardanoBlockchainPointerType import CardanoBlockchainPointerType
|
||||
from .CardanoGetAddress import CardanoGetAddress
|
||||
from .CardanoGetPublicKey import CardanoGetPublicKey
|
||||
@ -34,6 +35,7 @@ from .CardanoPoolRelayParametersType import CardanoPoolRelayParametersType
|
||||
from .CardanoPublicKey import CardanoPublicKey
|
||||
from .CardanoSignTx import CardanoSignTx
|
||||
from .CardanoSignedTx import CardanoSignedTx
|
||||
from .CardanoTokenType import CardanoTokenType
|
||||
from .CardanoTxCertificateType import CardanoTxCertificateType
|
||||
from .CardanoTxInputType import CardanoTxInputType
|
||||
from .CardanoTxOutputType import CardanoTxOutputType
|
||||
|
@ -65,7 +65,8 @@ def test_cardano_sign_tx(client, parameters, result):
|
||||
inputs=inputs,
|
||||
outputs=outputs,
|
||||
fee=parameters["fee"],
|
||||
ttl=parameters["ttl"],
|
||||
ttl=parameters.get("ttl"),
|
||||
validity_interval_start=parameters.get("validity_interval_start"),
|
||||
certificates=certificates,
|
||||
withdrawals=withdrawals,
|
||||
metadata=bytes.fromhex(parameters["metadata"]),
|
||||
@ -96,7 +97,8 @@ def test_cardano_sign_tx_failed(client, parameters, result):
|
||||
inputs=inputs,
|
||||
outputs=outputs,
|
||||
fee=parameters["fee"],
|
||||
ttl=parameters["ttl"],
|
||||
ttl=parameters.get("ttl"),
|
||||
validity_interval_start=parameters.get("validity_interval_start"),
|
||||
certificates=certificates,
|
||||
withdrawals=withdrawals,
|
||||
metadata=bytes.fromhex(parameters["metadata"]),
|
||||
|
@ -1,25 +1,28 @@
|
||||
{
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change0]": "ff1ad82caac745577d51f574da41ad0364b2453524ff2e138a927ea03463103d",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change1]": "179ad9e910ba421b51a6492f2e63b5ab8be0c9513d6692cf9bb94dcc210d201c",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_multiple_inputs]": "fa870dea0bf144c1142d04b9ef7dad74d357cd7b730e232b19d1c8a28edcb132",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change0]": "fa870dea0bf144c1142d04b9ef7dad74d357cd7b730e232b19d1c8a28edcb132",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change1]": "699fb7c9c2537a25366a865e512d2c15b6134077bc7c89a6eb58344535fef91d",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate]": "e680f96cbed1ec77a80b49e61e201be7de539d52443b587499bfae05467b58dd",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_o-0c37e6dc": "3f92f33e81342622a95308e4ce236368f65d099d7646c9a2b2480f1730fbd458",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_output]": "7158886e32f1a1e3cb5876036d0bd627b895de28cc6c6ebdb291aa36f51514b2",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_script_address_c-466ef44c": "5e81ca3f97f73ceb1498db47ff41e9fb9565ccca3087ea97159fa00b04926c37",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_enterprise_address_ch-15518a4c": "7f0a248889f336eab3042454c5e2a6d99da79beafcdba340538c98010a5ccee0",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_pointer_address_change_output]": "bbbdb41e894af11290bc8645d0b7cebc6b4488d6c2bba45e74147ad71e9cc13f",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_certificate_with_no_p-0bbad967": "7e96c91d46c2b1564ce145b7a496fc825e2cd4dc3331839ac83049f1e253379b",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_on_testnet]": "d00e78baff80f218b719ad4b0966a1ac7e5e9a3544cc34365ad0b942bc4a318d",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction0]": "994900bb0b0d52d0872dae1254fc8d5ed337e51be0e2ddd85b9d613bc9b11687",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction1]": "120eb04eae3bbcd492e4e0ab19e25bd2e718e4fa9620d5a0496eaee5704f1951",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_metadata]": "e0707009a202512da0e38ec536d24d0522f12453ca0bcf91ff074e7653b7958f",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration]": "3d2ae35075551db91aa24dedbc388a37f58f0b618e073a73aed6a094a352b306",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_and_withdrawal]": "60f510ca75fc1288c92b50ac38ce2d413b608cc008a5ac519772936a98e60253",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_and_stake-3fdfc583": "604b63443e2d554fd3173e748439c29a968597b4db82ad98f56176cda225128f",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certifica-e7bd462a": "ab4eb02c8769a90c0c5a643826d6affbab9cda1a55b5bfa1cc1066ac97a86368",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certificate]": "c804dd78f120d14ef2585f04a148df23ab6da539d35b2b20b5bfc6092a4a0da7",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change0]": "5e2334cff9d0946ec722d69d7065023d707d8208a0ceee928824fd006edb93ad",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change1]": "1ac78675dd64f4acbf7cf8f24bc1492bec5f0bce32a3f860742d5fa1922afb24",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_multiple_inputs]": "8151b1b3cfa5ef79a256409d78b0219eb43b8fb498776b16e2f43bb5c9a38c55",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change0]": "8151b1b3cfa5ef79a256409d78b0219eb43b8fb498776b16e2f43bb5c9a38c55",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change1]": "66a8f9e4a2590c304046c8802673fb373d3fa9f3baa03dbc361818dd56fb1eab",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_different_policies_-1dbb1bfb": "accbbaba30610e45d9cbd74a3a6693cff7b65811dbd7ec0c8db8a6adc014d9d5",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_multiasset_output]": "cf3dd28eb435afc09eace0f2b02e7bae18978d0f47a6a43f27040cb6b6f5460e",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_no_ttl-validity_start]": "3954d5a5374321ba8328a86e5302878d231c9ec8f1bb70de257a5f24ffdc2dd6",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate]": "8e8b165ad23d69e4d5f52c5a6cb1f11b27829d54d5e44dd401b13875667e6287",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_o-0c37e6dc": "10cb4b3cbb74b3d44e430f3be1affd489ca6dfde179f1916d0abb82fbfff8764",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_output]": "ce02b6982e756401f8dd006e64c86825a4254dc57e6c2077f7c62848c9a3d178",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_script_address_c-466ef44c": "4a46dd8ac42295d853646a55ca1b85023b2235af6155be663b1de10a6c98def2",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_enterprise_address_ch-15518a4c": "079c395ab5dfa10d9bc6364e4201c128cd02ade9fad730390720784360b17d79",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_pointer_address_change_output]": "d5d251a3a597abc1df5480651dfbf15d59f7b207bf351131906862b0aaa07a51",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_certificate_with_no_p-0bbad967": "28a4cc241374f3125d60d33a87c0456ffe9509817d1849d8bfc0e378d6c48a07",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_on_testnet]": "d8303a92b2d5a67d81543eea2fb822ac2ab994ffa07c7d6d23db24a38f626dab",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction0]": "0f2330f22f60905681622bec047bfd67d1aeb3a30c7523d20dee62b59dd86dec",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction1]": "af40cd3886590c39a36c503c1dddfff60ea3ec8a0948e45c109b45c83056d72a",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_metadata]": "d364e0bc601fc16088bd7717822b554f3d4bd234e1ed779cc5bf9acdb316bf26",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration]": "a22ad00e9e58a64eca1f295191fa36937beb09b41620e64942498788e448e3a3",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_and_withdrawal]": "b89e4b24a93197752607d62fa88f918590ff94a2c40007ead6773a3d1bda7285",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_and_stake-3fdfc583": "a7a3f01b6972aeab505e9df70c83111ef03102b62d5260164ed36a0140d7d9dc",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certifica-e7bd462a": "9912dd5d7fe33c3f4c48e813c39d717947d9c96a15f4349ed153548314c4cf80",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certificate]": "45c35b504a486f709af64c5827231446269b3396335fd014da8c3015a1d799cc",
|
||||
"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[certificate_has_invalid_pool_size]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_non_staking_path]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
|
||||
@ -43,10 +46,13 @@
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_total_is_too_high]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[pool_reward_address_belongs_to_differe-e79b6855": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[pool_reward_address_is_a_base_address]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[repeated_asset_name_in_multiasset_token_group]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[repeated_policyid_in_multiasset_output]": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[shelley_mainnet_transaction_with_testn-af110e3e": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx_failed[shelley_testnet_transaction_with_mainn-ba78ab8f": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
|
||||
"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[too_many_tokens_in_output]": "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",
|
||||
|
Loading…
Reference in New Issue
Block a user