cdk_ffi/types/
keys.rs

1//! Key-related FFI types
2
3use std::collections::HashMap;
4
5use serde::{Deserialize, Serialize};
6
7use super::amount::CurrencyUnit;
8use crate::error::FfiError;
9
10/// FFI-compatible KeySetInfo
11#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
12pub struct KeySetInfo {
13    pub id: String,
14    pub unit: CurrencyUnit,
15    pub active: bool,
16    /// Input fee per thousand (ppk)
17    pub input_fee_ppk: u64,
18}
19
20impl From<cdk::nuts::KeySetInfo> for KeySetInfo {
21    fn from(keyset: cdk::nuts::KeySetInfo) -> Self {
22        Self {
23            id: keyset.id.to_string(),
24            unit: keyset.unit.into(),
25            active: keyset.active,
26            input_fee_ppk: keyset.input_fee_ppk,
27        }
28    }
29}
30
31impl From<KeySetInfo> for cdk::nuts::KeySetInfo {
32    fn from(keyset: KeySetInfo) -> Self {
33        use std::str::FromStr;
34        Self {
35            id: cdk::nuts::Id::from_str(&keyset.id).unwrap(),
36            unit: keyset.unit.into(),
37            active: keyset.active,
38            final_expiry: None,
39            input_fee_ppk: keyset.input_fee_ppk,
40        }
41    }
42}
43
44impl KeySetInfo {
45    /// Convert KeySetInfo to JSON string
46    pub fn to_json(&self) -> Result<String, FfiError> {
47        Ok(serde_json::to_string(self)?)
48    }
49}
50
51/// Decode KeySetInfo from JSON string
52#[uniffi::export]
53pub fn decode_key_set_info(json: String) -> Result<KeySetInfo, FfiError> {
54    Ok(serde_json::from_str(&json)?)
55}
56
57/// Encode KeySetInfo to JSON string
58#[uniffi::export]
59pub fn encode_key_set_info(info: KeySetInfo) -> Result<String, FfiError> {
60    Ok(serde_json::to_string(&info)?)
61}
62
63/// FFI-compatible PublicKey
64#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
65#[serde(transparent)]
66pub struct PublicKey {
67    /// Hex-encoded public key
68    pub hex: String,
69}
70
71impl From<cdk::nuts::PublicKey> for PublicKey {
72    fn from(key: cdk::nuts::PublicKey) -> Self {
73        Self {
74            hex: key.to_string(),
75        }
76    }
77}
78
79impl TryFrom<PublicKey> for cdk::nuts::PublicKey {
80    type Error = FfiError;
81
82    fn try_from(key: PublicKey) -> Result<Self, Self::Error> {
83        key.hex
84            .parse()
85            .map_err(|e| FfiError::InvalidCryptographicKey {
86                msg: format!("Invalid public key: {}", e),
87            })
88    }
89}
90
91/// FFI-compatible Keys (simplified - contains only essential info)
92#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
93pub struct Keys {
94    /// Keyset ID
95    pub id: String,
96    /// Currency unit
97    pub unit: CurrencyUnit,
98    /// Map of amount to public key hex (simplified from BTreeMap)
99    pub keys: HashMap<u64, String>,
100}
101
102impl From<cdk::nuts::Keys> for Keys {
103    fn from(keys: cdk::nuts::Keys) -> Self {
104        // Keys doesn't have id and unit - we'll need to get these from context
105        // For now, use placeholder values
106        Self {
107            id: "unknown".to_string(), // This should come from KeySet
108            unit: CurrencyUnit::Sat,   // This should come from KeySet
109            keys: keys
110                .keys()
111                .iter()
112                .map(|(amount, pubkey)| (u64::from(*amount), pubkey.to_string()))
113                .collect(),
114        }
115    }
116}
117
118impl TryFrom<Keys> for cdk::nuts::Keys {
119    type Error = FfiError;
120
121    fn try_from(keys: Keys) -> Result<Self, Self::Error> {
122        use std::collections::BTreeMap;
123        use std::str::FromStr;
124
125        // Convert the HashMap to BTreeMap with proper types
126        let mut keys_map = BTreeMap::new();
127        for (amount_u64, pubkey_hex) in keys.keys {
128            let amount = cdk::Amount::from(amount_u64);
129            let pubkey = cdk::nuts::PublicKey::from_str(&pubkey_hex)
130                .map_err(|e| FfiError::InvalidCryptographicKey { msg: e.to_string() })?;
131            keys_map.insert(amount, pubkey);
132        }
133
134        Ok(cdk::nuts::Keys::new(keys_map))
135    }
136}
137
138impl Keys {
139    /// Convert Keys to JSON string
140    pub fn to_json(&self) -> Result<String, FfiError> {
141        Ok(serde_json::to_string(self)?)
142    }
143}
144
145/// Decode Keys from JSON string
146#[uniffi::export]
147pub fn decode_keys(json: String) -> Result<Keys, FfiError> {
148    Ok(serde_json::from_str(&json)?)
149}
150
151/// Encode Keys to JSON string
152#[uniffi::export]
153pub fn encode_keys(keys: Keys) -> Result<String, FfiError> {
154    Ok(serde_json::to_string(&keys)?)
155}
156
157/// FFI-compatible KeySet
158#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
159pub struct KeySet {
160    /// Keyset ID
161    pub id: String,
162    /// Currency unit
163    pub unit: CurrencyUnit,
164    /// The keys (map of amount to public key hex)
165    pub keys: HashMap<u64, String>,
166    /// Optional expiry timestamp
167    pub final_expiry: Option<u64>,
168}
169
170impl From<cdk::nuts::KeySet> for KeySet {
171    fn from(keyset: cdk::nuts::KeySet) -> Self {
172        Self {
173            id: keyset.id.to_string(),
174            unit: keyset.unit.into(),
175            keys: keyset
176                .keys
177                .keys()
178                .iter()
179                .map(|(amount, pubkey)| (u64::from(*amount), pubkey.to_string()))
180                .collect(),
181            final_expiry: keyset.final_expiry,
182        }
183    }
184}
185
186impl TryFrom<KeySet> for cdk::nuts::KeySet {
187    type Error = FfiError;
188
189    fn try_from(keyset: KeySet) -> Result<Self, Self::Error> {
190        use std::collections::BTreeMap;
191        use std::str::FromStr;
192
193        // Convert id
194        let id = cdk::nuts::Id::from_str(&keyset.id)
195            .map_err(|e| FfiError::Serialization { msg: e.to_string() })?;
196
197        // Convert unit
198        let unit: cdk::nuts::CurrencyUnit = keyset.unit.into();
199
200        // Convert keys
201        let mut keys_map = BTreeMap::new();
202        for (amount_u64, pubkey_hex) in keyset.keys {
203            let amount = cdk::Amount::from(amount_u64);
204            let pubkey = cdk::nuts::PublicKey::from_str(&pubkey_hex)
205                .map_err(|e| FfiError::InvalidCryptographicKey { msg: e.to_string() })?;
206            keys_map.insert(amount, pubkey);
207        }
208        let keys = cdk::nuts::Keys::new(keys_map);
209
210        Ok(cdk::nuts::KeySet {
211            id,
212            unit,
213            keys,
214            final_expiry: keyset.final_expiry,
215        })
216    }
217}
218
219impl KeySet {
220    /// Convert KeySet to JSON string
221    pub fn to_json(&self) -> Result<String, FfiError> {
222        Ok(serde_json::to_string(self)?)
223    }
224}
225
226/// Decode KeySet from JSON string
227#[uniffi::export]
228pub fn decode_key_set(json: String) -> Result<KeySet, FfiError> {
229    Ok(serde_json::from_str(&json)?)
230}
231
232/// Encode KeySet to JSON string
233#[uniffi::export]
234pub fn encode_key_set(keyset: KeySet) -> Result<String, FfiError> {
235    Ok(serde_json::to_string(&keyset)?)
236}
237
238/// FFI-compatible Id (for keyset IDs)
239#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
240#[serde(transparent)]
241pub struct Id {
242    pub hex: String,
243}
244
245impl From<cdk::nuts::Id> for Id {
246    fn from(id: cdk::nuts::Id) -> Self {
247        Self {
248            hex: id.to_string(),
249        }
250    }
251}
252
253impl From<Id> for cdk::nuts::Id {
254    fn from(id: Id) -> Self {
255        use std::str::FromStr;
256        Self::from_str(&id.hex).unwrap()
257    }
258}