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