token.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. //! WASM token bindings
  2. use std::collections::BTreeSet;
  3. use std::str::FromStr;
  4. use wasm_bindgen::prelude::*;
  5. use crate::error::WasmError;
  6. use crate::types::{Amount, MintUrl, Proofs};
  7. /// WASM-compatible Token
  8. #[wasm_bindgen]
  9. pub struct Token {
  10. pub(crate) inner: cdk::nuts::Token,
  11. }
  12. impl std::fmt::Debug for Token {
  13. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  14. write!(f, "Token({})", self.inner)
  15. }
  16. }
  17. impl std::fmt::Display for Token {
  18. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  19. write!(f, "{}", self.inner)
  20. }
  21. }
  22. impl FromStr for Token {
  23. type Err = WasmError;
  24. fn from_str(s: &str) -> Result<Self, Self::Err> {
  25. let token = cdk::nuts::Token::from_str(s)
  26. .map_err(|e| WasmError::internal(format!("Invalid token: {}", e)))?;
  27. Ok(Token { inner: token })
  28. }
  29. }
  30. impl From<cdk::nuts::Token> for Token {
  31. fn from(token: cdk::nuts::Token) -> Self {
  32. Self { inner: token }
  33. }
  34. }
  35. impl From<Token> for cdk::nuts::Token {
  36. fn from(token: Token) -> Self {
  37. token.inner
  38. }
  39. }
  40. #[wasm_bindgen]
  41. impl Token {
  42. /// Create a new Token from string
  43. #[wasm_bindgen(js_name = "fromString")]
  44. pub fn from_string(encoded_token: String) -> Result<Token, WasmError> {
  45. let token = cdk::nuts::Token::from_str(&encoded_token)
  46. .map_err(|e| WasmError::internal(format!("Invalid token: {}", e)))?;
  47. Ok(Token { inner: token })
  48. }
  49. /// Get the total value of the token
  50. pub fn value(&self) -> Result<Amount, WasmError> {
  51. Ok(self.inner.value()?.into())
  52. }
  53. /// Get the memo from the token
  54. pub fn memo(&self) -> Option<String> {
  55. self.inner.memo().clone()
  56. }
  57. /// Get the mint URL
  58. #[wasm_bindgen(js_name = "mintUrl")]
  59. pub fn mint_url(&self) -> Result<JsValue, WasmError> {
  60. let url: MintUrl = self.inner.mint_url()?.into();
  61. serde_wasm_bindgen::to_value(&url).map_err(WasmError::internal)
  62. }
  63. /// Get proofs from the token (simplified - no keyset filtering)
  64. #[wasm_bindgen(js_name = "proofsSimple")]
  65. pub fn proofs_simple(&self) -> Result<JsValue, WasmError> {
  66. let empty_keysets = vec![];
  67. let proofs = self.inner.proofs(&empty_keysets)?;
  68. let ffi_proofs: Proofs = proofs.into_iter().map(|p| p.into()).collect();
  69. serde_wasm_bindgen::to_value(&ffi_proofs).map_err(WasmError::internal)
  70. }
  71. /// Convert token to raw bytes
  72. #[wasm_bindgen(js_name = "toRawBytes")]
  73. pub fn to_raw_bytes(&self) -> Result<Vec<u8>, WasmError> {
  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. #[wasm_bindgen(js_name = "fromRawBytes")]
  82. pub fn from_raw_bytes(bytes: Vec<u8>) -> Result<Token, WasmError> {
  83. let token = cdk::nuts::Token::try_from(&bytes)?;
  84. Ok(Token { inner: token })
  85. }
  86. /// Decode token from string representation
  87. pub fn decode(encoded_token: String) -> Result<Token, WasmError> {
  88. encoded_token.parse()
  89. }
  90. /// Return all P2PK pubkeys referenced by this token's spending conditions
  91. #[wasm_bindgen(js_name = "p2pkPubkeys")]
  92. pub fn p2pk_pubkeys(&self) -> Vec<String> {
  93. let set = self
  94. .inner
  95. .p2pk_pubkeys()
  96. .map(|keys| {
  97. keys.into_iter()
  98. .map(|k| k.to_string())
  99. .collect::<BTreeSet<_>>()
  100. })
  101. .unwrap_or_default();
  102. set.into_iter().collect()
  103. }
  104. /// Return all locktimes from spending conditions (sorted ascending)
  105. pub fn locktimes(&self) -> Vec<u64> {
  106. self.inner
  107. .locktimes()
  108. .map(|s| s.into_iter().collect())
  109. .unwrap_or_default()
  110. }
  111. }