token.rs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. //! FFI token bindings
  2. use std::collections::BTreeSet;
  3. use std::str::FromStr;
  4. use crate::error::FfiError;
  5. use crate::{Amount, CurrencyUnit, KeySetInfo, MintUrl, Proofs};
  6. /// FFI-compatible Token
  7. #[derive(Debug, uniffi::Object)]
  8. pub struct Token {
  9. pub(crate) inner: cdk::nuts::Token,
  10. }
  11. impl std::fmt::Display for Token {
  12. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  13. write!(f, "{}", self.inner)
  14. }
  15. }
  16. impl FromStr for Token {
  17. type Err = FfiError;
  18. fn from_str(s: &str) -> Result<Self, Self::Err> {
  19. let token = cdk::nuts::Token::from_str(s)
  20. .map_err(|e| FfiError::internal(format!("Invalid token: {}", e)))?;
  21. Ok(Token { inner: token })
  22. }
  23. }
  24. impl From<cdk::nuts::Token> for Token {
  25. fn from(token: cdk::nuts::Token) -> Self {
  26. Self { inner: token }
  27. }
  28. }
  29. impl From<Token> for cdk::nuts::Token {
  30. fn from(token: Token) -> Self {
  31. token.inner
  32. }
  33. }
  34. #[uniffi::export]
  35. impl Token {
  36. /// Create a new Token from string
  37. #[uniffi::constructor]
  38. pub fn from_string(encoded_token: String) -> Result<Token, FfiError> {
  39. let token = cdk::nuts::Token::from_str(&encoded_token)
  40. .map_err(|e| FfiError::internal(format!("Invalid token: {}", e)))?;
  41. Ok(Token { inner: token })
  42. }
  43. /// Get the total value of the token
  44. pub fn value(&self) -> Result<Amount, FfiError> {
  45. Ok(self.inner.value()?.into())
  46. }
  47. /// Get the memo from the token
  48. pub fn memo(&self) -> Option<String> {
  49. self.inner.memo().clone()
  50. }
  51. /// Get the currency unit
  52. pub fn unit(&self) -> Option<CurrencyUnit> {
  53. self.inner.unit().map(Into::into)
  54. }
  55. /// Get the mint URL
  56. pub fn mint_url(&self) -> Result<MintUrl, FfiError> {
  57. Ok(self.inner.mint_url()?.into())
  58. }
  59. /// Get proofs from the token (simplified - no keyset filtering for now)
  60. pub fn proofs_simple(&self) -> Result<Proofs, FfiError> {
  61. // For now, return empty keysets to get all proofs
  62. let empty_keysets = vec![];
  63. let proofs = self.inner.proofs(&empty_keysets)?;
  64. Ok(proofs.into_iter().map(|p| p.into()).collect())
  65. }
  66. /// Get proofs from the token
  67. pub fn proofs(&self, mint_keysets: Vec<KeySetInfo>) -> Result<Proofs, FfiError> {
  68. let mint_keysets: Vec<_> = mint_keysets.into_iter().map(|k| k.into()).collect();
  69. let proofs = self.inner.proofs(&mint_keysets)?;
  70. Ok(proofs.into_iter().map(|p| p.into()).collect())
  71. }
  72. /// Convert token to raw bytes
  73. pub fn to_raw_bytes(&self) -> Result<Vec<u8>, FfiError> {
  74. Ok(self.inner.to_raw_bytes()?)
  75. }
  76. /// Encode token to string representation
  77. pub fn encode(&self) -> String {
  78. self.to_string()
  79. }
  80. /// Decode token from raw bytes
  81. #[uniffi::constructor]
  82. pub fn from_raw_bytes(bytes: Vec<u8>) -> Result<Token, FfiError> {
  83. let token = cdk::nuts::Token::try_from(&bytes)?;
  84. Ok(Token { inner: token })
  85. }
  86. /// Decode token from string representation
  87. #[uniffi::constructor]
  88. pub fn decode(encoded_token: String) -> Result<Token, FfiError> {
  89. encoded_token.parse()
  90. }
  91. /// Return unique spending conditions across all proofs in this token
  92. pub fn spending_conditions(&self) -> Vec<crate::types::SpendingConditions> {
  93. self.inner
  94. .spending_conditions()
  95. .map(|set| set.into_iter().map(Into::into).collect())
  96. .unwrap_or_default()
  97. }
  98. /// Return all P2PK pubkeys referenced by this token's spending conditions
  99. pub fn p2pk_pubkeys(&self) -> Vec<String> {
  100. let set = self
  101. .inner
  102. .p2pk_pubkeys()
  103. .map(|keys| {
  104. keys.into_iter()
  105. .map(|k| k.to_string())
  106. .collect::<BTreeSet<_>>()
  107. })
  108. .unwrap_or_default();
  109. set.into_iter().collect()
  110. }
  111. /// Return all refund pubkeys from P2PK spending conditions
  112. pub fn p2pk_refund_pubkeys(&self) -> Vec<String> {
  113. let set = self
  114. .inner
  115. .p2pk_refund_pubkeys()
  116. .map(|keys| {
  117. keys.into_iter()
  118. .map(|k| k.to_string())
  119. .collect::<BTreeSet<_>>()
  120. })
  121. .unwrap_or_default();
  122. set.into_iter().collect()
  123. }
  124. /// Return all HTLC hashes from spending conditions
  125. pub fn htlc_hashes(&self) -> Vec<String> {
  126. let set = self
  127. .inner
  128. .htlc_hashes()
  129. .map(|hashes| {
  130. hashes
  131. .into_iter()
  132. .map(|h| h.to_string())
  133. .collect::<BTreeSet<_>>()
  134. })
  135. .unwrap_or_default();
  136. set.into_iter().collect()
  137. }
  138. /// Return all locktimes from spending conditions (sorted ascending)
  139. pub fn locktimes(&self) -> Vec<u64> {
  140. self.inner
  141. .locktimes()
  142. .map(|s| s.into_iter().collect())
  143. .unwrap_or_default()
  144. }
  145. }