1use async_trait::async_trait;
5use bitcoin::PublicKey;
6use bitcoin::secp256k1::{All, Secp256k1};
7use std::sync::Arc;
8
9use crate::apdu::StatusResponse;
10use crate::error::{ReadError, StatusError};
11use crate::shared::{
12 Authentication, Certificate, CkTransport, Nfc, Read, Wait, card_pubkey_to_ident,
13};
14use crate::tap_signer::TapSignerShared;
15
16pub struct SatsChip {
21 pub transport: Arc<dyn CkTransport>,
22 pub secp: Secp256k1<All>,
23 pub proto: u32,
24 pub ver: String,
25 pub birth: u32,
26 pub path: Option<Vec<u32>>,
27 pub num_backups: Option<u32>,
29 pub pubkey: PublicKey,
30 pub card_nonce: [u8; 16],
31 pub auth_delay: Option<u8>,
32}
33
34impl Authentication for SatsChip {
35 fn secp(&self) -> &Secp256k1<All> {
36 &self.secp
37 }
38
39 fn ver(&self) -> &str {
40 &self.ver
41 }
42
43 fn pubkey(&self) -> &PublicKey {
44 &self.pubkey
45 }
46
47 fn card_nonce(&self) -> &[u8; 16] {
48 &self.card_nonce
49 }
50
51 fn set_card_nonce(&mut self, new_nonce: [u8; 16]) {
52 self.card_nonce = new_nonce;
53 }
54
55 fn auth_delay(&self) -> Option<u8> {
56 self.auth_delay
57 }
58
59 fn set_auth_delay(&mut self, auth_delay: Option<u8>) {
60 self.auth_delay = auth_delay;
61 }
62
63 fn transport(&self) -> Arc<dyn CkTransport> {
64 self.transport.clone()
65 }
66}
67
68#[async_trait]
69impl TapSignerShared for SatsChip {}
70
71impl SatsChip {
72 pub fn card_ident(&self) -> String {
73 card_pubkey_to_ident(&self.pubkey)
74 }
75
76 pub fn try_from_status(
77 transport: Arc<dyn CkTransport>,
78 status_response: StatusResponse,
79 ) -> Result<Self, StatusError> {
80 let pubkey = status_response.pubkey.as_slice();
81 let pubkey = PublicKey::from_slice(pubkey).map_err(StatusError::from)?;
82
83 Ok(SatsChip {
84 transport,
85 secp: Secp256k1::new(),
86 proto: status_response.proto,
87 ver: status_response.ver,
88 birth: status_response.birth,
89 path: status_response.path,
90 num_backups: status_response.num_backups,
91 pubkey,
92 card_nonce: status_response.card_nonce,
93 auth_delay: status_response.auth_delay,
94 })
95 }
96}
97
98#[async_trait]
99impl Wait for SatsChip {}
100
101#[async_trait]
102impl Read for SatsChip {
103 fn requires_auth(&self) -> bool {
104 true
105 }
106
107 fn slot(&self) -> Option<u8> {
108 None
109 }
110}
111
112#[async_trait]
113impl Certificate for SatsChip {
114 async fn slot_pubkey(&mut self) -> Result<Option<PublicKey>, ReadError> {
115 Ok(None)
116 }
117}
118
119#[async_trait]
120impl Nfc for SatsChip {}
121
122impl core::fmt::Debug for SatsChip {
123 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
124 f.debug_struct("SatsChip")
125 .field("proto", &self.proto)
126 .field("ver", &self.ver)
127 .field("birth", &self.birth)
128 .field("path", &self.path)
129 .field("num_backups", &self.num_backups)
130 .field("card_ident", &self.card_ident())
131 .field("pubkey", &self.pubkey)
132 .field("card_nonce", &self.card_nonce)
133 .field("auth_delay", &self.auth_delay)
134 .finish()
135 }
136}