cml_cip25_wasm/
lib.rs

1#![allow(
2    clippy::len_without_is_empty,
3    clippy::too_many_arguments,
4    clippy::new_without_default
5)]
6
7pub mod utils;
8
9use cml_core_wasm::{
10    impl_wasm_cbor_json_api_cbor_event_serialize, impl_wasm_conversions, impl_wasm_json_api,
11    impl_wasm_list,
12};
13pub use utils::CIP25LabelMetadata;
14
15pub use cml_cip25::CIP25Version;
16
17use wasm_bindgen::prelude::{wasm_bindgen, JsValue};
18
19/// This is the entire metadata schema for CIP-25
20/// It can be parsed by passing in the CBOR bytes of the entire transaction metadata
21/// or by passing in an existing Metadata struct.
22/// Parsing from CBOR bytes should be marginally faster.
23#[derive(Clone, Debug)]
24#[wasm_bindgen]
25pub struct CIP25Metadata(cml_cip25::CIP25Metadata);
26
27impl_wasm_conversions!(cml_cip25::CIP25Metadata, CIP25Metadata);
28
29// we manually write to_cbor_bytes/from_cbor_bytes so we can add the comments
30
31impl_wasm_json_api!(CIP25Metadata);
32
33#[wasm_bindgen]
34impl CIP25Metadata {
35    /// Serialize to CBOR bytes compatible with tx metadata
36    /// Does not guarantee any specific type of CBOR format and should NOT
37    /// be used with round-tripping. It will ignore all non-CIP25 keys.
38    /// Use cml_cip25::metadate crate for round-tripping metadata.
39    pub fn to_cbor_bytes(&self) -> Vec<u8> {
40        use cml_cip25::serialization::ToBytes;
41        ToBytes::to_bytes(&self.0)
42    }
43
44    /// Deserialize from CBOR bytes compatible with tx metadata
45    /// Does not guarantee any specific type of CBOR format and should NOT
46    /// be used with round-tripping. It will ignore all non-CIP25 keys.
47    /// Use cml_cip25::metadate crate for round-tripping metadata.
48    pub fn from_cbor_bytes(data: Vec<u8>) -> Result<CIP25Metadata, JsValue> {
49        use cml_cip25::serialization::FromBytes;
50        FromBytes::from_bytes(data)
51            .map(Self)
52            .map_err(|e| JsValue::from_str(&format!("from_cbor_bytes: {e}")))
53    }
54
55    /// The core details of the CIP25 spec
56    pub fn key_721(&self) -> CIP25LabelMetadata {
57        self.0.key_721.clone().into()
58    }
59
60    pub fn new(key_721: &CIP25LabelMetadata) -> Self {
61        Self(cml_cip25::CIP25Metadata::new(key_721.clone().into()))
62    }
63}
64
65/// A String that may or may not be chunked into 64-byte chunks to be able
66/// to conform to Cardano TX Metadata limitations.
67/// Most users should simply use CIP25ChunkableString::from_string() and CIP25ChunkableString::to_string()
68/// and avoid the explicit single/chunk interface:
69/// ```javascript
70/// let chunkableString = CIP25.CIP25ChunkableString.from_string("this can be any length and will automatically be chunked if needed");
71/// ```
72#[derive(Clone, Debug)]
73#[wasm_bindgen]
74pub struct CIP25ChunkableString(cml_cip25::CIP25ChunkableString);
75
76impl_wasm_conversions!(cml_cip25::CIP25ChunkableString, CIP25ChunkableString);
77
78impl_wasm_cbor_json_api_cbor_event_serialize!(CIP25ChunkableString);
79
80#[wasm_bindgen]
81impl CIP25ChunkableString {
82    pub fn new_single(single: &CIP25String64) -> Self {
83        Self(cml_cip25::CIP25ChunkableString::new_single(
84            single.clone().into(),
85        ))
86    }
87
88    pub fn new_chunked(chunked: &CIP25String64List) -> Self {
89        Self(cml_cip25::CIP25ChunkableString::new_chunked(
90            chunked.clone().into(),
91        ))
92    }
93
94    pub fn kind(&self) -> ChunkableStringKind {
95        match &self.0 {
96            cml_cip25::CIP25ChunkableString::Single(_) => ChunkableStringKind::Single,
97            cml_cip25::CIP25ChunkableString::Chunked(_) => ChunkableStringKind::Chunked,
98        }
99    }
100
101    pub fn as_single(&self) -> Option<CIP25String64> {
102        match &self.0 {
103            cml_cip25::CIP25ChunkableString::Single(single) => Some(single.clone().into()),
104            _ => None,
105        }
106    }
107
108    pub fn as_chunked(&self) -> Option<CIP25String64List> {
109        match &self.0 {
110            cml_cip25::CIP25ChunkableString::Chunked(chunked) => Some(chunked.clone().into()),
111            _ => None,
112        }
113    }
114}
115
116#[wasm_bindgen]
117pub enum ChunkableStringKind {
118    Single,
119    Chunked,
120}
121
122#[derive(Clone, Debug)]
123#[wasm_bindgen]
124pub struct CIP25FilesDetails(cml_cip25::CIP25FilesDetails);
125
126impl_wasm_conversions!(cml_cip25::CIP25FilesDetails, CIP25FilesDetails);
127
128impl_wasm_cbor_json_api_cbor_event_serialize!(CIP25FilesDetails);
129
130#[wasm_bindgen]
131impl CIP25FilesDetails {
132    pub fn name(&self) -> CIP25String64 {
133        self.0.name.clone().into()
134    }
135
136    pub fn media_type(&self) -> CIP25String64 {
137        self.0.media_type.clone().into()
138    }
139
140    pub fn src(&self) -> CIP25ChunkableString {
141        self.0.src.clone().into()
142    }
143
144    pub fn new(
145        name: &CIP25String64,
146        media_type: &CIP25String64,
147        src: &CIP25ChunkableString,
148    ) -> Self {
149        Self(cml_cip25::CIP25FilesDetails::new(
150            name.clone().into(),
151            media_type.clone().into(),
152            src.clone().into(),
153        ))
154    }
155}
156
157impl_wasm_list!(
158    cml_cip25::CIP25FilesDetails,
159    CIP25FilesDetails,
160    FilesDetailsList
161);
162
163#[derive(Clone, Debug)]
164#[wasm_bindgen]
165pub struct CIP25MetadataDetails(cml_cip25::CIP25MetadataDetails);
166
167impl_wasm_conversions!(cml_cip25::CIP25MetadataDetails, CIP25MetadataDetails);
168
169impl_wasm_cbor_json_api_cbor_event_serialize!(CIP25MetadataDetails);
170
171#[wasm_bindgen]
172impl CIP25MetadataDetails {
173    pub fn name(&self) -> CIP25String64 {
174        self.0.name.clone().into()
175    }
176
177    pub fn image(&self) -> CIP25ChunkableString {
178        self.0.image.clone().into()
179    }
180
181    pub fn set_media_type(&mut self, media_type: &CIP25String64) {
182        self.0.media_type = Some(media_type.clone().into())
183    }
184
185    pub fn media_type(&self) -> Option<CIP25String64> {
186        self.0.media_type.clone().map(std::convert::Into::into)
187    }
188
189    pub fn set_description(&mut self, description: &CIP25ChunkableString) {
190        self.0.description = Some(description.clone().into())
191    }
192
193    pub fn description(&self) -> Option<CIP25ChunkableString> {
194        self.0.description.clone().map(std::convert::Into::into)
195    }
196
197    pub fn set_files(&mut self, files: &FilesDetailsList) {
198        self.0.files = Some(files.clone().into())
199    }
200
201    pub fn files(&self) -> Option<FilesDetailsList> {
202        self.0.files.clone().map(std::convert::Into::into)
203    }
204
205    pub fn new(name: &CIP25String64, image: &CIP25ChunkableString) -> Self {
206        Self(cml_cip25::CIP25MetadataDetails::new(
207            name.clone().into(),
208            image.clone().into(),
209        ))
210    }
211}
212
213/// A String of at most 64 bytes.
214/// This is to conform with Cardano metadata restrictions.
215#[derive(Clone, Debug)]
216#[wasm_bindgen]
217pub struct CIP25String64(cml_cip25::CIP25String64);
218
219impl_wasm_conversions!(cml_cip25::CIP25String64, CIP25String64);
220
221impl_wasm_cbor_json_api_cbor_event_serialize!(CIP25String64);
222
223#[wasm_bindgen]
224impl CIP25String64 {
225    pub fn get(&self) -> String {
226        self.0.get().clone()
227    }
228}
229
230impl_wasm_list!(cml_cip25::CIP25String64, CIP25String64, CIP25String64List);