diff --git a/CHANGELOG-npm.md b/CHANGELOG-npm.md index 5f7e921..58d80c7 100644 --- a/CHANGELOG-npm.md +++ b/CHANGELOG-npm.md @@ -1,6 +1,7 @@ # Changelog -## Unreleased +## 0.9.0 +- cardano: add support for 258-tagged sets ## 0.8.0 - cardano: allow vote delegation diff --git a/CHANGELOG-rust.md b/CHANGELOG-rust.md index fa2aac1..944e169 100644 --- a/CHANGELOG-rust.md +++ b/CHANGELOG-rust.md @@ -1,6 +1,7 @@ # Changelog -## Unreleased +## 0.7.0 +- cardano: add support for 258-tagged sets ## 0.6.0 - btc: handle error when an input's previous transaction is required but missing diff --git a/Cargo.lock b/Cargo.lock index b025876..82caeba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,7 +162,7 @@ checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] name = "bitbox-api" -version = "0.6.0" +version = "0.7.0" dependencies = [ "async-trait", "base32", diff --git a/Cargo.toml b/Cargo.toml index aa497cf..5ae7fdb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bitbox-api" authors = ["Marko Bencun "] -version = "0.6.0" +version = "0.7.0" homepage = "https://bitbox.swiss/" repository = "https://github.com/BitBoxSwiss/bitbox-api-rs/" readme = "README-rust.md" diff --git a/NPM_VERSION b/NPM_VERSION index 8adc70f..899f24f 100644 --- a/NPM_VERSION +++ b/NPM_VERSION @@ -1 +1 @@ -0.8.0 \ No newline at end of file +0.9.0 \ No newline at end of file diff --git a/examples/cardano.rs b/examples/cardano.rs index c8d17c6..fe93bcd 100644 --- a/examples/cardano.rs +++ b/examples/cardano.rs @@ -94,6 +94,7 @@ async fn demo() { withdrawals: vec![], validity_interval_start: 41110811, allow_zero_ttl: false, + tag_cbor_sets: false, }; let witness = paired_bitbox @@ -148,6 +149,7 @@ async fn demo() { withdrawals: vec![], validity_interval_start: 41110811, allow_zero_ttl: false, + tag_cbor_sets: false, }; let witness = paired_bitbox @@ -185,6 +187,7 @@ async fn demo() { }], validity_interval_start: 0, allow_zero_ttl: false, + tag_cbor_sets: false, }; let witness = paired_bitbox diff --git a/messages/btc.proto b/messages/btc.proto index 6310343..7a49fe4 100644 --- a/messages/btc.proto +++ b/messages/btc.proto @@ -115,6 +115,9 @@ message BTCSignInitRequest { } FormatUnit format_unit = 8; bool contains_silent_payment_outputs = 9; + // used script configs for outputs that send to an address of the same keystore, but not + // necessarily the same account (as defined by `script_configs` above). + repeated BTCScriptConfigWithKeypath output_script_configs = 10; } message BTCSignNextResponse { @@ -174,12 +177,19 @@ message BTCSignOutputRequest { uint64 value = 3; bytes payload = 4; // if ours is false. Renamed from `hash`. repeated uint32 keypath = 5; // if ours is true - // If ours is true. References a script config from BTCSignInitRequest + // If ours is true and `output_script_config_index` is absent. References a script config from + // BTCSignInitRequest. This allows change output identification and allows us to identify + // non-change outputs to the same account, so we can display this info to the user. uint32 script_config_index = 6; optional uint32 payment_request_index = 7; // If provided, `type` and `payload` is ignored. The generated output pkScript is returned in // BTCSignNextResponse. `contains_silent_payment_outputs` in the init request must be true. SilentPayment silent_payment = 8; + // If ours is true. If set, `script_config_index` is ignored. References an output script config + // from BTCSignInitRequest. This enables verification that an output belongs to the same keystore, + // even if it is from a different account than we spend from, allowing us to display this info to + // the user. + optional uint32 output_script_config_index = 9; } message BTCScriptConfigRegistration { diff --git a/messages/cardano.proto b/messages/cardano.proto index ead7ecb..54b661d 100644 --- a/messages/cardano.proto +++ b/messages/cardano.proto @@ -126,6 +126,9 @@ message CardanoSignTransactionRequest { repeated Withdrawal withdrawals = 7; uint64 validity_interval_start = 8; bool allow_zero_ttl = 9; // include ttl even if it is zero + // Tag arrays in the transaction serialization with the 258 tag. + // See https://github.com/IntersectMBO/cardano-ledger/blob/6e2d37cc0f47bd02e89b4ce9f78b59c35c958e96/eras/conway/impl/cddl-files/extra.cddl#L5 + bool tag_cbor_sets = 10; } message CardanoSignTransactionResponse { diff --git a/sandbox/package-lock.json b/sandbox/package-lock.json index c6f953e..c9ea28b 100644 --- a/sandbox/package-lock.json +++ b/sandbox/package-lock.json @@ -30,7 +30,7 @@ }, "../pkg": { "name": "bitbox-api", - "version": "0.7.0", + "version": "0.9.0", "license": "Apache-2.0" }, "node_modules/@esbuild/aix-ppc64": { diff --git a/sandbox/src/Cardano.tsx b/sandbox/src/Cardano.tsx index c15e082..b2a89f3 100644 --- a/sandbox/src/Cardano.tsx +++ b/sandbox/src/Cardano.tsx @@ -202,6 +202,7 @@ function CardanoSignTransaction({ bb02 }: Props) { withdrawals: [], validityIntervalStart: BigInt(41110811), allowZeroTTL: false, + tagCborSets: false, }; case 'zero-ttl': return { @@ -224,6 +225,7 @@ function CardanoSignTransaction({ bb02 }: Props) { withdrawals: [], validityIntervalStart: BigInt(41110811), allowZeroTTL: true, + tagCborSets: false, }; case 'tokens': return { @@ -262,6 +264,7 @@ function CardanoSignTransaction({ bb02 }: Props) { withdrawals: [], validityIntervalStart: BigInt(41110811), allowZeroTTL: false, + tagCborSets: false, }; case 'delegate': return { @@ -292,6 +295,7 @@ function CardanoSignTransaction({ bb02 }: Props) { withdrawals: [], validityIntervalStart: BigInt(41110811), allowZeroTTL: false, + tagCborSets: false, }; case 'vote-delegation': return { @@ -317,6 +321,7 @@ function CardanoSignTransaction({ bb02 }: Props) { withdrawals: [], validityIntervalStart: BigInt(41110811), allowZeroTTL: false, + tagCborSets: false, }; case 'vote-delegation-keyhash': return { @@ -343,6 +348,7 @@ function CardanoSignTransaction({ bb02 }: Props) { withdrawals: [], validityIntervalStart: BigInt(41110811), allowZeroTTL: false, + tagCborSets: false, }; case 'withdraw-staking-rewards': return { @@ -366,6 +372,7 @@ function CardanoSignTransaction({ bb02 }: Props) { ], validityIntervalStart: BigInt(0), allowZeroTTL: false, + tagCborSets: false, }; } }; diff --git a/src/btc.rs b/src/btc.rs index 4ede88a..b16088c 100644 --- a/src/btc.rs +++ b/src/btc.rs @@ -723,6 +723,7 @@ impl PairedBitBox { .get_next_response(Request::BtcSignInit(pb::BtcSignInitRequest { coin: coin as _, script_configs: transaction.script_configs.clone(), + output_script_configs: vec![], version: transaction.version, num_inputs: transaction.inputs.len() as _, num_outputs: transaction.outputs.len() as _, diff --git a/src/cardano.rs b/src/cardano.rs index ddb10e6..148c3bd 100644 --- a/src/cardano.rs +++ b/src/cardano.rs @@ -135,6 +135,9 @@ impl PairedBitBox { &self, transaction: pb::CardanoSignTransactionRequest, ) -> Result { + if transaction.tag_cbor_sets { + self.validate_version(">=9.22.0")?; + } match self .query_proto_cardano(pb::cardano_request::Request::SignTransaction(transaction)) .await? diff --git a/src/eth.rs b/src/eth.rs index 31dad8b..27a3782 100644 --- a/src/eth.rs +++ b/src/eth.rs @@ -302,7 +302,7 @@ fn encode_value(typ: &MemberType, value: &Value) -> Result, String> { DataType::Uint => match value { Value::String(v) => { if v.starts_with("0x") || v.starts_with("0X") { - Ok(BigUint::parse_bytes(v[2..].as_bytes(), 16) + Ok(BigUint::parse_bytes(&v.as_bytes()[2..], 16) .ok_or(format!("could not parse {} as hex", v))? .to_bytes_be()) } else { diff --git a/src/shiftcrypto.bitbox02.rs b/src/shiftcrypto.bitbox02.rs index fb00593..8eedd15 100644 --- a/src/shiftcrypto.bitbox02.rs +++ b/src/shiftcrypto.bitbox02.rs @@ -188,8 +188,8 @@ pub mod insert_remove_sd_card_request { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - SdCardAction::RemoveCard => "REMOVE_CARD", - SdCardAction::InsertCard => "INSERT_CARD", + Self::RemoveCard => "REMOVE_CARD", + Self::InsertCard => "INSERT_CARD", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -304,8 +304,8 @@ pub mod btc_script_config { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - ScriptType::P2wsh => "P2WSH", - ScriptType::P2wshP2sh => "P2WSH_P2SH", + Self::P2wsh => "P2WSH", + Self::P2wshP2sh => "P2WSH_P2SH", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -356,9 +356,9 @@ pub mod btc_script_config { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - SimpleType::P2wpkhP2sh => "P2WPKH_P2SH", - SimpleType::P2wpkh => "P2WPKH", - SimpleType::P2tr => "P2TR", + Self::P2wpkhP2sh => "P2WPKH_P2SH", + Self::P2wpkh => "P2WPKH", + Self::P2tr => "P2TR", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -453,16 +453,16 @@ pub mod btc_pub_request { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - XPubType::Tpub => "TPUB", - XPubType::Xpub => "XPUB", - XPubType::Ypub => "YPUB", - XPubType::Zpub => "ZPUB", - XPubType::Vpub => "VPUB", - XPubType::Upub => "UPUB", - XPubType::CapitalVpub => "CAPITAL_VPUB", - XPubType::CapitalZpub => "CAPITAL_ZPUB", - XPubType::CapitalUpub => "CAPITAL_UPUB", - XPubType::CapitalYpub => "CAPITAL_YPUB", + Self::Tpub => "TPUB", + Self::Xpub => "XPUB", + Self::Ypub => "YPUB", + Self::Zpub => "ZPUB", + Self::Vpub => "VPUB", + Self::Upub => "UPUB", + Self::CapitalVpub => "CAPITAL_VPUB", + Self::CapitalZpub => "CAPITAL_ZPUB", + Self::CapitalUpub => "CAPITAL_UPUB", + Self::CapitalYpub => "CAPITAL_YPUB", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -528,6 +528,10 @@ pub struct BtcSignInitRequest { pub format_unit: i32, #[prost(bool, tag = "9")] pub contains_silent_payment_outputs: bool, + /// used script configs for outputs that send to an address of the same keystore, but not + /// necessarily the same account (as defined by `script_configs` above). + #[prost(message, repeated, tag = "10")] + pub output_script_configs: ::prost::alloc::vec::Vec, } /// Nested message and enum types in `BTCSignInitRequest`. pub mod btc_sign_init_request { @@ -558,8 +562,8 @@ pub mod btc_sign_init_request { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - FormatUnit::Default => "DEFAULT", - FormatUnit::Sat => "SAT", + Self::Default => "DEFAULT", + Self::Sat => "SAT", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -634,14 +638,14 @@ pub mod btc_sign_next_response { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Type::Input => "INPUT", - Type::Output => "OUTPUT", - Type::Done => "DONE", - Type::PrevtxInit => "PREVTX_INIT", - Type::PrevtxInput => "PREVTX_INPUT", - Type::PrevtxOutput => "PREVTX_OUTPUT", - Type::HostNonce => "HOST_NONCE", - Type::PaymentRequest => "PAYMENT_REQUEST", + Self::Input => "INPUT", + Self::Output => "OUTPUT", + Self::Done => "DONE", + Self::PrevtxInit => "PREVTX_INIT", + Self::PrevtxInput => "PREVTX_INPUT", + Self::PrevtxOutput => "PREVTX_OUTPUT", + Self::HostNonce => "HOST_NONCE", + Self::PaymentRequest => "PAYMENT_REQUEST", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -708,7 +712,9 @@ pub struct BtcSignOutputRequest { serde(deserialize_with = "crate::keypath::serde_deserialize") )] pub keypath: ::prost::alloc::vec::Vec, - /// If ours is true. References a script config from BTCSignInitRequest + /// If ours is true and `output_script_config_index` is absent. References a script config from + /// BTCSignInitRequest. This allows change output identification and allows us to identify + /// non-change outputs to the same account, so we can display this info to the user. #[prost(uint32, tag = "6")] pub script_config_index: u32, #[prost(uint32, optional, tag = "7")] @@ -717,6 +723,12 @@ pub struct BtcSignOutputRequest { /// BTCSignNextResponse. `contains_silent_payment_outputs` in the init request must be true. #[prost(message, optional, tag = "8")] pub silent_payment: ::core::option::Option, + /// If ours is true. If set, `script_config_index` is ignored. References an output script config + /// from BTCSignInitRequest. This enables verification that an output belongs to the same keystore, + /// even if it is from a different account than we spend from, allowing us to display this info to + /// the user. + #[prost(uint32, optional, tag = "9")] + pub output_script_config_index: ::core::option::Option, } /// Nested message and enum types in `BTCSignOutputRequest`. pub mod btc_sign_output_request { @@ -804,8 +816,8 @@ pub mod btc_register_script_config_request { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - XPubType::AutoElectrum => "AUTO_ELECTRUM", - XPubType::AutoXpubTpub => "AUTO_XPUB_TPUB", + Self::AutoElectrum => "AUTO_ELECTRUM", + Self::AutoXpubTpub => "AUTO_XPUB_TPUB", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -991,11 +1003,11 @@ impl BtcCoin { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - BtcCoin::Btc => "BTC", - BtcCoin::Tbtc => "TBTC", - BtcCoin::Ltc => "LTC", - BtcCoin::Tltc => "TLTC", - BtcCoin::Rbtc => "RBTC", + Self::Btc => "BTC", + Self::Tbtc => "TBTC", + Self::Ltc => "LTC", + Self::Tltc => "TLTC", + Self::Rbtc => "RBTC", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1029,12 +1041,12 @@ impl BtcOutputType { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - BtcOutputType::Unknown => "UNKNOWN", - BtcOutputType::P2pkh => "P2PKH", - BtcOutputType::P2sh => "P2SH", - BtcOutputType::P2wpkh => "P2WPKH", - BtcOutputType::P2wsh => "P2WSH", - BtcOutputType::P2tr => "P2TR", + Self::Unknown => "UNKNOWN", + Self::P2pkh => "P2PKH", + Self::P2sh => "P2SH", + Self::P2wpkh => "P2WPKH", + Self::P2wsh => "P2WSH", + Self::P2tr => "P2TR", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1156,6 +1168,10 @@ pub struct CardanoSignTransactionRequest { #[prost(bool, tag = "9")] #[cfg_attr(feature = "wasm", serde(rename = "allowZeroTTL"))] pub allow_zero_ttl: bool, + /// Tag arrays in the transaction serialization with the 258 tag. + /// See + #[prost(bool, tag = "10")] + pub tag_cbor_sets: bool, } /// Nested message and enum types in `CardanoSignTransactionRequest`. pub mod cardano_sign_transaction_request { @@ -1285,10 +1301,10 @@ pub mod cardano_sign_transaction_request { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - CardanoDRepType::KeyHash => "KEY_HASH", - CardanoDRepType::ScriptHash => "SCRIPT_HASH", - CardanoDRepType::AlwaysAbstain => "ALWAYS_ABSTAIN", - CardanoDRepType::AlwaysNoConfidence => "ALWAYS_NO_CONFIDENCE", + Self::KeyHash => "KEY_HASH", + Self::ScriptHash => "SCRIPT_HASH", + Self::AlwaysAbstain => "ALWAYS_ABSTAIN", + Self::AlwaysNoConfidence => "ALWAYS_NO_CONFIDENCE", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1411,8 +1427,8 @@ impl CardanoNetwork { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - CardanoNetwork::CardanoMainnet => "CardanoMainnet", - CardanoNetwork::CardanoTestnet => "CardanoTestnet", + Self::CardanoMainnet => "CardanoMainnet", + Self::CardanoTestnet => "CardanoTestnet", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1474,8 +1490,8 @@ pub mod eth_pub_request { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - OutputType::Address => "ADDRESS", - OutputType::Xpub => "XPUB", + Self::Address => "ADDRESS", + Self::Xpub => "XPUB", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1680,15 +1696,15 @@ pub mod eth_sign_typed_message_request { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - DataType::Unknown => "UNKNOWN", - DataType::Bytes => "BYTES", - DataType::Uint => "UINT", - DataType::Int => "INT", - DataType::Bool => "BOOL", - DataType::Address => "ADDRESS", - DataType::String => "STRING", - DataType::Array => "ARRAY", - DataType::Struct => "STRUCT", + Self::Unknown => "UNKNOWN", + Self::Bytes => "BYTES", + Self::Uint => "UINT", + Self::Int => "INT", + Self::Bool => "BOOL", + Self::Address => "ADDRESS", + Self::String => "STRING", + Self::Array => "ARRAY", + Self::Struct => "STRUCT", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1745,9 +1761,9 @@ pub mod eth_typed_message_value_response { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - RootObject::Unknown => "UNKNOWN", - RootObject::Domain => "DOMAIN", - RootObject::Message => "MESSAGE", + Self::Unknown => "UNKNOWN", + Self::Domain => "DOMAIN", + Self::Message => "MESSAGE", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1839,9 +1855,9 @@ impl EthCoin { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - EthCoin::Eth => "ETH", - EthCoin::RopstenEth => "RopstenETH", - EthCoin::RinkebyEth => "RinkebyETH", + Self::Eth => "ETH", + Self::RopstenEth => "RopstenETH", + Self::RinkebyEth => "RinkebyETH", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1870,9 +1886,9 @@ impl EthAddressCase { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - EthAddressCase::Mixed => "ETH_ADDRESS_CASE_MIXED", - EthAddressCase::Upper => "ETH_ADDRESS_CASE_UPPER", - EthAddressCase::Lower => "ETH_ADDRESS_CASE_LOWER", + Self::Mixed => "ETH_ADDRESS_CASE_MIXED", + Self::Upper => "ETH_ADDRESS_CASE_UPPER", + Self::Lower => "ETH_ADDRESS_CASE_LOWER", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -2002,8 +2018,8 @@ pub mod reboot_request { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Purpose::Upgrade => "UPGRADE", - Purpose::Settings => "SETTINGS", + Self::Upgrade => "UPGRADE", + Self::Settings => "SETTINGS", } } /// Creates an enum from field names used in the ProtoBuf definition. diff --git a/src/wasm/types.rs b/src/wasm/types.rs index 63352e9..aa85de7 100644 --- a/src/wasm/types.rs +++ b/src/wasm/types.rs @@ -143,6 +143,7 @@ type CardanoTransaction = { withdrawals: CardanoWithdrawal[]; validityIntervalStart: bigint; allowZeroTTL: boolean; + tagCborSets: boolean; }; type CardanoShelleyWitness = { signature: Uint8Array; diff --git a/tests/simulators.json b/tests/simulators.json index 8a9300d..ed22ef7 100644 --- a/tests/simulators.json +++ b/tests/simulators.json @@ -10,5 +10,9 @@ { "url": "https://github.com/BitBoxSwiss/bitbox02-firmware/releases/download/firmware%2Fv9.21.0/bitbox02-multi-v9.21.0-simulator1.0.0-linux-amd64", "sha256": "72031b226ea344970a6a1506893838a63b075e0bad726557ab9d941b42c534f5" + }, + { + "url": "https://github.com/BitBoxSwiss/bitbox02-firmware/releases/download/firmware%2Fv9.22.0/bitbox02-multi-v9.22.0-simulator1.0.0-linux-amd64", + "sha256": "3af12697f6fd51b155bf277ef01ef3eea5290908bff99a4aae83a95cb144ced1" } ] diff --git a/tests/subtests/test_cardano.rs b/tests/subtests/test_cardano.rs index a317428..ecf1745 100644 --- a/tests/subtests/test_cardano.rs +++ b/tests/subtests/test_cardano.rs @@ -100,6 +100,7 @@ pub async fn test(bitbox: &PairedBitBox) { withdrawals: vec![], validity_interval_start: 41110811, allow_zero_ttl: false, + tag_cbor_sets: false, }; let witness = bitbox.cardano_sign_transaction(transaction).await.unwrap(); @@ -156,6 +157,7 @@ pub async fn test(bitbox: &PairedBitBox) { withdrawals: vec![], validity_interval_start: 41110811, allow_zero_ttl: false, + tag_cbor_sets: false, }; let witness = bitbox.cardano_sign_transaction(transaction).await.unwrap(); @@ -205,6 +207,7 @@ pub async fn test(bitbox: &PairedBitBox) { withdrawals: vec![], validity_interval_start: 41110811, allow_zero_ttl: false, + tag_cbor_sets: false, }; if semver::VersionReq::parse(">=9.21.0") @@ -262,6 +265,7 @@ pub async fn test(bitbox: &PairedBitBox) { withdrawals: vec![], validity_interval_start: 41110811, allow_zero_ttl: false, + tag_cbor_sets: false, }; if semver::VersionReq::parse(">=9.21.0") @@ -310,6 +314,7 @@ pub async fn test(bitbox: &PairedBitBox) { }], validity_interval_start: 0, allow_zero_ttl: false, + tag_cbor_sets: false, }; let witness = bitbox.cardano_sign_transaction(transaction).await.unwrap(); @@ -323,4 +328,70 @@ pub async fn test(bitbox: &PairedBitBox) { "ed0d6426efcae3b02b963db0997845ba43ed53c131aa2f0faa01976ddcdb3751", ); } + // Using 258-tagged cbor sets + { + let transaction = pb::CardanoSignTransactionRequest { + network: pb::CardanoNetwork::CardanoMainnet as i32, + inputs: vec![ + pb::cardano_sign_transaction_request::Input { + keypath: keypath_input.to_vec(), + prev_out_hash: hex::decode("59864ee73ca5d91098a32b3ce9811bac1996dcbaefa6b6247dcaafb5779c2538").unwrap(), + prev_out_index: 0, + }, + ], + outputs: vec![ + pb::cardano_sign_transaction_request::Output { + encoded_address: "addr1q9qfllpxg2vu4lq6rnpel4pvpp5xnv3kvvgtxk6k6wp4ff89xrhu8jnu3p33vnctc9eklee5dtykzyag5penc6dcmakqsqqgpt".to_string(), + value: 1000000, + asset_groups: vec![ + // Asset policy ids and asset names from: + // https://github.com/cardano-foundation/CIPs/blob/a2ef32d8a2b485fed7f6ffde2781dd58869ff511/CIP-0014/README.md#test-vectors + pb::cardano_sign_transaction_request::AssetGroup { + policy_id: hex::decode("1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209").unwrap(), + tokens: vec![ + pb::cardano_sign_transaction_request::asset_group::Token { + asset_name: hex::decode("504154415445").unwrap(), + value: 1, + }, + pb::cardano_sign_transaction_request::asset_group::Token { + asset_name: hex::decode("7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373").unwrap(), + value: 3, + }, + ], + }, + ], + ..Default::default() + }, + pb::cardano_sign_transaction_request::Output { + encoded_address: change_address.clone(), + value: 4829501, + script_config: Some(change_config.clone()), + ..Default::default() + }, + ], + fee: 170499, + ttl: 41115811, + certificates: vec![], + withdrawals: vec![], + validity_interval_start: 41110811, + allow_zero_ttl: false, + tag_cbor_sets: true, + }; + if semver::VersionReq::parse(">=9.22.0") + .unwrap() + .matches(bitbox.version()) + { + let witness = bitbox.cardano_sign_transaction(transaction).await.unwrap(); + assert_eq!(witness.shelley_witnesses.len(), 1); + assert_eq!( + hex::encode(&witness.shelley_witnesses[0].public_key), + "6b5d4134cfc66281827d51cb0196f1a951ce168c19ba1314233f43d39d91e2bc", + ); + } else { + assert!(matches!( + bitbox.cardano_sign_transaction(transaction).await, + Err(bitbox_api::error::Error::Version(">=9.22.0")) + )); + } + } }