lib.rs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. //! CDK FFI Bindings
  2. //!
  3. //! UniFFI bindings for the CDK Wallet and related types.
  4. pub mod database;
  5. pub mod error;
  6. pub mod multi_mint_wallet;
  7. pub mod types;
  8. pub mod wallet;
  9. pub use database::*;
  10. pub use error::*;
  11. pub use multi_mint_wallet::*;
  12. pub use types::*;
  13. pub use wallet::*;
  14. uniffi::setup_scaffolding!();
  15. #[cfg(test)]
  16. mod tests {
  17. use super::*;
  18. #[test]
  19. fn test_amount_conversion() {
  20. let amount = Amount::new(1000);
  21. assert_eq!(amount.value, 1000);
  22. assert!(!amount.is_zero());
  23. let zero = Amount::zero();
  24. assert!(zero.is_zero());
  25. }
  26. #[test]
  27. fn test_currency_unit_conversion() {
  28. use cdk::nuts::CurrencyUnit as CdkCurrencyUnit;
  29. let unit = CurrencyUnit::Sat;
  30. let cdk_unit: CdkCurrencyUnit = unit.into();
  31. let back: CurrencyUnit = cdk_unit.into();
  32. assert_eq!(back, CurrencyUnit::Sat);
  33. }
  34. #[test]
  35. fn test_mint_url_creation() {
  36. let url = MintUrl::new("https://mint.example.com".to_string());
  37. assert!(url.is_ok());
  38. let invalid_url = MintUrl::new("not-a-url".to_string());
  39. assert!(invalid_url.is_err());
  40. }
  41. #[test]
  42. fn test_send_options_default() {
  43. let options = SendOptions::default();
  44. assert!(options.memo.is_none());
  45. assert!(options.conditions.is_none());
  46. assert!(matches!(options.amount_split_target, SplitTarget::None));
  47. assert!(matches!(options.send_kind, SendKind::OnlineExact));
  48. assert!(!options.include_fee);
  49. assert!(options.max_proofs.is_none());
  50. assert!(options.metadata.is_empty());
  51. }
  52. #[test]
  53. fn test_receive_options_default() {
  54. let options = ReceiveOptions::default();
  55. assert!(matches!(options.amount_split_target, SplitTarget::None));
  56. assert!(options.p2pk_signing_keys.is_empty());
  57. assert!(options.preimages.is_empty());
  58. assert!(options.metadata.is_empty());
  59. }
  60. #[test]
  61. fn test_send_memo() {
  62. let memo_text = "Test memo".to_string();
  63. let memo = SendMemo {
  64. memo: memo_text.clone(),
  65. include_memo: true,
  66. };
  67. assert_eq!(memo.memo, memo_text);
  68. assert!(memo.include_memo);
  69. }
  70. #[test]
  71. fn test_split_target_variants() {
  72. let split_none = SplitTarget::None;
  73. assert!(matches!(split_none, SplitTarget::None));
  74. let amount = Amount::new(1000);
  75. let split_value = SplitTarget::Value { amount };
  76. assert!(matches!(split_value, SplitTarget::Value { .. }));
  77. let amounts = vec![Amount::new(100), Amount::new(200)];
  78. let split_values = SplitTarget::Values { amounts };
  79. assert!(matches!(split_values, SplitTarget::Values { .. }));
  80. }
  81. #[test]
  82. fn test_send_kind_variants() {
  83. let online_exact = SendKind::OnlineExact;
  84. assert!(matches!(online_exact, SendKind::OnlineExact));
  85. let tolerance = Amount::new(50);
  86. let online_tolerance = SendKind::OnlineTolerance { tolerance };
  87. assert!(matches!(online_tolerance, SendKind::OnlineTolerance { .. }));
  88. let offline_exact = SendKind::OfflineExact;
  89. assert!(matches!(offline_exact, SendKind::OfflineExact));
  90. let offline_tolerance = SendKind::OfflineTolerance { tolerance };
  91. assert!(matches!(
  92. offline_tolerance,
  93. SendKind::OfflineTolerance { .. }
  94. ));
  95. }
  96. #[test]
  97. fn test_secret_key_from_hex() {
  98. // Test valid hex string (64 characters)
  99. let valid_hex = "a".repeat(64);
  100. let secret_key = SecretKey::from_hex(valid_hex.clone());
  101. assert!(secret_key.is_ok());
  102. assert_eq!(secret_key.unwrap().hex, valid_hex);
  103. // Test invalid length
  104. let invalid_length = "a".repeat(32); // 32 chars instead of 64
  105. let secret_key = SecretKey::from_hex(invalid_length);
  106. assert!(secret_key.is_err());
  107. // Test invalid characters
  108. let invalid_chars = "g".repeat(64); // 'g' is not a valid hex character
  109. let secret_key = SecretKey::from_hex(invalid_chars);
  110. assert!(secret_key.is_err());
  111. }
  112. #[test]
  113. fn test_secret_key_random() {
  114. let key1 = SecretKey::random();
  115. let key2 = SecretKey::random();
  116. // Keys should be different
  117. assert_ne!(key1.hex, key2.hex);
  118. // Keys should be valid hex (64 characters)
  119. assert_eq!(key1.hex.len(), 64);
  120. assert_eq!(key2.hex.len(), 64);
  121. assert!(key1.hex.chars().all(|c| c.is_ascii_hexdigit()));
  122. assert!(key2.hex.chars().all(|c| c.is_ascii_hexdigit()));
  123. }
  124. #[test]
  125. fn test_send_options_with_all_fields() {
  126. use std::collections::HashMap;
  127. let memo = SendMemo {
  128. memo: "Test memo".to_string(),
  129. include_memo: true,
  130. };
  131. let mut metadata = HashMap::new();
  132. metadata.insert("key1".to_string(), "value1".to_string());
  133. let conditions = SpendingConditions::P2PK {
  134. pubkey: "02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc"
  135. .to_string(),
  136. conditions: None,
  137. };
  138. let options = SendOptions {
  139. memo: Some(memo),
  140. conditions: Some(conditions),
  141. amount_split_target: SplitTarget::Value {
  142. amount: Amount::new(1000),
  143. },
  144. send_kind: SendKind::OnlineTolerance {
  145. tolerance: Amount::new(50),
  146. },
  147. include_fee: true,
  148. max_proofs: Some(10),
  149. metadata,
  150. };
  151. assert!(options.memo.is_some());
  152. assert!(options.conditions.is_some());
  153. assert!(matches!(
  154. options.amount_split_target,
  155. SplitTarget::Value { .. }
  156. ));
  157. assert!(matches!(
  158. options.send_kind,
  159. SendKind::OnlineTolerance { .. }
  160. ));
  161. assert!(options.include_fee);
  162. assert_eq!(options.max_proofs, Some(10));
  163. assert!(!options.metadata.is_empty());
  164. }
  165. #[test]
  166. fn test_receive_options_with_all_fields() {
  167. use std::collections::HashMap;
  168. let secret_key = SecretKey::random();
  169. let mut metadata = HashMap::new();
  170. metadata.insert("key1".to_string(), "value1".to_string());
  171. let options = ReceiveOptions {
  172. amount_split_target: SplitTarget::Values {
  173. amounts: vec![Amount::new(100), Amount::new(200)],
  174. },
  175. p2pk_signing_keys: vec![secret_key],
  176. preimages: vec!["preimage1".to_string(), "preimage2".to_string()],
  177. metadata,
  178. };
  179. assert!(matches!(
  180. options.amount_split_target,
  181. SplitTarget::Values { .. }
  182. ));
  183. assert_eq!(options.p2pk_signing_keys.len(), 1);
  184. assert_eq!(options.preimages.len(), 2);
  185. assert!(!options.metadata.is_empty());
  186. }
  187. #[test]
  188. fn test_wallet_config() {
  189. let config = WalletConfig {
  190. target_proof_count: None,
  191. };
  192. assert!(config.target_proof_count.is_none());
  193. let config_with_values = WalletConfig {
  194. target_proof_count: Some(5),
  195. };
  196. assert_eq!(config_with_values.target_proof_count, Some(5));
  197. }
  198. #[test]
  199. fn test_mnemonic_generation() {
  200. // Test mnemonic generation
  201. let mnemonic = generate_mnemonic().unwrap();
  202. assert!(!mnemonic.is_empty());
  203. assert_eq!(mnemonic.split_whitespace().count(), 12);
  204. // Verify it's a valid mnemonic by trying to parse it
  205. use bip39::Mnemonic;
  206. let parsed = Mnemonic::parse(&mnemonic);
  207. assert!(parsed.is_ok());
  208. }
  209. #[test]
  210. fn test_mnemonic_validation() {
  211. // Test with valid mnemonic
  212. let mnemonic = generate_mnemonic().unwrap();
  213. use bip39::Mnemonic;
  214. let parsed = Mnemonic::parse(&mnemonic);
  215. assert!(parsed.is_ok());
  216. // Test with invalid mnemonic
  217. let invalid_mnemonic = "invalid mnemonic phrase that should not work";
  218. let parsed_invalid = Mnemonic::parse(invalid_mnemonic);
  219. assert!(parsed_invalid.is_err());
  220. // Test mnemonic word count variations
  221. let mnemonic_12 = generate_mnemonic().unwrap();
  222. assert_eq!(mnemonic_12.split_whitespace().count(), 12);
  223. }
  224. #[test]
  225. fn test_mnemonic_to_entropy() {
  226. // Test with generated mnemonic
  227. let mnemonic = generate_mnemonic().unwrap();
  228. let entropy = mnemonic_to_entropy(mnemonic.clone()).unwrap();
  229. // For a 12-word mnemonic, entropy should be 16 bytes (128 bits)
  230. assert_eq!(entropy.len(), 16);
  231. // Test that we can recreate the mnemonic from entropy
  232. use bip39::Mnemonic;
  233. let recreated_mnemonic = Mnemonic::from_entropy(&entropy).unwrap();
  234. assert_eq!(recreated_mnemonic.to_string(), mnemonic);
  235. // Test with invalid mnemonic
  236. let invalid_result = mnemonic_to_entropy("invalid mnemonic".to_string());
  237. assert!(invalid_result.is_err());
  238. }
  239. }