1use crate::*;
2use hashlink::LinkedHashMap;
3
4const MD_MAX_LEN: usize = 64;
5
6#[wasm_bindgen]
7#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
8pub struct MetadataMap(pub(crate) LinkedHashMap<TransactionMetadatum, TransactionMetadatum>);
9
10to_from_bytes!(MetadataMap);
11
12#[wasm_bindgen]
13impl MetadataMap {
14 pub fn new() -> Self {
15 Self(LinkedHashMap::new())
16 }
17
18 pub fn len(&self) -> usize {
19 self.0.len()
20 }
21
22 pub fn insert(
23 &mut self,
24 key: &TransactionMetadatum,
25 value: &TransactionMetadatum,
26 ) -> Option<TransactionMetadatum> {
27 self.0.insert(key.clone(), value.clone())
28 }
29
30 pub fn insert_str(
32 &mut self,
33 key: &str,
34 value: &TransactionMetadatum,
35 ) -> Result<Option<TransactionMetadatum>, JsError> {
36 Ok(self.insert(&TransactionMetadatum::new_text(key.to_owned())?, value))
37 }
38
39 pub fn insert_i32(
41 &mut self,
42 key: i32,
43 value: &TransactionMetadatum,
44 ) -> Option<TransactionMetadatum> {
45 self.insert(&TransactionMetadatum::new_int(&Int::new_i32(key)), value)
46 }
47
48 pub fn get(&self, key: &TransactionMetadatum) -> Result<TransactionMetadatum, JsError> {
49 self.0
50 .get(key)
51 .map(|v| v.clone())
52 .ok_or_else(|| JsError::from_str(&format!("key {:?} not found", key)))
53 }
54
55 pub fn get_str(&self, key: &str) -> Result<TransactionMetadatum, JsError> {
57 self.get(&TransactionMetadatum::new_text(key.to_owned())?)
58 }
59
60 pub fn get_i32(&self, key: i32) -> Result<TransactionMetadatum, JsError> {
62 self.get(&TransactionMetadatum::new_int(&Int::new_i32(key)))
63 }
64
65 pub fn has(&self, key: &TransactionMetadatum) -> bool {
66 self.0.contains_key(key)
67 }
68
69 pub fn keys(&self) -> MetadataList {
70 MetadataList(
71 self.0
72 .iter()
73 .map(|(k, _v)| k.clone())
74 .collect::<Vec<TransactionMetadatum>>(),
75 )
76 }
77}
78
79#[wasm_bindgen]
80#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
81pub struct MetadataList(pub(crate) Vec<TransactionMetadatum>);
82
83to_from_bytes!(MetadataList);
84
85#[wasm_bindgen]
86impl MetadataList {
87 pub fn new() -> Self {
88 Self(Vec::new())
89 }
90
91 pub fn len(&self) -> usize {
92 self.0.len()
93 }
94
95 pub fn get(&self, index: usize) -> TransactionMetadatum {
96 self.0[index].clone()
97 }
98
99 pub fn add(&mut self, elem: &TransactionMetadatum) {
100 self.0.push(elem.clone());
101 }
102}
103
104#[wasm_bindgen]
105#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
106pub enum TransactionMetadatumKind {
107 MetadataMap,
108 MetadataList,
109 Int,
110 Bytes,
111 Text,
112}
113
114#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
115pub(crate) enum TransactionMetadatumEnum {
116 MetadataMap(MetadataMap),
117 MetadataList(MetadataList),
118 Int(Int),
119 Bytes(Vec<u8>),
120 Text(String),
121}
122
123#[wasm_bindgen]
124#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
125pub struct TransactionMetadatum(pub(crate) TransactionMetadatumEnum);
126
127to_from_bytes!(TransactionMetadatum);
128
129#[wasm_bindgen]
130impl TransactionMetadatum {
131 pub fn new_map(map: &MetadataMap) -> Self {
132 Self(TransactionMetadatumEnum::MetadataMap(map.clone()))
133 }
134
135 pub fn new_list(list: &MetadataList) -> Self {
136 Self(TransactionMetadatumEnum::MetadataList(list.clone()))
137 }
138
139 pub fn new_int(int: &Int) -> Self {
140 Self(TransactionMetadatumEnum::Int(int.clone()))
141 }
142
143 pub fn new_bytes(bytes: Vec<u8>) -> Result<TransactionMetadatum, JsError> {
144 if bytes.len() > MD_MAX_LEN {
145 Err(JsError::from_str(&format!(
146 "Max metadata bytes too long: {}, max = {}",
147 bytes.len(),
148 MD_MAX_LEN
149 )))
150 } else {
151 Ok(Self(TransactionMetadatumEnum::Bytes(bytes)))
152 }
153 }
154
155 pub fn new_text(text: String) -> Result<TransactionMetadatum, JsError> {
156 if text.len() > MD_MAX_LEN {
157 Err(JsError::from_str(&format!(
158 "Max metadata string too long: {}, max = {}",
159 text.len(),
160 MD_MAX_LEN
161 )))
162 } else {
163 Ok(Self(TransactionMetadatumEnum::Text(text)))
164 }
165 }
166
167 pub fn kind(&self) -> TransactionMetadatumKind {
168 match &self.0 {
169 TransactionMetadatumEnum::MetadataMap(_) => TransactionMetadatumKind::MetadataMap,
170 TransactionMetadatumEnum::MetadataList(_) => TransactionMetadatumKind::MetadataList,
171 TransactionMetadatumEnum::Int(_) => TransactionMetadatumKind::Int,
172 TransactionMetadatumEnum::Bytes(_) => TransactionMetadatumKind::Bytes,
173 TransactionMetadatumEnum::Text(_) => TransactionMetadatumKind::Text,
174 }
175 }
176
177 pub fn as_map(&self) -> Result<MetadataMap, JsError> {
178 match &self.0 {
179 TransactionMetadatumEnum::MetadataMap(x) => Ok(x.clone()),
180 _ => Err(JsError::from_str("not a map")),
181 }
182 }
183
184 pub fn as_list(&self) -> Result<MetadataList, JsError> {
185 match &self.0 {
186 TransactionMetadatumEnum::MetadataList(x) => Ok(x.clone()),
187 _ => Err(JsError::from_str("not a list")),
188 }
189 }
190
191 pub fn as_int(&self) -> Result<Int, JsError> {
192 match &self.0 {
193 TransactionMetadatumEnum::Int(x) => Ok(x.clone()),
194 _ => Err(JsError::from_str("not an int")),
195 }
196 }
197
198 pub fn as_bytes(&self) -> Result<Vec<u8>, JsError> {
199 match &self.0 {
200 TransactionMetadatumEnum::Bytes(x) => Ok(x.clone()),
201 _ => Err(JsError::from_str("not bytes")),
202 }
203 }
204
205 pub fn as_text(&self) -> Result<String, JsError> {
206 match &self.0 {
207 TransactionMetadatumEnum::Text(x) => Ok(x.clone()),
208 _ => Err(JsError::from_str("not text")),
209 }
210 }
211}
212
213impl serde::Serialize for TransactionMetadatum {
214 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
215 where
216 S: serde::Serializer,
217 {
218 let json_str = decode_metadatum_to_json_str(self, MetadataJsonSchema::DetailedSchema)
219 .map_err(|e| serde::ser::Error::custom(&format!("{:?}", e)))?;
220 serializer.serialize_str(&json_str)
221 }
222}
223
224impl<'de> serde::de::Deserialize<'de> for TransactionMetadatum {
225 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
226 where
227 D: serde::de::Deserializer<'de>,
228 {
229 let s = <String as serde::de::Deserialize>::deserialize(deserializer)?;
230 encode_json_str_to_metadatum(s.clone(), MetadataJsonSchema::DetailedSchema).map_err(|e| {
231 serde::de::Error::invalid_value(
232 serde::de::Unexpected::Str(&s),
233 &format!("{:?}", e).as_str(),
234 )
235 })
236 }
237}
238
239impl JsonSchema for TransactionMetadatum {
242 fn schema_name() -> String {
243 String::from("TransactionMetadatum")
244 }
245 fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
246 String::json_schema(gen)
247 }
248 fn is_referenceable() -> bool {
249 String::is_referenceable()
250 }
251}
252
253pub type TransactionMetadatumLabel = BigNum;
254
255#[wasm_bindgen]
256#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
257pub struct TransactionMetadatumLabels(pub(crate) Vec<TransactionMetadatumLabel>);
258
259to_from_bytes!(TransactionMetadatumLabels);
260
261#[wasm_bindgen]
262impl TransactionMetadatumLabels {
263 pub fn new() -> Self {
264 Self(Vec::new())
265 }
266
267 pub fn len(&self) -> usize {
268 self.0.len()
269 }
270
271 pub fn get(&self, index: usize) -> TransactionMetadatumLabel {
272 self.0[index].clone()
273 }
274
275 pub fn add(&mut self, elem: &TransactionMetadatumLabel) {
276 self.0.push(elem.clone());
277 }
278}
279
280#[wasm_bindgen]
281#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
282pub struct GeneralTransactionMetadata(
283 pub(crate) LinkedHashMap<TransactionMetadatumLabel, TransactionMetadatum>,
284);
285
286impl_to_from!(GeneralTransactionMetadata);
287
288#[wasm_bindgen]
289impl GeneralTransactionMetadata {
290 pub fn new() -> Self {
291 Self(LinkedHashMap::new())
292 }
293
294 pub fn len(&self) -> usize {
295 self.0.len()
296 }
297
298 pub fn insert(
299 &mut self,
300 key: &TransactionMetadatumLabel,
301 value: &TransactionMetadatum,
302 ) -> Option<TransactionMetadatum> {
303 self.0.insert(key.clone(), value.clone())
304 }
305
306 pub fn get(&self, key: &TransactionMetadatumLabel) -> Option<TransactionMetadatum> {
307 self.0.get(key).map(|v| v.clone())
308 }
309
310 pub fn keys(&self) -> TransactionMetadatumLabels {
311 TransactionMetadatumLabels(
312 self.0
313 .iter()
314 .map(|(k, _v)| k.clone())
315 .collect::<Vec<TransactionMetadatumLabel>>(),
316 )
317 }
318}
319
320impl serde::Serialize for GeneralTransactionMetadata {
321 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
322 where
323 S: serde::Serializer,
324 {
325 let map = self.0.iter().collect::<std::collections::BTreeMap<_, _>>();
326 map.serialize(serializer)
327 }
328}
329
330impl<'de> serde::de::Deserialize<'de> for GeneralTransactionMetadata {
331 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
332 where
333 D: serde::de::Deserializer<'de>,
334 {
335 let map = <std::collections::BTreeMap<_, _> as serde::de::Deserialize>::deserialize(
336 deserializer,
337 )?;
338 Ok(Self(map.into_iter().collect()))
339 }
340}
341
342impl JsonSchema for GeneralTransactionMetadata {
343 fn schema_name() -> String {
344 String::from("GeneralTransactionMetadata")
345 }
346 fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
347 std::collections::BTreeMap::<TransactionMetadatumLabel, TransactionMetadatum>::json_schema(
348 gen,
349 )
350 }
351 fn is_referenceable() -> bool {
352 std::collections::BTreeMap::<TransactionMetadatumLabel, TransactionMetadatum>::is_referenceable()
353 }
354}
355
356#[wasm_bindgen]
357#[derive(Clone, Debug, Ord, PartialOrd, serde::Serialize, serde::Deserialize, JsonSchema)]
358pub struct AuxiliaryData {
359 pub(crate) metadata: Option<GeneralTransactionMetadata>,
360 pub(crate) native_scripts: Option<NativeScripts>,
361 pub(crate) plutus_scripts: Option<PlutusScripts>,
362 pub(crate) prefer_alonzo_format: bool,
363}
364
365impl std::cmp::PartialEq<Self> for AuxiliaryData {
366 fn eq(&self, other: &Self) -> bool {
367 self.metadata.eq(&other.metadata)
368 && self.native_scripts.eq(&other.native_scripts)
369 && self.plutus_scripts.eq(&other.plutus_scripts)
370 }
371}
372
373impl std::cmp::Eq for AuxiliaryData {}
374
375impl_to_from!(AuxiliaryData);
376
377#[wasm_bindgen]
378impl AuxiliaryData {
379 pub fn new() -> Self {
380 Self {
381 metadata: None,
382 native_scripts: None,
383 plutus_scripts: None,
384 prefer_alonzo_format: false,
385 }
386 }
387
388 pub fn metadata(&self) -> Option<GeneralTransactionMetadata> {
389 self.metadata.clone()
390 }
391
392 pub fn set_metadata(&mut self, metadata: &GeneralTransactionMetadata) {
393 self.metadata = Some(metadata.clone());
394 }
395
396 pub fn native_scripts(&self) -> Option<NativeScripts> {
397 self.native_scripts.clone()
398 }
399
400 pub fn set_native_scripts(&mut self, native_scripts: &NativeScripts) {
401 self.native_scripts = Some(native_scripts.clone())
402 }
403
404 pub fn plutus_scripts(&self) -> Option<PlutusScripts> {
405 self.plutus_scripts.clone()
406 }
407
408 pub fn set_plutus_scripts(&mut self, plutus_scripts: &PlutusScripts) {
409 self.plutus_scripts = Some(plutus_scripts.clone())
410 }
411
412 pub fn prefer_alonzo_format(&self) -> bool {
413 self.prefer_alonzo_format.clone()
414 }
415
416 pub fn set_prefer_alonzo_format(&mut self, prefer: bool) {
417 self.prefer_alonzo_format = prefer
418 }
419}
420
421#[wasm_bindgen]
423pub fn encode_arbitrary_bytes_as_metadatum(bytes: &[u8]) -> TransactionMetadatum {
424 let mut list = MetadataList::new();
425 for chunk in bytes.chunks(MD_MAX_LEN) {
426 list.add(&TransactionMetadatum::new_bytes(chunk.to_vec()).unwrap());
428 }
429 TransactionMetadatum::new_list(&list)
430}
431
432#[wasm_bindgen]
434pub fn decode_arbitrary_bytes_from_metadatum(
435 metadata: &TransactionMetadatum,
436) -> Result<Vec<u8>, JsError> {
437 let mut bytes = Vec::new();
438 for elem in metadata.as_list()?.0 {
439 bytes.append(&mut elem.as_bytes()?);
440 }
441 Ok(bytes)
442}
443
444#[wasm_bindgen]
445#[derive(Copy, Clone, Eq, PartialEq)]
446pub enum MetadataJsonSchema {
452 NoConversions,
462 BasicConversions,
474 DetailedSchema,
484}
485
486fn supports_tagged_values(schema: MetadataJsonSchema) -> bool {
487 match schema {
488 MetadataJsonSchema::NoConversions | MetadataJsonSchema::BasicConversions => false,
489 MetadataJsonSchema::DetailedSchema => true,
490 }
491}
492
493fn hex_string_to_bytes(hex: &str) -> Option<Vec<u8>> {
494 if hex.starts_with("0x") {
495 hex::decode(&hex[2..]).ok()
496 } else {
497 None
498 }
499}
500
501fn bytes_to_hex_string(bytes: &[u8]) -> String {
502 format!("0x{}", hex::encode(bytes))
503}
504
505#[wasm_bindgen]
507pub fn encode_json_str_to_metadatum(
508 json: String,
509 schema: MetadataJsonSchema,
510) -> Result<TransactionMetadatum, JsError> {
511 let value = serde_json::from_str(&json).map_err(|e| JsError::from_str(&e.to_string()))?;
512 encode_json_value_to_metadatum(value, schema)
513}
514
515pub fn encode_json_value_to_metadatum(
516 value: serde_json::Value,
517 schema: MetadataJsonSchema,
518) -> Result<TransactionMetadatum, JsError> {
519 use serde_json::Value;
520 fn encode_number(x: serde_json::Number) -> Result<TransactionMetadatum, JsError> {
521 if let Some(x) = x.as_u64() {
522 Ok(TransactionMetadatum::new_int(&Int::new(&x.into())))
523 } else if let Some(x) = x.as_i64() {
524 Ok(TransactionMetadatum::new_int(&Int::new_negative(
525 &(-x as u64).into(),
526 )))
527 } else {
528 Err(JsError::from_str("floats not allowed in metadata"))
529 }
530 }
531 fn encode_string(
532 s: String,
533 schema: MetadataJsonSchema,
534 ) -> Result<TransactionMetadatum, JsError> {
535 if schema == MetadataJsonSchema::BasicConversions {
536 match hex_string_to_bytes(&s) {
537 Some(bytes) => TransactionMetadatum::new_bytes(bytes),
538 None => TransactionMetadatum::new_text(s),
539 }
540 } else {
541 TransactionMetadatum::new_text(s)
542 }
543 }
544 fn encode_array(
545 json_arr: Vec<Value>,
546 schema: MetadataJsonSchema,
547 ) -> Result<TransactionMetadatum, JsError> {
548 let mut arr = MetadataList::new();
549 for value in json_arr {
550 arr.add(&encode_json_value_to_metadatum(value, schema)?);
551 }
552 Ok(TransactionMetadatum::new_list(&arr))
553 }
554 match schema {
555 MetadataJsonSchema::NoConversions | MetadataJsonSchema::BasicConversions => match value {
556 Value::Null => Err(JsError::from_str("null not allowed in metadata")),
557 Value::Bool(_) => Err(JsError::from_str("bools not allowed in metadata")),
558 Value::Number(x) => encode_number(x),
559 Value::String(s) => encode_string(s, schema),
560 Value::Array(json_arr) => encode_array(json_arr, schema),
561 Value::Object(json_obj) => {
562 let mut map = MetadataMap::new();
563 for (raw_key, value) in json_obj {
564 let key = if schema == MetadataJsonSchema::BasicConversions {
565 match raw_key.parse::<i128>() {
566 Ok(x) => TransactionMetadatum::new_int(&Int(x)),
567 Err(_) => encode_string(raw_key, schema)?,
568 }
569 } else {
570 TransactionMetadatum::new_text(raw_key)?
571 };
572 map.insert(&key, &encode_json_value_to_metadatum(value, schema)?);
573 }
574 Ok(TransactionMetadatum::new_map(&map))
575 }
576 },
577 MetadataJsonSchema::DetailedSchema => match value {
579 Value::Object(obj) if obj.len() == 1 => {
580 let (k, v) = obj.into_iter().next().unwrap();
581 fn tag_mismatch() -> JsError {
582 JsError::from_str("key does not match type")
583 }
584 match k.as_str() {
585 "int" => match v {
586 Value::Number(x) => encode_number(x),
587 _ => Err(tag_mismatch()),
588 },
589 "string" => {
590 encode_string(v.as_str().ok_or_else(tag_mismatch)?.to_owned(), schema)
591 }
592 "bytes" => match hex::decode(v.as_str().ok_or_else(tag_mismatch)?) {
593 Ok(bytes) => TransactionMetadatum::new_bytes(bytes),
594 Err(_) => Err(JsError::from_str(
595 "invalid hex string in tagged byte-object",
596 )),
597 },
598 "list" => encode_array(v.as_array().ok_or_else(tag_mismatch)?.clone(), schema),
599 "map" => {
600 let mut map = MetadataMap::new();
601 fn map_entry_err() -> JsError {
602 JsError::from_str("entry format in detailed schema map object not correct. Needs to be of form {\"k\": \"key\", \"v\": value}")
603 }
604 for entry in v.as_array().ok_or_else(tag_mismatch)? {
605 let entry_obj = entry.as_object().ok_or_else(map_entry_err)?;
606 let raw_key = entry_obj.get("k").ok_or_else(map_entry_err)?;
607 let value = entry_obj.get("v").ok_or_else(map_entry_err)?;
608 let key = encode_json_value_to_metadatum(raw_key.clone(), schema)?;
609 map.insert(
610 &key,
611 &encode_json_value_to_metadatum(value.clone(), schema)?,
612 );
613 }
614 Ok(TransactionMetadatum::new_map(&map))
615 }
616 invalid_key => Err(JsError::from_str(&format!(
617 "key '{}' in tagged object not valid",
618 invalid_key
619 ))),
620 }
621 }
622 _ => Err(JsError::from_str(
623 "DetailedSchema requires types to be tagged objects",
624 )),
625 },
626 }
627}
628
629#[wasm_bindgen]
631pub fn decode_metadatum_to_json_str(
632 metadatum: &TransactionMetadatum,
633 schema: MetadataJsonSchema,
634) -> Result<String, JsError> {
635 let value = decode_metadatum_to_json_value(metadatum, schema)?;
636 serde_json::to_string(&value).map_err(|e| JsError::from_str(&e.to_string()))
637}
638
639pub fn decode_metadatum_to_json_value(
640 metadatum: &TransactionMetadatum,
641 schema: MetadataJsonSchema,
642) -> Result<serde_json::Value, JsError> {
643 use serde_json::Value;
644 use std::convert::TryFrom;
645 fn decode_key(
646 key: &TransactionMetadatum,
647 schema: MetadataJsonSchema,
648 ) -> Result<String, JsError> {
649 match &key.0 {
650 TransactionMetadatumEnum::Text(s) => Ok(s.clone()),
651 TransactionMetadatumEnum::Bytes(b) if schema != MetadataJsonSchema::NoConversions => {
652 Ok(bytes_to_hex_string(b.as_ref()))
653 }
654 TransactionMetadatumEnum::Int(i) if schema != MetadataJsonSchema::NoConversions => {
655 let int_str = if i.0 >= 0 {
656 u64::try_from(i.0).map(|x| x.to_string())
657 } else {
658 i64::try_from(i.0).map(|x| x.to_string())
659 };
660 int_str.map_err(|e| JsError::from_str(&e.to_string()))
661 }
662 TransactionMetadatumEnum::MetadataList(list)
663 if schema == MetadataJsonSchema::DetailedSchema =>
664 {
665 decode_metadatum_to_json_str(&TransactionMetadatum::new_list(&list), schema)
666 }
667 TransactionMetadatumEnum::MetadataMap(map)
668 if schema == MetadataJsonSchema::DetailedSchema =>
669 {
670 decode_metadatum_to_json_str(&TransactionMetadatum::new_map(&map), schema)
671 }
672 _ => Err(JsError::from_str(&format!(
673 "key type {:?} not allowed in JSON under specified schema",
674 key.0
675 ))),
676 }
677 }
678 let (type_key, value) = match &metadatum.0 {
679 TransactionMetadatumEnum::MetadataMap(map) => match schema {
680 MetadataJsonSchema::NoConversions | MetadataJsonSchema::BasicConversions => {
681 let mut json_map = serde_json::map::Map::with_capacity(map.len());
683 for (key, value) in map.0.iter() {
684 json_map.insert(
685 decode_key(key, schema)?,
686 decode_metadatum_to_json_value(value, schema)?,
687 );
688 }
689 ("map", Value::from(json_map))
690 }
691
692 MetadataJsonSchema::DetailedSchema => (
693 "map",
694 Value::from(
695 map.0
696 .iter()
697 .map(|(key, value)| {
698 let k = decode_metadatum_to_json_value(key, schema)?;
701 let v = decode_metadatum_to_json_value(value, schema)?;
702 let mut kv_obj = serde_json::map::Map::with_capacity(2);
703 kv_obj.insert(String::from("k"), Value::from(k));
704 kv_obj.insert(String::from("v"), v);
705 Ok(Value::from(kv_obj))
706 })
707 .collect::<Result<Vec<_>, JsError>>()?,
708 ),
709 ),
710 },
711 TransactionMetadatumEnum::MetadataList(arr) => (
712 "list",
713 Value::from(
714 arr.0
715 .iter()
716 .map(|e| decode_metadatum_to_json_value(e, schema))
717 .collect::<Result<Vec<_>, JsError>>()?,
718 ),
719 ),
720 TransactionMetadatumEnum::Int(x) => (
721 "int",
722 if x.0 >= 0 {
723 Value::from(u64::try_from(x.0).map_err(|e| JsError::from_str(&e.to_string()))?)
724 } else {
725 Value::from(i64::try_from(x.0).map_err(|e| JsError::from_str(&e.to_string()))?)
726 },
727 ),
728 TransactionMetadatumEnum::Bytes(bytes) => (
729 "bytes",
730 match schema {
731 MetadataJsonSchema::NoConversions => Err(JsError::from_str(
732 "bytes not allowed in JSON in specified schema",
733 )),
734 MetadataJsonSchema::BasicConversions => {
736 Ok(Value::from(bytes_to_hex_string(bytes.as_ref())))
737 }
738 MetadataJsonSchema::DetailedSchema => Ok(Value::from(hex::encode(bytes))),
740 }?,
741 ),
742 TransactionMetadatumEnum::Text(s) => ("string", Value::from(s.clone())),
743 };
744 if supports_tagged_values(schema) {
746 let mut wrapper = serde_json::map::Map::with_capacity(1);
747 wrapper.insert(String::from(type_key), value);
748 Ok(Value::from(wrapper))
749 } else {
750 Ok(value)
751 }
752}