Skip to main content

bsv/wallet/
interfaces.rs

1//! WalletInterface trait and all arg/result structs.
2//!
3//! Defines the contract that all wallet implementations must satisfy.
4//! Translated from Go SDK wallet/interfaces.go and TS SDK Wallet.interfaces.ts.
5//! Uses #[async_trait] for object safety -- enables `dyn WalletInterface`.
6
7use std::collections::HashMap;
8
9use async_trait::async_trait;
10
11use crate::primitives::public_key::PublicKey;
12use crate::wallet::error::WalletError;
13use crate::wallet::types::{
14    BasketStringUnder300Bytes, BooleanDefaultFalse, BooleanDefaultTrue, Counterparty,
15    DescriptionString5to50Bytes, LabelStringUnder300Bytes, OutpointString,
16    OutputTagStringUnder300Bytes, PositiveIntegerDefault10Max10000, PositiveIntegerOrZero,
17    Protocol, SatoshiValue, TXIDHexString,
18};
19
20// ---------------------------------------------------------------------------
21// Serde helper modules (only compiled with "network" feature)
22// ---------------------------------------------------------------------------
23
24/// Serde helpers for custom JSON serialization of wallet types.
25/// Gated behind the "network" feature since serde is an optional dependency.
26#[cfg(feature = "network")]
27pub(crate) mod serde_helpers {
28    use crate::primitives::public_key::PublicKey;
29
30    /// Serialize/deserialize PublicKey as DER hex string.
31    pub mod public_key_hex {
32        use super::PublicKey;
33        use serde::{self, Deserialize, Deserializer, Serializer};
34
35        pub fn serialize<S>(pk: &PublicKey, serializer: S) -> Result<S::Ok, S::Error>
36        where
37            S: Serializer,
38        {
39            serializer.serialize_str(&pk.to_der_hex())
40        }
41
42        pub fn deserialize<'de, D>(deserializer: D) -> Result<PublicKey, D::Error>
43        where
44            D: Deserializer<'de>,
45        {
46            let s = String::deserialize(deserializer)?;
47            PublicKey::from_string(&s).map_err(serde::de::Error::custom)
48        }
49    }
50
51    /// Serialize/deserialize `Option<PublicKey>` as optional DER hex string.
52    #[allow(dead_code)]
53    pub mod option_public_key_hex {
54        use super::PublicKey;
55        use serde::{self, Deserialize, Deserializer, Serializer};
56
57        pub fn serialize<S>(pk: &Option<PublicKey>, serializer: S) -> Result<S::Ok, S::Error>
58        where
59            S: Serializer,
60        {
61            match pk {
62                Some(pk) => serializer.serialize_str(&pk.to_der_hex()),
63                None => serializer.serialize_none(),
64            }
65        }
66
67        pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<PublicKey>, D::Error>
68        where
69            D: Deserializer<'de>,
70        {
71            let opt: Option<String> = Option::deserialize(deserializer)?;
72            match opt {
73                Some(s) if !s.is_empty() => PublicKey::from_string(&s)
74                    .map(Some)
75                    .map_err(serde::de::Error::custom),
76                _ => Ok(None),
77            }
78        }
79    }
80
81    /// Serialize/deserialize `Vec<PublicKey>` as array of DER hex strings.
82    pub mod vec_public_key_hex {
83        use super::PublicKey;
84        use serde::ser::SerializeSeq;
85        use serde::{self, Deserialize, Deserializer, Serializer};
86
87        pub fn serialize<S>(pks: &[PublicKey], serializer: S) -> Result<S::Ok, S::Error>
88        where
89            S: Serializer,
90        {
91            let mut seq = serializer.serialize_seq(Some(pks.len()))?;
92            for pk in pks {
93                seq.serialize_element(&pk.to_der_hex())?;
94            }
95            seq.end()
96        }
97
98        pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<PublicKey>, D::Error>
99        where
100            D: Deserializer<'de>,
101        {
102            let strs: Vec<String> = Vec::deserialize(deserializer)?;
103            strs.iter()
104                .map(|s| PublicKey::from_string(s).map_err(serde::de::Error::custom))
105                .collect()
106        }
107    }
108
109    /// Serialize/deserialize [u8; 32] as base64 string (matches Go SDK Bytes32Base64).
110    pub mod bytes32_base64 {
111        use serde::{self, Deserialize, Deserializer, Serializer};
112
113        pub fn serialize<S>(bytes: &[u8; 32], serializer: S) -> Result<S::Ok, S::Error>
114        where
115            S: Serializer,
116        {
117            serializer.serialize_str(&base64_encode(bytes))
118        }
119
120        pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error>
121        where
122            D: Deserializer<'de>,
123        {
124            let s = String::deserialize(deserializer)?;
125            let decoded = base64_decode(&s).map_err(serde::de::Error::custom)?;
126            if decoded.len() > 32 {
127                return Err(serde::de::Error::custom(
128                    "base64 decoded value exceeds 32 bytes",
129                ));
130            }
131            let mut buf = [0u8; 32];
132            buf[..decoded.len()].copy_from_slice(&decoded);
133            Ok(buf)
134        }
135
136        fn base64_encode(data: &[u8]) -> String {
137            const CHARS: &[u8] =
138                b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
139            let mut result = String::new();
140            let chunks = data.chunks(3);
141            for chunk in chunks {
142                let b0 = chunk[0] as u32;
143                let b1 = if chunk.len() > 1 { chunk[1] as u32 } else { 0 };
144                let b2 = if chunk.len() > 2 { chunk[2] as u32 } else { 0 };
145                let triple = (b0 << 16) | (b1 << 8) | b2;
146                result.push(CHARS[((triple >> 18) & 0x3F) as usize] as char);
147                result.push(CHARS[((triple >> 12) & 0x3F) as usize] as char);
148                if chunk.len() > 1 {
149                    result.push(CHARS[((triple >> 6) & 0x3F) as usize] as char);
150                } else {
151                    result.push('=');
152                }
153                if chunk.len() > 2 {
154                    result.push(CHARS[(triple & 0x3F) as usize] as char);
155                } else {
156                    result.push('=');
157                }
158            }
159            result
160        }
161
162        fn base64_decode(s: &str) -> Result<Vec<u8>, String> {
163            fn char_to_val(c: u8) -> Result<u8, String> {
164                match c {
165                    b'A'..=b'Z' => Ok(c - b'A'),
166                    b'a'..=b'z' => Ok(c - b'a' + 26),
167                    b'0'..=b'9' => Ok(c - b'0' + 52),
168                    b'+' => Ok(62),
169                    b'/' => Ok(63),
170                    _ => Err(format!("invalid base64 character: {}", c as char)),
171                }
172            }
173            let bytes = s.as_bytes();
174            let mut result = Vec::new();
175            let mut i = 0;
176            while i < bytes.len() {
177                if bytes[i] == b'=' {
178                    break;
179                }
180                let a = char_to_val(bytes[i])?;
181                let b = if i + 1 < bytes.len() && bytes[i + 1] != b'=' {
182                    char_to_val(bytes[i + 1])?
183                } else {
184                    0
185                };
186                let c = if i + 2 < bytes.len() && bytes[i + 2] != b'=' {
187                    char_to_val(bytes[i + 2])?
188                } else {
189                    0
190                };
191                let d = if i + 3 < bytes.len() && bytes[i + 3] != b'=' {
192                    char_to_val(bytes[i + 3])?
193                } else {
194                    0
195                };
196                let triple =
197                    ((a as u32) << 18) | ((b as u32) << 12) | ((c as u32) << 6) | (d as u32);
198                result.push(((triple >> 16) & 0xFF) as u8);
199                if i + 2 < bytes.len() && bytes[i + 2] != b'=' {
200                    result.push(((triple >> 8) & 0xFF) as u8);
201                }
202                if i + 3 < bytes.len() && bytes[i + 3] != b'=' {
203                    result.push((triple & 0xFF) as u8);
204                }
205                i += 4;
206            }
207            Ok(result)
208        }
209    }
210
211    /// Serialize/deserialize `Vec<u8>` as JSON array of numbers (matches Go SDK BytesList).
212    pub mod bytes_as_array {
213        use serde::{Deserialize, Deserializer, Serializer};
214
215        pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
216        where
217            S: Serializer,
218        {
219            serializer.collect_seq(bytes.iter())
220        }
221
222        pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
223        where
224            D: Deserializer<'de>,
225        {
226            Vec::<u8>::deserialize(deserializer)
227        }
228    }
229
230    /// Serialize/deserialize `Option<Vec<u8>>` as optional JSON array of numbers.
231    pub mod option_bytes_as_array {
232        use serde::{Deserialize, Deserializer, Serializer};
233
234        pub fn serialize<S>(bytes: &Option<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error>
235        where
236            S: Serializer,
237        {
238            match bytes {
239                Some(b) => serializer.collect_seq(b.iter()),
240                None => serializer.serialize_none(),
241            }
242        }
243
244        pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
245        where
246            D: Deserializer<'de>,
247        {
248            Option::<Vec<u8>>::deserialize(deserializer)
249        }
250    }
251
252    /// Serialize/deserialize `Vec<u8>` as hex string (matches Go SDK BytesHex).
253    pub mod bytes_as_hex {
254        use serde::{self, Deserialize, Deserializer, Serializer};
255
256        pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
257        where
258            S: Serializer,
259        {
260            serializer.serialize_str(&to_hex(bytes))
261        }
262
263        pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
264        where
265            D: Deserializer<'de>,
266        {
267            let s = String::deserialize(deserializer)?;
268            from_hex(&s).map_err(serde::de::Error::custom)
269        }
270
271        fn to_hex(bytes: &[u8]) -> String {
272            const HEX: &[u8; 16] = b"0123456789abcdef";
273            let mut s = String::with_capacity(bytes.len() * 2);
274            for &b in bytes {
275                s.push(HEX[(b >> 4) as usize] as char);
276                s.push(HEX[(b & 0xf) as usize] as char);
277            }
278            s
279        }
280
281        pub(crate) fn from_hex(s: &str) -> Result<Vec<u8>, String> {
282            if !s.len().is_multiple_of(2) {
283                return Err("hex string has odd length".to_string());
284            }
285            let bytes = s.as_bytes();
286            let mut result = Vec::with_capacity(bytes.len() / 2);
287            for chunk in bytes.chunks(2) {
288                let hi = hex_val(chunk[0])?;
289                let lo = hex_val(chunk[1])?;
290                result.push((hi << 4) | lo);
291            }
292            Ok(result)
293        }
294
295        fn hex_val(b: u8) -> Result<u8, String> {
296            match b {
297                b'0'..=b'9' => Ok(b - b'0'),
298                b'a'..=b'f' => Ok(b - b'a' + 10),
299                b'A'..=b'F' => Ok(b - b'A' + 10),
300                _ => Err(format!("invalid hex character: {}", b as char)),
301            }
302        }
303    }
304
305    /// Serialize/deserialize `Option<Vec<u8>>` as optional hex string.
306    pub mod option_bytes_as_hex {
307        use serde::{self, Deserialize, Deserializer, Serializer};
308
309        pub fn serialize<S>(bytes: &Option<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error>
310        where
311            S: Serializer,
312        {
313            match bytes {
314                Some(b) => super::bytes_as_hex::serialize(b, serializer),
315                None => serializer.serialize_none(),
316            }
317        }
318
319        pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
320        where
321            D: Deserializer<'de>,
322        {
323            let opt: Option<String> = Option::deserialize(deserializer)?;
324            match opt {
325                Some(s) if !s.is_empty() => super::bytes_as_hex::from_hex(&s)
326                    .map(Some)
327                    .map_err(serde::de::Error::custom),
328                _ => Ok(None),
329            }
330        }
331    }
332}
333
334// ---------------------------------------------------------------------------
335// Enums
336// ---------------------------------------------------------------------------
337
338/// Current state of a transaction action.
339#[derive(Clone, Debug, PartialEq, Eq)]
340#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
341#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
342pub enum ActionStatus {
343    Completed,
344    Unprocessed,
345    Sending,
346    Unproven,
347    Unsigned,
348    #[cfg_attr(feature = "network", serde(rename = "nosend"))]
349    NoSend,
350    #[cfg_attr(feature = "network", serde(rename = "nonfinal"))]
351    NonFinal,
352}
353
354impl ActionStatus {
355    pub fn as_str(&self) -> &'static str {
356        match self {
357            ActionStatus::Completed => "completed",
358            ActionStatus::Unprocessed => "unprocessed",
359            ActionStatus::Sending => "sending",
360            ActionStatus::Unproven => "unproven",
361            ActionStatus::Unsigned => "unsigned",
362            ActionStatus::NoSend => "nosend",
363            ActionStatus::NonFinal => "nonfinal",
364        }
365    }
366}
367
368/// Status of a transaction result (subset of ActionStatus).
369#[derive(Clone, Debug, PartialEq, Eq)]
370#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
371#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
372pub enum ActionResultStatus {
373    Unproven,
374    Sending,
375    Failed,
376}
377
378impl ActionResultStatus {
379    pub fn as_str(&self) -> &'static str {
380        match self {
381            ActionResultStatus::Unproven => "unproven",
382            ActionResultStatus::Sending => "sending",
383            ActionResultStatus::Failed => "failed",
384        }
385    }
386}
387
388/// How multiple criteria are combined in queries.
389#[derive(Clone, Debug, PartialEq, Eq)]
390#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
391#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
392pub enum QueryMode {
393    Any,
394    All,
395}
396
397impl QueryMode {
398    pub fn as_str(&self) -> &'static str {
399        match self {
400            QueryMode::Any => "any",
401            QueryMode::All => "all",
402        }
403    }
404}
405
406/// What additional data to include with output listings.
407#[derive(Clone, Debug, PartialEq, Eq)]
408#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
409pub enum OutputInclude {
410    #[cfg_attr(feature = "network", serde(rename = "locking scripts"))]
411    LockingScripts,
412    #[cfg_attr(feature = "network", serde(rename = "entire transactions"))]
413    EntireTransactions,
414}
415
416impl OutputInclude {
417    pub fn as_str(&self) -> &'static str {
418        match self {
419            OutputInclude::LockingScripts => "locking scripts",
420            OutputInclude::EntireTransactions => "entire transactions",
421        }
422    }
423}
424
425/// Protocol for internalizing transaction outputs.
426#[derive(Clone, Debug, PartialEq, Eq)]
427#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
428pub enum InternalizeProtocol {
429    #[cfg_attr(feature = "network", serde(rename = "wallet payment"))]
430    WalletPayment,
431    #[cfg_attr(feature = "network", serde(rename = "basket insertion"))]
432    BasketInsertion,
433}
434
435impl InternalizeProtocol {
436    pub fn as_str(&self) -> &'static str {
437        match self {
438            InternalizeProtocol::WalletPayment => "wallet payment",
439            InternalizeProtocol::BasketInsertion => "basket insertion",
440        }
441    }
442}
443
444/// Protocol for certificate acquisition.
445#[derive(Clone, Debug, PartialEq, Eq)]
446#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
447#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
448pub enum AcquisitionProtocol {
449    Direct,
450    Issuance,
451}
452
453impl AcquisitionProtocol {
454    pub fn as_str(&self) -> &'static str {
455        match self {
456            AcquisitionProtocol::Direct => "direct",
457            AcquisitionProtocol::Issuance => "issuance",
458        }
459    }
460}
461
462/// Blockchain network type.
463#[derive(Clone, Debug, PartialEq, Eq)]
464#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
465#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
466pub enum Network {
467    Mainnet,
468    Testnet,
469}
470
471impl Network {
472    pub fn as_str(&self) -> &'static str {
473        match self {
474            Network::Mainnet => "mainnet",
475            Network::Testnet => "testnet",
476        }
477    }
478}
479
480/// Trust level for self-referential operations.
481#[derive(Clone, Debug, PartialEq, Eq)]
482#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
483#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
484pub enum TrustSelf {
485    Known,
486}
487
488impl TrustSelf {
489    pub fn as_str(&self) -> &'static str {
490        match self {
491            TrustSelf::Known => "known",
492        }
493    }
494}
495
496// ---------------------------------------------------------------------------
497// Core types: Certificate, CertificateType, SerialNumber, KeyringRevealer
498// ---------------------------------------------------------------------------
499
500/// Newtype wrapper for certificate type identifier (32 bytes).
501/// Serializes as base64 string matching Go SDK Bytes32Base64.
502#[derive(Clone, Debug, PartialEq, Eq, Hash)]
503pub struct CertificateType(pub [u8; 32]);
504
505#[cfg(feature = "network")]
506impl serde::Serialize for CertificateType {
507    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
508        serde_helpers::bytes32_base64::serialize(&self.0, serializer)
509    }
510}
511
512#[cfg(feature = "network")]
513impl<'de> serde::Deserialize<'de> for CertificateType {
514    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
515        serde_helpers::bytes32_base64::deserialize(deserializer).map(CertificateType)
516    }
517}
518
519impl CertificateType {
520    pub fn from_string(s: &str) -> Result<Self, WalletError> {
521        if s.len() > 32 {
522            return Err(WalletError::InvalidParameter(
523                "certificate type string longer than 32 bytes".to_string(),
524            ));
525        }
526        let mut buf = [0u8; 32];
527        buf[..s.len()].copy_from_slice(s.as_bytes());
528        Ok(CertificateType(buf))
529    }
530
531    pub fn bytes(&self) -> &[u8; 32] {
532        &self.0
533    }
534}
535
536/// Newtype wrapper for certificate serial number (32 bytes).
537/// Serializes as base64 string matching Go SDK Bytes32Base64.
538#[derive(Clone, Debug, PartialEq, Eq, Hash)]
539pub struct SerialNumber(pub [u8; 32]);
540
541#[cfg(feature = "network")]
542impl serde::Serialize for SerialNumber {
543    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
544        serde_helpers::bytes32_base64::serialize(&self.0, serializer)
545    }
546}
547
548#[cfg(feature = "network")]
549impl<'de> serde::Deserialize<'de> for SerialNumber {
550    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
551        serde_helpers::bytes32_base64::deserialize(deserializer).map(SerialNumber)
552    }
553}
554
555impl SerialNumber {
556    /// Parse a SerialNumber from a base64 or hex string.
557    ///
558    /// Accepts:
559    /// - 44-character base64 string (with optional padding, decodes to 32 bytes)
560    /// - 64-character hex string (decodes to 32 bytes)
561    ///
562    /// Returns an error for other formats or if the decoded length is not 32 bytes.
563    pub fn from_string(s: &str) -> Result<Self, WalletError> {
564        let bytes = if s.len() == 44 || (!s.is_empty() && s.ends_with('=')) {
565            // Base64 format (32 bytes -> 44 base64 chars with padding)
566            Self::base64_decode_sn(s)?
567        } else if s.len() == 64 && s.chars().all(|c| c.is_ascii_hexdigit()) {
568            // Hex format (32 bytes -> 64 hex chars)
569            crate::primitives::utils::from_hex(s)
570                .map_err(|e| WalletError::InvalidParameter(format!("hex: {}", e)))?
571        } else {
572            return Err(WalletError::InvalidParameter(format!(
573                "SerialNumber string must be 44 (base64) or 64 (hex) chars, got {}",
574                s.len()
575            )));
576        };
577        if bytes.len() != 32 {
578            return Err(WalletError::InvalidParameter(
579                "SerialNumber must decode to 32 bytes".into(),
580            ));
581        }
582        let mut buf = [0u8; 32];
583        buf.copy_from_slice(&bytes);
584        Ok(SerialNumber(buf))
585    }
586
587    /// Inline base64 decoder for SerialNumber (self-contained, no cross-module dependency).
588    fn base64_decode_sn(s: &str) -> Result<Vec<u8>, WalletError> {
589        fn b64_val(c: u8) -> Result<u8, WalletError> {
590            match c {
591                b'A'..=b'Z' => Ok(c - b'A'),
592                b'a'..=b'z' => Ok(c - b'a' + 26),
593                b'0'..=b'9' => Ok(c - b'0' + 52),
594                b'+' => Ok(62),
595                b'/' => Ok(63),
596                _ => Err(WalletError::InvalidParameter(format!(
597                    "invalid base64 character: {}",
598                    c as char
599                ))),
600            }
601        }
602        let bytes = s.as_bytes();
603        let mut result = Vec::new();
604        let mut i = 0;
605        while i < bytes.len() {
606            if bytes[i] == b'=' {
607                break;
608            }
609            let a = b64_val(bytes[i])?;
610            let b = if i + 1 < bytes.len() && bytes[i + 1] != b'=' {
611                b64_val(bytes[i + 1])?
612            } else {
613                0
614            };
615            let c = if i + 2 < bytes.len() && bytes[i + 2] != b'=' {
616                b64_val(bytes[i + 2])?
617            } else {
618                0
619            };
620            let d = if i + 3 < bytes.len() && bytes[i + 3] != b'=' {
621                b64_val(bytes[i + 3])?
622            } else {
623                0
624            };
625            let n = (a as u32) << 18 | (b as u32) << 12 | (c as u32) << 6 | (d as u32);
626            result.push((n >> 16) as u8);
627            if i + 2 < bytes.len() && bytes[i + 2] != b'=' {
628                result.push((n >> 8) as u8);
629            }
630            if i + 3 < bytes.len() && bytes[i + 3] != b'=' {
631                result.push(n as u8);
632            }
633            i += 4;
634        }
635        Ok(result)
636    }
637
638    pub fn bytes(&self) -> &[u8; 32] {
639        &self.0
640    }
641}
642
643/// A certificate in the wallet.
644#[derive(Clone, Debug)]
645#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
646#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
647pub struct Certificate {
648    #[cfg_attr(feature = "network", serde(rename = "type"))]
649    pub cert_type: CertificateType,
650    pub serial_number: SerialNumber,
651    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
652    pub subject: PublicKey,
653    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
654    pub certifier: PublicKey,
655    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
656    pub revocation_outpoint: Option<String>,
657    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
658    pub fields: Option<HashMap<String, String>>,
659    #[cfg_attr(
660        feature = "network",
661        serde(with = "serde_helpers::option_bytes_as_hex")
662    )]
663    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
664    pub signature: Option<Vec<u8>>,
665}
666
667/// Identifies who reveals a keyring.
668#[derive(Clone, Debug)]
669pub enum KeyringRevealer {
670    /// The certifier reveals the keyring.
671    Certifier,
672    /// A specific public key reveals the keyring.
673    PubKey(PublicKey),
674}
675
676#[cfg(feature = "network")]
677impl serde::Serialize for KeyringRevealer {
678    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
679        match self {
680            KeyringRevealer::Certifier => serializer.serialize_str("certifier"),
681            KeyringRevealer::PubKey(pk) => serializer.serialize_str(&pk.to_der_hex()),
682        }
683    }
684}
685
686#[cfg(feature = "network")]
687impl<'de> serde::Deserialize<'de> for KeyringRevealer {
688    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
689        let s = String::deserialize(deserializer)?;
690        if s == "certifier" || s.is_empty() {
691            Ok(KeyringRevealer::Certifier)
692        } else {
693            PublicKey::from_string(&s)
694                .map(KeyringRevealer::PubKey)
695                .map_err(serde::de::Error::custom)
696        }
697    }
698}
699
700// ---------------------------------------------------------------------------
701// Action types (CreateAction, SignAction, AbortAction)
702// ---------------------------------------------------------------------------
703
704/// An input to be spent in a new transaction.
705#[derive(Clone, Debug)]
706#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
707#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
708pub struct CreateActionInput {
709    pub outpoint: OutpointString,
710    pub input_description: String,
711    #[cfg_attr(
712        feature = "network",
713        serde(with = "serde_helpers::option_bytes_as_hex")
714    )]
715    #[cfg_attr(
716        feature = "network",
717        serde(skip_serializing_if = "Option::is_none", default)
718    )]
719    pub unlocking_script: Option<Vec<u8>>,
720    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
721    pub unlocking_script_length: Option<u32>,
722    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
723    pub sequence_number: Option<u32>,
724}
725
726/// An output to be created in a new transaction.
727#[derive(Clone, Debug)]
728#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
729#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
730pub struct CreateActionOutput {
731    #[cfg_attr(
732        feature = "network",
733        serde(with = "serde_helpers::option_bytes_as_hex")
734    )]
735    #[cfg_attr(
736        feature = "network",
737        serde(skip_serializing_if = "Option::is_none", default)
738    )]
739    pub locking_script: Option<Vec<u8>>,
740    pub satoshis: SatoshiValue,
741    pub output_description: String,
742    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
743    pub basket: Option<BasketStringUnder300Bytes>,
744    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
745    pub custom_instructions: Option<String>,
746    #[cfg_attr(
747        feature = "network",
748        serde(skip_serializing_if = "Vec::is_empty", default)
749    )]
750    pub tags: Vec<OutputTagStringUnder300Bytes>,
751}
752
753/// Optional parameters for creating a new transaction.
754#[derive(Clone, Debug, Default)]
755#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
756#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
757pub struct CreateActionOptions {
758    pub sign_and_process: BooleanDefaultTrue,
759    pub accept_delayed_broadcast: BooleanDefaultTrue,
760    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
761    pub trust_self: Option<TrustSelf>,
762    #[cfg_attr(
763        feature = "network",
764        serde(skip_serializing_if = "Vec::is_empty", default)
765    )]
766    pub known_txids: Vec<TXIDHexString>,
767    pub return_txid_only: BooleanDefaultFalse,
768    pub no_send: BooleanDefaultFalse,
769    #[cfg_attr(
770        feature = "network",
771        serde(skip_serializing_if = "Vec::is_empty", default)
772    )]
773    pub no_send_change: Vec<OutpointString>,
774    #[cfg_attr(
775        feature = "network",
776        serde(skip_serializing_if = "Vec::is_empty", default)
777    )]
778    pub send_with: Vec<TXIDHexString>,
779    pub randomize_outputs: BooleanDefaultTrue,
780}
781
782/// Arguments for creating a new transaction.
783#[derive(Clone, Debug)]
784#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
785#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
786pub struct CreateActionArgs {
787    pub description: DescriptionString5to50Bytes,
788    #[cfg_attr(
789        feature = "network",
790        serde(with = "serde_helpers::option_bytes_as_array")
791    )]
792    #[cfg_attr(
793        feature = "network",
794        serde(skip_serializing_if = "Option::is_none", default)
795    )]
796    #[cfg_attr(feature = "network", serde(rename = "inputBEEF"))]
797    pub input_beef: Option<Vec<u8>>,
798    #[cfg_attr(
799        feature = "network",
800        serde(skip_serializing_if = "Vec::is_empty", default)
801    )]
802    pub inputs: Vec<CreateActionInput>,
803    #[cfg_attr(
804        feature = "network",
805        serde(skip_serializing_if = "Vec::is_empty", default)
806    )]
807    pub outputs: Vec<CreateActionOutput>,
808    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
809    pub lock_time: Option<u32>,
810    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
811    pub version: Option<u32>,
812    #[cfg_attr(
813        feature = "network",
814        serde(skip_serializing_if = "Vec::is_empty", default)
815    )]
816    pub labels: Vec<LabelStringUnder300Bytes>,
817    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
818    pub options: Option<CreateActionOptions>,
819    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
820    pub reference: Option<String>,
821}
822
823/// Data needed to complete signing of a partial transaction.
824#[derive(Clone, Debug)]
825#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
826#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
827pub struct SignableTransaction {
828    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
829    pub tx: Vec<u8>,
830    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
831    pub reference: Vec<u8>,
832}
833
834/// Status of a transaction sent as part of a batch.
835#[derive(Clone, Debug)]
836#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
837#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
838pub struct SendWithResult {
839    pub txid: TXIDHexString,
840    pub status: ActionResultStatus,
841}
842
843/// Result of creating a transaction.
844#[derive(Clone, Debug)]
845#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
846#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
847pub struct CreateActionResult {
848    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
849    pub txid: Option<TXIDHexString>,
850    #[cfg_attr(
851        feature = "network",
852        serde(with = "serde_helpers::option_bytes_as_array")
853    )]
854    #[cfg_attr(
855        feature = "network",
856        serde(skip_serializing_if = "Option::is_none", default)
857    )]
858    pub tx: Option<Vec<u8>>,
859    #[cfg_attr(
860        feature = "network",
861        serde(skip_serializing_if = "Vec::is_empty", default)
862    )]
863    pub no_send_change: Vec<OutpointString>,
864    #[cfg_attr(
865        feature = "network",
866        serde(skip_serializing_if = "Vec::is_empty", default)
867    )]
868    pub send_with_results: Vec<SendWithResult>,
869    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
870    pub signable_transaction: Option<SignableTransaction>,
871}
872
873/// Unlocking script and sequence number for a specific input.
874#[derive(Clone, Debug)]
875#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
876#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
877pub struct SignActionSpend {
878    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_hex"))]
879    pub unlocking_script: Vec<u8>,
880    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
881    pub sequence_number: Option<u32>,
882}
883
884/// Controls signing and broadcasting behavior.
885#[derive(Clone, Debug, Default)]
886#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
887#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
888pub struct SignActionOptions {
889    pub accept_delayed_broadcast: BooleanDefaultTrue,
890    pub return_txid_only: BooleanDefaultFalse,
891    pub no_send: BooleanDefaultFalse,
892    #[cfg_attr(
893        feature = "network",
894        serde(skip_serializing_if = "Vec::is_empty", default)
895    )]
896    pub send_with: Vec<TXIDHexString>,
897}
898
899/// Arguments for signing a previously created transaction.
900#[derive(Clone, Debug)]
901#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
902#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
903pub struct SignActionArgs {
904    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
905    pub reference: Vec<u8>,
906    pub spends: HashMap<u32, SignActionSpend>,
907    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
908    pub options: Option<SignActionOptions>,
909}
910
911/// Result of a successful signing operation.
912#[derive(Clone, Debug)]
913#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
914#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
915pub struct SignActionResult {
916    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
917    pub txid: Option<TXIDHexString>,
918    #[cfg_attr(
919        feature = "network",
920        serde(with = "serde_helpers::option_bytes_as_array")
921    )]
922    #[cfg_attr(
923        feature = "network",
924        serde(skip_serializing_if = "Option::is_none", default)
925    )]
926    pub tx: Option<Vec<u8>>,
927    #[cfg_attr(
928        feature = "network",
929        serde(skip_serializing_if = "Vec::is_empty", default)
930    )]
931    pub send_with_results: Vec<SendWithResult>,
932}
933
934/// Arguments for aborting a transaction.
935#[derive(Clone, Debug)]
936#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
937#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
938pub struct AbortActionArgs {
939    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
940    pub reference: Vec<u8>,
941}
942
943/// Result of aborting a transaction.
944#[derive(Clone, Debug)]
945#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
946#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
947pub struct AbortActionResult {
948    pub aborted: bool,
949}
950
951// ---------------------------------------------------------------------------
952// Action detail types (for listing)
953// ---------------------------------------------------------------------------
954
955/// A transaction input with full details.
956#[derive(Clone, Debug)]
957#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
958#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
959pub struct ActionInput {
960    pub source_outpoint: OutpointString,
961    pub source_satoshis: SatoshiValue,
962    #[cfg_attr(
963        feature = "network",
964        serde(with = "serde_helpers::option_bytes_as_hex")
965    )]
966    #[cfg_attr(
967        feature = "network",
968        serde(skip_serializing_if = "Option::is_none", default)
969    )]
970    pub source_locking_script: Option<Vec<u8>>,
971    #[cfg_attr(
972        feature = "network",
973        serde(with = "serde_helpers::option_bytes_as_hex")
974    )]
975    #[cfg_attr(
976        feature = "network",
977        serde(skip_serializing_if = "Option::is_none", default)
978    )]
979    pub unlocking_script: Option<Vec<u8>>,
980    pub input_description: String,
981    pub sequence_number: u32,
982}
983
984/// A transaction output with full details.
985#[derive(Clone, Debug)]
986#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
987#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
988pub struct ActionOutput {
989    pub satoshis: SatoshiValue,
990    #[cfg_attr(
991        feature = "network",
992        serde(with = "serde_helpers::option_bytes_as_hex")
993    )]
994    #[cfg_attr(
995        feature = "network",
996        serde(skip_serializing_if = "Option::is_none", default)
997    )]
998    pub locking_script: Option<Vec<u8>>,
999    pub spendable: bool,
1000    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1001    pub custom_instructions: Option<String>,
1002    pub tags: Vec<String>,
1003    pub output_index: u32,
1004    pub output_description: String,
1005    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1006    pub basket: Option<String>,
1007}
1008
1009/// Full details about a wallet transaction.
1010#[derive(Clone, Debug)]
1011#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1012#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1013pub struct Action {
1014    pub txid: TXIDHexString,
1015    pub satoshis: i64,
1016    pub status: ActionStatus,
1017    pub is_outgoing: bool,
1018    pub description: String,
1019    #[cfg_attr(
1020        feature = "network",
1021        serde(skip_serializing_if = "Vec::is_empty", default)
1022    )]
1023    pub labels: Vec<String>,
1024    pub version: u32,
1025    pub lock_time: u32,
1026    #[cfg_attr(
1027        feature = "network",
1028        serde(skip_serializing_if = "Vec::is_empty", default)
1029    )]
1030    pub inputs: Vec<ActionInput>,
1031    #[cfg_attr(
1032        feature = "network",
1033        serde(skip_serializing_if = "Vec::is_empty", default)
1034    )]
1035    pub outputs: Vec<ActionOutput>,
1036}
1037
1038/// Maximum number of actions or outputs that can be returned.
1039pub const MAX_ACTIONS_LIMIT: u32 = 10000;
1040
1041// ---------------------------------------------------------------------------
1042// ListActions
1043// ---------------------------------------------------------------------------
1044
1045/// Filtering and pagination options for listing wallet transactions.
1046#[derive(Clone, Debug)]
1047#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1048#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1049pub struct ListActionsArgs {
1050    pub labels: Vec<LabelStringUnder300Bytes>,
1051    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1052    pub label_query_mode: Option<QueryMode>,
1053    pub include_labels: BooleanDefaultFalse,
1054    pub include_inputs: BooleanDefaultFalse,
1055    pub include_input_source_locking_scripts: BooleanDefaultFalse,
1056    pub include_input_unlocking_scripts: BooleanDefaultFalse,
1057    pub include_outputs: BooleanDefaultFalse,
1058    pub include_output_locking_scripts: BooleanDefaultFalse,
1059    pub limit: PositiveIntegerDefault10Max10000,
1060    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1061    pub offset: Option<PositiveIntegerOrZero>,
1062    pub seek_permission: BooleanDefaultTrue,
1063}
1064
1065/// Paginated list of wallet transactions.
1066#[derive(Clone, Debug)]
1067#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1068#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1069pub struct ListActionsResult {
1070    pub total_actions: u32,
1071    pub actions: Vec<Action>,
1072}
1073
1074// ---------------------------------------------------------------------------
1075// InternalizeAction
1076// ---------------------------------------------------------------------------
1077
1078/// Derivation and identity data for wallet payment outputs.
1079#[derive(Clone, Debug)]
1080#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1081#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1082pub struct Payment {
1083    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1084    pub derivation_prefix: Vec<u8>,
1085    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1086    pub derivation_suffix: Vec<u8>,
1087    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1088    pub sender_identity_key: PublicKey,
1089}
1090
1091/// Metadata for outputs being inserted into baskets.
1092#[derive(Clone, Debug)]
1093#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1094#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1095pub struct BasketInsertion {
1096    pub basket: BasketStringUnder300Bytes,
1097    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1098    pub custom_instructions: Option<String>,
1099    #[cfg_attr(
1100        feature = "network",
1101        serde(skip_serializing_if = "Vec::is_empty", default)
1102    )]
1103    pub tags: Vec<OutputTagStringUnder300Bytes>,
1104}
1105
1106/// How to process a transaction output -- as payment or basket insertion.
1107///
1108/// An enum with two variants, encoding the protocol in the variant itself.
1109/// This makes impossible states unrepresentable: a WalletPayment always has
1110/// a Payment, and a BasketInsertion always has a BasketInsertion.
1111#[derive(Clone, Debug)]
1112#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1113#[cfg_attr(feature = "network", serde(tag = "protocol", rename_all = "camelCase"))]
1114pub enum InternalizeOutput {
1115    #[cfg_attr(feature = "network", serde(rename = "wallet payment"))]
1116    WalletPayment {
1117        output_index: u32,
1118        #[cfg_attr(feature = "network", serde(rename = "paymentRemittance"))]
1119        payment: Payment,
1120    },
1121    #[cfg_attr(feature = "network", serde(rename = "basket insertion"))]
1122    BasketInsertion {
1123        output_index: u32,
1124        #[cfg_attr(feature = "network", serde(rename = "insertionRemittance"))]
1125        insertion: BasketInsertion,
1126    },
1127}
1128
1129/// Arguments for importing an external transaction into the wallet.
1130#[derive(Clone, Debug)]
1131#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1132#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1133pub struct InternalizeActionArgs {
1134    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1135    pub tx: Vec<u8>,
1136    pub description: String,
1137    #[cfg_attr(
1138        feature = "network",
1139        serde(skip_serializing_if = "Vec::is_empty", default)
1140    )]
1141    pub labels: Vec<LabelStringUnder300Bytes>,
1142    pub seek_permission: BooleanDefaultTrue,
1143    pub outputs: Vec<InternalizeOutput>,
1144}
1145
1146/// Result of internalizing a transaction.
1147#[derive(Clone, Debug)]
1148#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1149#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1150pub struct InternalizeActionResult {
1151    pub accepted: bool,
1152}
1153
1154// ---------------------------------------------------------------------------
1155// ListOutputs
1156// ---------------------------------------------------------------------------
1157
1158/// Filtering and options for listing wallet outputs.
1159#[derive(Clone, Debug)]
1160#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1161#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1162pub struct ListOutputsArgs {
1163    pub basket: BasketStringUnder300Bytes,
1164    #[cfg_attr(
1165        feature = "network",
1166        serde(skip_serializing_if = "Vec::is_empty", default)
1167    )]
1168    pub tags: Vec<OutputTagStringUnder300Bytes>,
1169    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1170    pub tag_query_mode: Option<QueryMode>,
1171    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1172    pub include: Option<OutputInclude>,
1173    #[cfg_attr(feature = "network", serde(skip_serializing_if = "BooleanDefaultFalse::is_none"))]
1174    pub include_custom_instructions: BooleanDefaultFalse,
1175    #[cfg_attr(feature = "network", serde(skip_serializing_if = "BooleanDefaultFalse::is_none"))]
1176    pub include_tags: BooleanDefaultFalse,
1177    #[cfg_attr(feature = "network", serde(skip_serializing_if = "BooleanDefaultFalse::is_none"))]
1178    pub include_labels: BooleanDefaultFalse,
1179    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1180    pub limit: PositiveIntegerDefault10Max10000,
1181    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1182    pub offset: Option<PositiveIntegerOrZero>,
1183    #[cfg_attr(feature = "network", serde(skip_serializing_if = "BooleanDefaultTrue::is_none"))]
1184    pub seek_permission: BooleanDefaultTrue,
1185}
1186
1187/// A wallet UTXO with its metadata.
1188#[derive(Clone, Debug)]
1189#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1190#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1191pub struct Output {
1192    pub satoshis: SatoshiValue,
1193    #[cfg_attr(
1194        feature = "network",
1195        serde(with = "serde_helpers::option_bytes_as_hex")
1196    )]
1197    #[cfg_attr(
1198        feature = "network",
1199        serde(skip_serializing_if = "Option::is_none", default)
1200    )]
1201    pub locking_script: Option<Vec<u8>>,
1202    pub spendable: bool,
1203    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1204    pub custom_instructions: Option<String>,
1205    #[cfg_attr(
1206        feature = "network",
1207        serde(skip_serializing_if = "Vec::is_empty", default)
1208    )]
1209    pub tags: Vec<String>,
1210    pub outpoint: OutpointString,
1211    #[cfg_attr(
1212        feature = "network",
1213        serde(skip_serializing_if = "Vec::is_empty", default)
1214    )]
1215    pub labels: Vec<String>,
1216}
1217
1218/// Paginated list of wallet outputs.
1219#[derive(Clone, Debug)]
1220#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1221#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1222pub struct ListOutputsResult {
1223    pub total_outputs: u32,
1224    #[cfg_attr(
1225        feature = "network",
1226        serde(with = "serde_helpers::option_bytes_as_array")
1227    )]
1228    #[cfg_attr(
1229        feature = "network",
1230        serde(skip_serializing_if = "Option::is_none", default)
1231    )]
1232    #[cfg_attr(feature = "network", serde(rename = "BEEF"))]
1233    pub beef: Option<Vec<u8>>,
1234    pub outputs: Vec<Output>,
1235}
1236
1237// ---------------------------------------------------------------------------
1238// RelinquishOutput
1239// ---------------------------------------------------------------------------
1240
1241/// Arguments for relinquishing ownership of an output.
1242#[derive(Clone, Debug)]
1243#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1244#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1245pub struct RelinquishOutputArgs {
1246    pub basket: BasketStringUnder300Bytes,
1247    pub output: OutpointString,
1248}
1249
1250/// Result of relinquishing an output.
1251#[derive(Clone, Debug)]
1252#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1253#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1254pub struct RelinquishOutputResult {
1255    pub relinquished: bool,
1256}
1257
1258// ---------------------------------------------------------------------------
1259// Key/Crypto types
1260// ---------------------------------------------------------------------------
1261
1262/// Arguments for getting a public key.
1263#[derive(Clone, Debug)]
1264#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1265#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1266pub struct GetPublicKeyArgs {
1267    pub identity_key: bool,
1268    #[cfg_attr(feature = "network", serde(rename = "protocolID"))]
1269    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1270    pub protocol_id: Option<Protocol>,
1271    #[cfg_attr(feature = "network", serde(rename = "keyID"))]
1272    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1273    pub key_id: Option<String>,
1274    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1275    pub counterparty: Option<Counterparty>,
1276    pub privileged: bool,
1277    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1278    pub privileged_reason: Option<String>,
1279    pub for_self: Option<bool>,
1280    pub seek_permission: Option<bool>,
1281}
1282
1283/// Result of getting a public key.
1284#[derive(Clone, Debug)]
1285#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1286#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1287pub struct GetPublicKeyResult {
1288    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1289    pub public_key: PublicKey,
1290}
1291
1292/// Arguments for encryption.
1293#[derive(Clone, Debug)]
1294#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1295#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1296pub struct EncryptArgs {
1297    #[cfg_attr(feature = "network", serde(rename = "protocolID"))]
1298    pub protocol_id: Protocol,
1299    #[cfg_attr(feature = "network", serde(rename = "keyID"))]
1300    pub key_id: String,
1301    pub counterparty: Counterparty,
1302    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1303    pub plaintext: Vec<u8>,
1304    pub privileged: bool,
1305    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1306    pub privileged_reason: Option<String>,
1307    pub seek_permission: Option<bool>,
1308}
1309
1310/// Result of encryption.
1311#[derive(Clone, Debug)]
1312#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1313#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1314pub struct EncryptResult {
1315    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1316    pub ciphertext: Vec<u8>,
1317}
1318
1319/// Arguments for decryption.
1320#[derive(Clone, Debug)]
1321#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1322#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1323pub struct DecryptArgs {
1324    #[cfg_attr(feature = "network", serde(rename = "protocolID"))]
1325    pub protocol_id: Protocol,
1326    #[cfg_attr(feature = "network", serde(rename = "keyID"))]
1327    pub key_id: String,
1328    pub counterparty: Counterparty,
1329    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1330    pub ciphertext: Vec<u8>,
1331    pub privileged: bool,
1332    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1333    pub privileged_reason: Option<String>,
1334    pub seek_permission: Option<bool>,
1335}
1336
1337/// Result of decryption.
1338#[derive(Clone, Debug)]
1339#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1340#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1341pub struct DecryptResult {
1342    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1343    pub plaintext: Vec<u8>,
1344}
1345
1346/// Arguments for creating an HMAC.
1347#[derive(Clone, Debug)]
1348#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1349#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1350pub struct CreateHmacArgs {
1351    #[cfg_attr(feature = "network", serde(rename = "protocolID"))]
1352    pub protocol_id: Protocol,
1353    #[cfg_attr(feature = "network", serde(rename = "keyID"))]
1354    pub key_id: String,
1355    pub counterparty: Counterparty,
1356    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1357    pub data: Vec<u8>,
1358    pub privileged: bool,
1359    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1360    pub privileged_reason: Option<String>,
1361    pub seek_permission: Option<bool>,
1362}
1363
1364/// Result of creating an HMAC.
1365#[derive(Clone, Debug)]
1366#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1367#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1368pub struct CreateHmacResult {
1369    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1370    pub hmac: Vec<u8>,
1371}
1372
1373/// Arguments for verifying an HMAC.
1374#[derive(Clone, Debug)]
1375#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1376#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1377pub struct VerifyHmacArgs {
1378    #[cfg_attr(feature = "network", serde(rename = "protocolID"))]
1379    pub protocol_id: Protocol,
1380    #[cfg_attr(feature = "network", serde(rename = "keyID"))]
1381    pub key_id: String,
1382    pub counterparty: Counterparty,
1383    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1384    pub data: Vec<u8>,
1385    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1386    pub hmac: Vec<u8>,
1387    pub privileged: bool,
1388    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1389    pub privileged_reason: Option<String>,
1390    pub seek_permission: Option<bool>,
1391}
1392
1393/// Result of verifying an HMAC.
1394#[derive(Clone, Debug)]
1395#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1396#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1397pub struct VerifyHmacResult {
1398    pub valid: bool,
1399}
1400
1401/// Arguments for creating a digital signature.
1402#[derive(Clone, Debug)]
1403#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1404#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1405pub struct CreateSignatureArgs {
1406    #[cfg_attr(feature = "network", serde(rename = "protocolID"))]
1407    pub protocol_id: Protocol,
1408    #[cfg_attr(feature = "network", serde(rename = "keyID"))]
1409    pub key_id: String,
1410    pub counterparty: Counterparty,
1411    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1412    pub data: Vec<u8>,
1413    pub privileged: bool,
1414    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1415    pub privileged_reason: Option<String>,
1416    pub seek_permission: Option<bool>,
1417}
1418
1419/// Result of creating a digital signature.
1420#[derive(Clone, Debug)]
1421#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1422#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1423pub struct CreateSignatureResult {
1424    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_hex"))]
1425    pub signature: Vec<u8>,
1426}
1427
1428/// Arguments for verifying a digital signature.
1429#[derive(Clone, Debug)]
1430#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1431#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1432pub struct VerifySignatureArgs {
1433    #[cfg_attr(feature = "network", serde(rename = "protocolID"))]
1434    pub protocol_id: Protocol,
1435    #[cfg_attr(feature = "network", serde(rename = "keyID"))]
1436    pub key_id: String,
1437    pub counterparty: Counterparty,
1438    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1439    pub data: Vec<u8>,
1440    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_hex"))]
1441    pub signature: Vec<u8>,
1442    pub for_self: Option<bool>,
1443    pub privileged: bool,
1444    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1445    pub privileged_reason: Option<String>,
1446    pub seek_permission: Option<bool>,
1447}
1448
1449/// Result of verifying a digital signature.
1450#[derive(Clone, Debug)]
1451#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1452#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1453pub struct VerifySignatureResult {
1454    pub valid: bool,
1455}
1456
1457// ---------------------------------------------------------------------------
1458// Certificate operations
1459// ---------------------------------------------------------------------------
1460
1461/// Arguments for acquiring a new certificate.
1462#[derive(Clone, Debug)]
1463#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1464#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1465pub struct AcquireCertificateArgs {
1466    #[cfg_attr(feature = "network", serde(rename = "type"))]
1467    pub cert_type: CertificateType,
1468    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1469    pub certifier: PublicKey,
1470    pub acquisition_protocol: AcquisitionProtocol,
1471    #[cfg_attr(
1472        feature = "network",
1473        serde(skip_serializing_if = "HashMap::is_empty", default)
1474    )]
1475    pub fields: HashMap<String, String>,
1476    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1477    pub serial_number: Option<SerialNumber>,
1478    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1479    pub revocation_outpoint: Option<String>,
1480    #[cfg_attr(
1481        feature = "network",
1482        serde(with = "serde_helpers::option_bytes_as_hex")
1483    )]
1484    #[cfg_attr(
1485        feature = "network",
1486        serde(skip_serializing_if = "Option::is_none", default)
1487    )]
1488    pub signature: Option<Vec<u8>>,
1489    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1490    pub certifier_url: Option<String>,
1491    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1492    pub keyring_revealer: Option<KeyringRevealer>,
1493    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1494    pub keyring_for_subject: Option<HashMap<String, String>>,
1495    pub privileged: bool,
1496    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1497    pub privileged_reason: Option<String>,
1498}
1499
1500/// Arguments for listing certificates.
1501#[derive(Clone, Debug)]
1502#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1503#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1504pub struct ListCertificatesArgs {
1505    #[cfg_attr(feature = "network", serde(with = "serde_helpers::vec_public_key_hex"))]
1506    pub certifiers: Vec<PublicKey>,
1507    pub types: Vec<CertificateType>,
1508    pub limit: PositiveIntegerDefault10Max10000,
1509    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1510    pub offset: Option<PositiveIntegerOrZero>,
1511    pub privileged: BooleanDefaultFalse,
1512    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1513    pub privileged_reason: Option<String>,
1514}
1515
1516/// A certificate with its keyring and verifier.
1517#[derive(Clone, Debug)]
1518#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1519#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1520pub struct CertificateResult {
1521    #[cfg_attr(feature = "network", serde(flatten))]
1522    pub certificate: Certificate,
1523    pub keyring: HashMap<String, String>,
1524    #[cfg_attr(
1525        feature = "network",
1526        serde(with = "serde_helpers::option_bytes_as_hex")
1527    )]
1528    #[cfg_attr(
1529        feature = "network",
1530        serde(skip_serializing_if = "Option::is_none", default)
1531    )]
1532    pub verifier: Option<Vec<u8>>,
1533}
1534
1535/// Paginated list of certificates.
1536#[derive(Clone, Debug)]
1537#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1538#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1539pub struct ListCertificatesResult {
1540    pub total_certificates: u32,
1541    pub certificates: Vec<CertificateResult>,
1542}
1543
1544/// Arguments for creating a verifiable certificate.
1545#[derive(Clone, Debug)]
1546#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1547#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1548pub struct ProveCertificateArgs {
1549    pub certificate: Certificate,
1550    pub fields_to_reveal: Vec<String>,
1551    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1552    pub verifier: PublicKey,
1553    pub privileged: BooleanDefaultFalse,
1554    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1555    pub privileged_reason: Option<String>,
1556}
1557
1558/// Result of creating a verifiable certificate.
1559#[derive(Clone, Debug)]
1560#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1561#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1562pub struct ProveCertificateResult {
1563    pub keyring_for_verifier: HashMap<String, String>,
1564}
1565
1566/// Arguments for relinquishing ownership of a certificate.
1567#[derive(Clone, Debug)]
1568#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1569#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1570pub struct RelinquishCertificateArgs {
1571    #[cfg_attr(feature = "network", serde(rename = "type"))]
1572    pub cert_type: CertificateType,
1573    pub serial_number: SerialNumber,
1574    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1575    pub certifier: PublicKey,
1576}
1577
1578/// Result of relinquishing a certificate.
1579#[derive(Clone, Debug)]
1580#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1581#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1582pub struct RelinquishCertificateResult {
1583    pub relinquished: bool,
1584}
1585
1586// ---------------------------------------------------------------------------
1587// Discovery types
1588// ---------------------------------------------------------------------------
1589
1590/// Information about an entity that issues identity certificates.
1591#[derive(Clone, Debug)]
1592#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1593#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1594pub struct IdentityCertifier {
1595    pub name: String,
1596    pub icon_url: String,
1597    pub description: String,
1598    pub trust: u8,
1599}
1600
1601/// An identity certificate with decoded fields and certifier info.
1602#[derive(Clone, Debug)]
1603#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1604#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1605pub struct IdentityCertificate {
1606    #[cfg_attr(feature = "network", serde(flatten))]
1607    pub certificate: Certificate,
1608    pub certifier_info: IdentityCertifier,
1609    pub publicly_revealed_keyring: HashMap<String, String>,
1610    pub decrypted_fields: HashMap<String, String>,
1611}
1612
1613/// Arguments for discovering certificates by identity key.
1614#[derive(Clone, Debug)]
1615#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1616#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1617pub struct DiscoverByIdentityKeyArgs {
1618    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1619    pub identity_key: PublicKey,
1620    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1621    pub limit: Option<u32>,
1622    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1623    pub offset: Option<u32>,
1624    pub seek_permission: Option<bool>,
1625}
1626
1627/// Arguments for discovering certificates by attributes.
1628#[derive(Clone, Debug)]
1629#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1630#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1631pub struct DiscoverByAttributesArgs {
1632    pub attributes: HashMap<String, String>,
1633    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1634    pub limit: Option<u32>,
1635    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1636    pub offset: Option<u32>,
1637    pub seek_permission: Option<bool>,
1638}
1639
1640/// Paginated list of identity certificates found during discovery.
1641#[derive(Clone, Debug)]
1642#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1643#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1644pub struct DiscoverCertificatesResult {
1645    pub total_certificates: u32,
1646    pub certificates: Vec<IdentityCertificate>,
1647}
1648
1649// ---------------------------------------------------------------------------
1650// Key linkage types
1651// ---------------------------------------------------------------------------
1652
1653/// Arguments for revealing key linkage between counterparties.
1654#[derive(Clone, Debug)]
1655#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1656#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1657pub struct RevealCounterpartyKeyLinkageArgs {
1658    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1659    pub counterparty: PublicKey,
1660    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1661    pub verifier: PublicKey,
1662    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1663    pub privileged: Option<bool>,
1664    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1665    pub privileged_reason: Option<String>,
1666}
1667
1668/// Result of revealing counterparty key linkage.
1669#[derive(Clone, Debug)]
1670#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1671#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1672pub struct RevealCounterpartyKeyLinkageResult {
1673    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1674    pub prover: PublicKey,
1675    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1676    pub counterparty: PublicKey,
1677    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1678    pub verifier: PublicKey,
1679    pub revelation_time: String,
1680    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1681    pub encrypted_linkage: Vec<u8>,
1682    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1683    pub encrypted_linkage_proof: Vec<u8>,
1684}
1685
1686/// Arguments for revealing specific key linkage.
1687#[derive(Clone, Debug)]
1688#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1689#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1690pub struct RevealSpecificKeyLinkageArgs {
1691    pub counterparty: Counterparty,
1692    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1693    pub verifier: PublicKey,
1694    #[cfg_attr(feature = "network", serde(rename = "protocolID"))]
1695    pub protocol_id: Protocol,
1696    #[cfg_attr(feature = "network", serde(rename = "keyID"))]
1697    pub key_id: String,
1698    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1699    pub privileged: Option<bool>,
1700    #[cfg_attr(feature = "network", serde(skip_serializing_if = "Option::is_none"))]
1701    pub privileged_reason: Option<String>,
1702}
1703
1704/// Result of revealing specific key linkage.
1705#[derive(Clone, Debug)]
1706#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1707#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1708pub struct RevealSpecificKeyLinkageResult {
1709    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1710    pub encrypted_linkage: Vec<u8>,
1711    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_array"))]
1712    pub encrypted_linkage_proof: Vec<u8>,
1713    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1714    pub prover: PublicKey,
1715    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1716    pub verifier: PublicKey,
1717    #[cfg_attr(feature = "network", serde(with = "serde_helpers::public_key_hex"))]
1718    pub counterparty: PublicKey,
1719    #[cfg_attr(feature = "network", serde(rename = "protocolID"))]
1720    pub protocol_id: Protocol,
1721    #[cfg_attr(feature = "network", serde(rename = "keyID"))]
1722    pub key_id: String,
1723    pub proof_type: u8,
1724}
1725
1726// ---------------------------------------------------------------------------
1727// Auth/Info types
1728// ---------------------------------------------------------------------------
1729
1730/// Whether the current session is authenticated.
1731#[derive(Clone, Debug)]
1732#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1733#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1734pub struct AuthenticatedResult {
1735    pub authenticated: bool,
1736}
1737
1738/// Current blockchain height.
1739#[derive(Clone, Debug)]
1740#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1741#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1742pub struct GetHeightResult {
1743    pub height: u32,
1744}
1745
1746/// Arguments for retrieving a blockchain header at a specific height.
1747#[derive(Clone, Debug)]
1748#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1749#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1750pub struct GetHeaderArgs {
1751    pub height: u32,
1752}
1753
1754/// Blockchain header data for the requested height.
1755#[derive(Clone, Debug)]
1756#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1757#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1758pub struct GetHeaderResult {
1759    #[cfg_attr(feature = "network", serde(with = "serde_helpers::bytes_as_hex"))]
1760    pub header: Vec<u8>,
1761}
1762
1763/// Current blockchain network.
1764#[derive(Clone, Debug)]
1765#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1766#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1767pub struct GetNetworkResult {
1768    pub network: Network,
1769}
1770
1771/// Version information about the wallet implementation.
1772#[derive(Clone, Debug)]
1773#[cfg_attr(feature = "network", derive(serde::Serialize, serde::Deserialize))]
1774#[cfg_attr(feature = "network", serde(rename_all = "camelCase"))]
1775pub struct GetVersionResult {
1776    pub version: String,
1777}
1778
1779// ---------------------------------------------------------------------------
1780// WalletInterface trait
1781// ---------------------------------------------------------------------------
1782
1783/// The core wallet interface with all 28 async methods.
1784///
1785/// Uses `#[async_trait]` for object safety -- supports both static dispatch
1786/// (`W: WalletInterface`) and dynamic dispatch (`dyn WalletInterface`).
1787///
1788/// Every method takes `originator: Option<&str>` as the last parameter,
1789/// identifying the calling application domain.
1790#[async_trait]
1791pub trait WalletInterface: Send + Sync {
1792    // -- Action methods --
1793
1794    async fn create_action(
1795        &self,
1796        args: CreateActionArgs,
1797        originator: Option<&str>,
1798    ) -> Result<CreateActionResult, WalletError>;
1799
1800    async fn sign_action(
1801        &self,
1802        args: SignActionArgs,
1803        originator: Option<&str>,
1804    ) -> Result<SignActionResult, WalletError>;
1805
1806    async fn abort_action(
1807        &self,
1808        args: AbortActionArgs,
1809        originator: Option<&str>,
1810    ) -> Result<AbortActionResult, WalletError>;
1811
1812    async fn list_actions(
1813        &self,
1814        args: ListActionsArgs,
1815        originator: Option<&str>,
1816    ) -> Result<ListActionsResult, WalletError>;
1817
1818    async fn internalize_action(
1819        &self,
1820        args: InternalizeActionArgs,
1821        originator: Option<&str>,
1822    ) -> Result<InternalizeActionResult, WalletError>;
1823
1824    // -- Output methods --
1825
1826    async fn list_outputs(
1827        &self,
1828        args: ListOutputsArgs,
1829        originator: Option<&str>,
1830    ) -> Result<ListOutputsResult, WalletError>;
1831
1832    async fn relinquish_output(
1833        &self,
1834        args: RelinquishOutputArgs,
1835        originator: Option<&str>,
1836    ) -> Result<RelinquishOutputResult, WalletError>;
1837
1838    // -- Key/Crypto methods --
1839
1840    async fn get_public_key(
1841        &self,
1842        args: GetPublicKeyArgs,
1843        originator: Option<&str>,
1844    ) -> Result<GetPublicKeyResult, WalletError>;
1845
1846    async fn reveal_counterparty_key_linkage(
1847        &self,
1848        args: RevealCounterpartyKeyLinkageArgs,
1849        originator: Option<&str>,
1850    ) -> Result<RevealCounterpartyKeyLinkageResult, WalletError>;
1851
1852    async fn reveal_specific_key_linkage(
1853        &self,
1854        args: RevealSpecificKeyLinkageArgs,
1855        originator: Option<&str>,
1856    ) -> Result<RevealSpecificKeyLinkageResult, WalletError>;
1857
1858    async fn encrypt(
1859        &self,
1860        args: EncryptArgs,
1861        originator: Option<&str>,
1862    ) -> Result<EncryptResult, WalletError>;
1863
1864    async fn decrypt(
1865        &self,
1866        args: DecryptArgs,
1867        originator: Option<&str>,
1868    ) -> Result<DecryptResult, WalletError>;
1869
1870    async fn create_hmac(
1871        &self,
1872        args: CreateHmacArgs,
1873        originator: Option<&str>,
1874    ) -> Result<CreateHmacResult, WalletError>;
1875
1876    async fn verify_hmac(
1877        &self,
1878        args: VerifyHmacArgs,
1879        originator: Option<&str>,
1880    ) -> Result<VerifyHmacResult, WalletError>;
1881
1882    async fn create_signature(
1883        &self,
1884        args: CreateSignatureArgs,
1885        originator: Option<&str>,
1886    ) -> Result<CreateSignatureResult, WalletError>;
1887
1888    async fn verify_signature(
1889        &self,
1890        args: VerifySignatureArgs,
1891        originator: Option<&str>,
1892    ) -> Result<VerifySignatureResult, WalletError>;
1893
1894    // -- Certificate methods --
1895
1896    async fn acquire_certificate(
1897        &self,
1898        args: AcquireCertificateArgs,
1899        originator: Option<&str>,
1900    ) -> Result<Certificate, WalletError>;
1901
1902    async fn list_certificates(
1903        &self,
1904        args: ListCertificatesArgs,
1905        originator: Option<&str>,
1906    ) -> Result<ListCertificatesResult, WalletError>;
1907
1908    async fn prove_certificate(
1909        &self,
1910        args: ProveCertificateArgs,
1911        originator: Option<&str>,
1912    ) -> Result<ProveCertificateResult, WalletError>;
1913
1914    async fn relinquish_certificate(
1915        &self,
1916        args: RelinquishCertificateArgs,
1917        originator: Option<&str>,
1918    ) -> Result<RelinquishCertificateResult, WalletError>;
1919
1920    // -- Discovery methods --
1921
1922    async fn discover_by_identity_key(
1923        &self,
1924        args: DiscoverByIdentityKeyArgs,
1925        originator: Option<&str>,
1926    ) -> Result<DiscoverCertificatesResult, WalletError>;
1927
1928    async fn discover_by_attributes(
1929        &self,
1930        args: DiscoverByAttributesArgs,
1931        originator: Option<&str>,
1932    ) -> Result<DiscoverCertificatesResult, WalletError>;
1933
1934    // -- Auth/Info methods --
1935
1936    async fn is_authenticated(
1937        &self,
1938        originator: Option<&str>,
1939    ) -> Result<AuthenticatedResult, WalletError>;
1940
1941    async fn wait_for_authentication(
1942        &self,
1943        originator: Option<&str>,
1944    ) -> Result<AuthenticatedResult, WalletError>;
1945
1946    async fn get_height(&self, originator: Option<&str>) -> Result<GetHeightResult, WalletError>;
1947
1948    async fn get_header_for_height(
1949        &self,
1950        args: GetHeaderArgs,
1951        originator: Option<&str>,
1952    ) -> Result<GetHeaderResult, WalletError>;
1953
1954    async fn get_network(&self, originator: Option<&str>) -> Result<GetNetworkResult, WalletError>;
1955
1956    async fn get_version(&self, originator: Option<&str>) -> Result<GetVersionResult, WalletError>;
1957}
1958
1959#[cfg(test)]
1960mod tests {
1961    use super::*;
1962
1963    #[test]
1964    fn test_serial_number_from_string_hex_valid() {
1965        let hex = "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2";
1966        let sn = SerialNumber::from_string(hex).unwrap();
1967        assert_eq!(sn.0[0], 0xa1);
1968        assert_eq!(sn.0[31], 0xb2);
1969    }
1970
1971    #[test]
1972    fn test_serial_number_from_string_base64_valid() {
1973        // 32 bytes of zeros -> base64 is "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
1974        let b64 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
1975        let sn = SerialNumber::from_string(b64).unwrap();
1976        assert_eq!(sn.0, [0u8; 32]);
1977    }
1978
1979    #[test]
1980    fn test_serial_number_from_string_base64_nonzero() {
1981        // All 0xFF bytes: base64 = "//////////////////////////////////////////8="
1982        let b64 = "//////////////////////////////////////////8=";
1983        let sn = SerialNumber::from_string(b64).unwrap();
1984        assert_eq!(sn.0, [0xffu8; 32]);
1985    }
1986
1987    #[test]
1988    fn test_serial_number_from_string_invalid_length() {
1989        assert!(SerialNumber::from_string("abc").is_err());
1990        assert!(SerialNumber::from_string("").is_err());
1991        assert!(SerialNumber::from_string("a1b2c3").is_err());
1992    }
1993
1994    #[test]
1995    fn test_serial_number_from_string_invalid_chars() {
1996        // 64 chars but not valid hex
1997        let bad_hex = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz";
1998        assert!(SerialNumber::from_string(bad_hex).is_err());
1999    }
2000}