casper_rust_wasm_sdk/helpers/
mod.rs

1use crate::types::hash::account_hash::AccountHash;
2use crate::types::transaction_params::transaction_str_params::{DEFAULT_GAS_PRICE, DEFAULT_TTL};
3use crate::types::{key::Key, public_key::PublicKey, sdk_error::SdkError, verbosity::Verbosity};
4use base64::engine::general_purpose;
5use base64::Engine;
6use bigdecimal::BigDecimal;
7use blake2::{
8    digest::{Update, VariableOutput},
9    VarBlake2b,
10};
11use casper_client::cli::JsonArg;
12use casper_types::{
13    bytesrepr::ToBytes, cl_value_to_json as cl_value_to_json_from_casper_types, CLValue,
14    Key as CasperTypesKey, NamedArg, PublicKey as CasperTypesPublicKey, RuntimeArgs, SecretKey,
15    TimeDiff, Timestamp,
16};
17use chrono::{DateTime, SecondsFormat, Utc};
18#[cfg(target_arch = "wasm32")]
19use gloo_utils::format::JsValueSerdeExt;
20use serde::Serialize;
21use serde_json::Value;
22use std::str::FromStr;
23#[cfg(target_arch = "wasm32")]
24use wasm_bindgen::{JsCast, JsValue};
25
26pub const BLAKE2B_DIGEST_LENGTH: usize = 32;
27
28/// Converts a CLValue to a JSON Value.
29///
30/// # Arguments
31///
32/// * `cl_value` - The CLValue to convert.
33///
34/// # Returns
35///
36/// A JSON Value representing the CLValue data.
37pub fn cl_value_to_json(cl_value: &CLValue) -> Option<Value> {
38    cl_value_to_json_from_casper_types(cl_value)
39}
40
41/// Gets the current timestamp.
42///
43/// # Arguments
44///
45/// * `timestamp` - An optional timestamp value in milliseconds since the Unix epoch.
46///
47/// # Returns
48///
49/// A string containing the current timestamp in RFC3339 format.
50pub fn get_current_timestamp(timestamp: Option<String>) -> String {
51    let parsed_timestamp = timestamp.as_ref().and_then(|ts| ts.parse::<i64>().ok());
52    let current_timestamp = parsed_timestamp
53        .map(|parsed_time| DateTime::from_timestamp(parsed_time / 1000, 0).unwrap_or_else(Utc::now))
54        .unwrap_or_else(Utc::now);
55    current_timestamp.to_rfc3339_opts(SecondsFormat::Secs, true)
56}
57
58/// Computes the Blake2b hash of the provided metadata.
59///
60/// # Arguments
61///
62/// * `meta_data` - A reference to a string containing the metadata to be hashed.
63///
64/// # Returns
65///
66/// A hexadecimal string representing the Blake2b hash of the input metadata.
67pub fn get_blake2b_hash(meta_data: &str) -> String {
68    let mut result = [0; BLAKE2B_DIGEST_LENGTH];
69    let mut hasher = VarBlake2b::new(BLAKE2B_DIGEST_LENGTH).expect("should create hasher");
70
71    hasher.update(meta_data);
72    hasher.finalize_variable(|slice| {
73        result.copy_from_slice(slice);
74    });
75    hex::encode(result).to_lowercase()
76}
77
78/// Creates a dictionary item key by concatenating the serialized bytes of the key and value.
79///
80/// # Arguments
81///
82/// * `key` - The key to be serialized.
83/// * `value` - The value to be serialized.
84///
85/// # Returns
86///
87/// A hexadecimal-encoded string representing the dictionary item key.
88///
89/// # Panics
90///
91/// Panics if the hasher cannot be created.
92///
93/// # Example
94///
95/// ```rust
96/// use casper_types::{U256, U512};
97/// use casper_rust_wasm_sdk::helpers::make_dictionary_item_key;
98/// use casper_rust_wasm_sdk::types::key::Key;
99/// // Key / Value as U256
100/// let key = Key::from_formatted_str( "account-hash-e11bfffe63bf899ea07117af8a2bb43ef0078c0e38ebee6b6cb0b0e39c233538").unwrap();
101/// let value = U256::from(1);
102/// let dictionary_item_key = make_dictionary_item_key(&key, &value);
103/// println!("Dictionary Item Key (Key/Value as U256): {}", dictionary_item_key);
104/// assert_eq!(dictionary_item_key,"145f6211a24c0a8af16b47e7aa58431ea25172eb402903b3c25ac92b9784c7a9".to_string());
105/// // Key / Value as Key
106/// let key = Key::from_formatted_str( "account-hash-813428ce1a9805f1087db07e6017c6c4f5af0ee78a05591bb6577763e89b4f1f").unwrap();
107/// let value = Key::from_formatted_str("account-hash-e11bfffe63bf899ea07117af8a2bb43ef0078c0e38ebee6b6cb0b0e39c233538").unwrap();
108/// let dictionary_item_key = make_dictionary_item_key(&key, &value);
109/// println!("Dictionary Item Key (Key/Value as Key): {}", dictionary_item_key);
110/// assert_eq!(dictionary_item_key,"1e26dc82db208943c3785c0e11b9d78b9c408fee748c78dda5a5d016840dedca".to_string());
111/// ```
112pub fn make_dictionary_item_key<V: ToBytes>(key: &Key, value: &V) -> String {
113    let key: CasperTypesKey = CasperTypesKey::from(key.clone());
114    let mut bytes_a = key.to_bytes().unwrap_or_default();
115    let mut bytes_b = value.to_bytes().unwrap_or_default();
116
117    bytes_a.append(&mut bytes_b);
118
119    let mut result = [0; BLAKE2B_DIGEST_LENGTH];
120    let mut hasher = VarBlake2b::new(BLAKE2B_DIGEST_LENGTH).expect("should create hasher");
121
122    hasher.update(bytes_a);
123    hasher.finalize_variable(|slice| {
124        result.copy_from_slice(slice);
125    });
126    hex::encode(result)
127}
128
129/// Convert a formatted account hash to a base64-encoded Key as string (cep-18 key encoding).
130///
131/// # Arguments
132///
133/// * `formatted_account_hash` - A hex-formatted string representing the account hash.
134///
135/// Example: "account-hash-b485c074cef7ccaccd0302949d2043ab7133abdb14cfa87e8392945c0bd80a5f"
136///
137/// # Returns
138///
139/// Returns a `Result` with the base64-encoded string on success, or a `SdkError` on failure.
140/// Example: "ALSFwHTO98yszQMClJ0gQ6txM6vbFM+ofoOSlFwL2Apf"
141pub fn get_base64_key_from_account_hash(account_hash: &str) -> Result<String, Box<SdkError>> {
142    let account_hash = AccountHash::from_formatted_str(account_hash)?;
143    let key = Key::from_account(account_hash).to_bytes().unwrap();
144    Ok(general_purpose::STANDARD.encode(key)) // base64.encode
145}
146
147/// Converts a formatted key hash to a base64-encoded string (CEP-18 key encoding).
148///
149/// # Arguments
150///
151/// * `formatted_hash` - A hex-formatted string representing the key hash.
152///   Example: "hash-b485c074cef7ccaccd0302949d2043ab7133abdb14cfa87e8392945c0bd80a5f"
153///
154/// # Returns
155///
156/// Returns a `Result` containing the base64-encoded string on success.
157/// Example: "AbSFwHTO98yszQMClJ0gQ6txM6vbFM+ofoOSlFwL2Apf"
158///
159/// # Errors
160///
161/// This function returns an error if:
162/// - The input string is not a valid formatted key hash.
163/// - The conversion to bytes or base64 encoding fails.
164pub fn get_base64_key_from_key_hash(formatted_hash: &str) -> Result<String, Box<SdkError>> {
165    let key = Key::from_formatted_str(formatted_hash)?;
166    let key = key.to_bytes().unwrap();
167    Ok(general_purpose::STANDARD.encode(key)) // base64.encode
168}
169
170/// Gets the time to live (TTL) value or returns the default value if not provided.
171///
172/// # Arguments
173///
174/// * `ttl` - An optional TTL value as a string.
175///
176/// # Returns
177///
178/// A string containing the TTL value or the default TTL if not provided.
179pub fn get_ttl_or_default(ttl: Option<&str>) -> String {
180    if let Some(ttl) = ttl {
181        ttl.to_string()
182    } else {
183        DEFAULT_TTL.to_string()
184    }
185}
186
187/// Parses a timestamp string into a `Timestamp` object.
188///
189/// # Arguments
190///
191/// * `value` - The timestamp string to parse.
192///
193/// # Returns
194///
195/// A `Result` containing the parsed `Timestamp` or an error if parsing fails.
196pub fn parse_timestamp(value: &str) -> Result<Timestamp, Box<SdkError>> {
197    Timestamp::from_str(value).map_err(|error| {
198        Box::new(SdkError::FailedToParseTimestamp {
199            context: "timestamp",
200            error,
201        })
202    })
203}
204
205/// Parses a TTL (time to live) string into a `TimeDiff` object.
206///
207/// # Arguments
208///
209/// * `value` - The TTL string to parse.
210///
211/// # Returns
212///
213/// A `Result` containing the parsed `TimeDiff` or an error if parsing fails.
214pub fn parse_ttl(value: &str) -> Result<TimeDiff, Box<SdkError>> {
215    TimeDiff::from_str(value).map_err(|error| {
216        Box::new(SdkError::FailedToParseTimeDiff {
217            context: "ttl",
218            error,
219        })
220    })
221}
222
223/// Gets the gas price or returns the default value if not provided.
224///
225/// # Arguments
226///
227/// * `gas_price` - An optional gas price value.
228///
229/// # Returns
230///
231/// The gas price or the default gas price if not provided.
232pub fn get_gas_price_or_default(gas_price: Option<u64>) -> u64 {
233    gas_price.unwrap_or(DEFAULT_GAS_PRICE)
234}
235
236/// Gets the value as a string or returns an empty string if not provided.
237///
238/// # Arguments
239///
240/// * `opt_str` - An optional string value.
241///
242/// # Returns
243///
244/// The string value or an empty string if not provided.
245pub(crate) fn get_str_or_default(opt_str: Option<&String>) -> &str {
246    opt_str.map(String::as_str).unwrap_or_default()
247}
248
249/// Generates a secret key using the Ed25519 algorithm.
250///
251/// # Returns
252///
253/// A `Result` containing the generated secret key or an error if the generation fails.
254///
255/// # Errors
256///
257/// Returns an `SdkError` if the secret key generation fails.
258pub fn secret_key_generate() -> Result<SecretKey, Box<SdkError>> {
259    SecretKey::generate_ed25519().map_err(|err| {
260        Box::new(SdkError::FailedToGenerateSecretKey {
261            context: "secret_key_from_pem".to_string(),
262            error: err,
263        })
264    })
265}
266
267/// Generates a secret key using the secp256k1 algorithm.
268///
269/// # Returns
270///
271/// A `Result` containing the generated secret key or an error if the generation fails.
272///
273/// # Errors
274///
275/// Returns an `SdkError` if the secret key generation fails.
276pub fn secret_key_secp256k1_generate() -> Result<SecretKey, Box<SdkError>> {
277    SecretKey::generate_secp256k1().map_err(|err| {
278        Box::new(SdkError::FailedToGenerateSecretKey {
279            context: "secret_key_from_pem".to_string(),
280            error: err,
281        })
282    })
283}
284
285/// Parses a secret key in PEM format into a `SecretKey` object.
286///
287/// # Arguments
288///
289/// * `secret_key` - The secret key in PEM format.
290///
291/// # Returns
292///
293/// A `Result` containing the parsed `SecretKey` or an error if parsing fails.
294pub fn secret_key_from_pem(secret_key: &str) -> Result<SecretKey, Box<SdkError>> {
295    SecretKey::from_pem(secret_key).map_err(|err| {
296        Box::new(SdkError::FailedToParseSecretKey {
297            context: "secret_key_from_pem".to_string(),
298            error: err,
299        })
300    })
301}
302
303/// Converts a secret key in PEM format to its corresponding public key as a string.
304///
305/// # Arguments
306///
307/// * `secret_key` - The secret key in PEM format.
308///
309/// # Returns
310///
311/// A `Result` containing the public key as a string or an error if the conversion fails.
312pub fn public_key_from_secret_key(secret_key: &str) -> Result<String, Box<SdkError>> {
313    // Handle the secret key parsing and map the error
314    let secret_key_from_pem = secret_key_from_pem(secret_key)?;
315
316    // Convert the secret key to public key and handle potential errors
317    let public_key = CasperTypesPublicKey::from(&secret_key_from_pem);
318
319    // Convert to desired public key format
320    let public_key_test: PublicKey = public_key.into();
321
322    // Return the public key as a string
323    Ok(public_key_test.to_string())
324}
325
326/// Converts a hexadecimal string to a vector of unsigned 8-bit integers (Uint8Array).
327///
328/// # Arguments
329///
330/// * `hex_string` - The hexadecimal string to convert.
331///
332/// # Returns
333///
334/// A vector of unsigned 8-bit integers (Uint8Array) containing the converted value.
335pub fn hex_to_uint8_vec(hex_string: &str) -> Vec<u8> {
336    let mut bytes = Vec::with_capacity(hex_string.len() / 2);
337    let mut hex_chars = hex_string.chars();
338    while let (Some(a), Some(b)) = (hex_chars.next(), hex_chars.next()) {
339        if let Ok(byte) = u8::from_str_radix(&format!("{a}{b}"), 16) {
340            bytes.push(byte);
341        } else {
342            // If an invalid hex pair is encountered, return an empty vector.
343            return Vec::new();
344        }
345    }
346    bytes
347}
348
349/// Converts a hexadecimal string to a regular string.
350///
351/// # Arguments
352///
353/// * `hex_string` - The hexadecimal string to convert.
354///
355/// # Returns
356///
357/// A regular string containing the converted value.
358pub fn hex_to_string(hex_string: &str) -> String {
359    match hex::decode(hex_string) {
360        Ok(bytes) => String::from_utf8_lossy(&bytes).to_string(),
361        Err(_) => hex_string.to_string(),
362    }
363}
364
365/// Converts motes to CSPR (Casper tokens).
366///
367/// # Arguments
368///
369/// * `motes` - The motes value to convert.
370///
371/// # Returns
372///
373/// A string representing the CSPR amount.
374pub fn motes_to_cspr(motes: &str) -> Result<String, Box<SdkError>> {
375    match BigDecimal::from_str(motes) {
376        Ok(motes_decimal) => {
377            let divisor = BigDecimal::from(1_000_000_000);
378            let cspr_decimal = &motes_decimal / divisor;
379            let formatted_cspr = format!("{cspr_decimal:.2}");
380
381            if formatted_cspr.ends_with(".00") {
382                Ok(formatted_cspr.replace(".00", ""))
383            } else {
384                Ok(formatted_cspr)
385            }
386        }
387        Err(err) => Err(Box::new(SdkError::CustomError {
388            context: "Failed to parse input as BigDecimal",
389            error: format!("{err:?}"),
390        })),
391    }
392}
393
394/// Pretty prints a serializable value as a JSON string.
395///
396/// # Arguments
397///
398/// * `value` - The serializable value to pretty print.
399/// * `verbosity` - An optional verbosity level for pretty printing.
400///
401/// # Returns
402///
403/// A JSON string representing the pretty printed value.
404pub fn json_pretty_print<T>(value: T, verbosity: Option<Verbosity>) -> Result<String, Box<SdkError>>
405where
406    T: Serialize,
407{
408    let deserialized = serde_json::to_value(&value).map_err(|e| Box::new(SdkError::from(e)))?;
409
410    match verbosity {
411        Some(Verbosity::Low) | None => Ok(deserialized.to_string()),
412        Some(Verbosity::Medium) => casper_types::json_pretty_print(&deserialized).map_err(|err| {
413            Box::new(SdkError::CustomError {
414                context: "Error in json_pretty_print",
415                error: format!("{err}"),
416            })
417        }),
418        Some(Verbosity::High) => {
419            serde_json::to_string_pretty(&deserialized).map_err(|e| Box::new(SdkError::from(e)))
420        }
421    }
422}
423
424/// Inserts a JavaScript value argument into a RuntimeArgs map.
425///
426/// # Arguments
427///
428/// * `args` - The RuntimeArgs map to insert the argument into.
429/// * `js_value_arg` - The JavaScript value argument to insert.
430///
431/// # Returns
432///
433/// The modified `RuntimeArgs` map.
434#[cfg(target_arch = "wasm32")]
435pub fn insert_js_value_arg(
436    args: &mut RuntimeArgs,
437    js_value_arg: JsValue,
438) -> Result<&RuntimeArgs, SdkError> {
439    if js_sys::Object::instanceof(&js_value_arg) {
440        let json_arg: JsonArg = js_value_arg
441            .into_serde()
442            .map_err(|err| SdkError::CustomError {
443                context: "Error converting to JsonArg",
444                error: format!("{err:?}"),
445            })?;
446
447        let named_arg = NamedArg::try_from(json_arg).map_err(|err| SdkError::CustomError {
448            context: "Error converting to NamedArg",
449            error: format!("{err:?}"),
450        })?;
451
452        args.insert_cl_value(named_arg.name(), named_arg.cl_value().clone());
453    } else if let Some(string_arg) = js_value_arg.as_string() {
454        let simple_arg = string_arg;
455        casper_client::cli::insert_arg(&simple_arg, args).map_err(|err| SdkError::CustomError {
456            context: "Error inserting simple arg",
457            error: format!("{err:?}"),
458        })?;
459    } else {
460        return Err(SdkError::CustomError {
461            context: "Error converting to JsonArg or Simple Arg",
462            error: String::from("Conversion failed"),
463        });
464    }
465
466    Ok(args)
467}
468
469/// Inserts an argument into a RuntimeArgs map.
470///
471/// # Arguments
472///
473/// * `args` - The RuntimeArgs map to insert the argument into.
474/// * `new_arg` - The argument as a string.
475///
476/// # Returns
477///
478/// The modified `RuntimeArgs` map.
479pub(crate) fn insert_arg(args: &mut RuntimeArgs, new_arg: String) -> &RuntimeArgs {
480    match serde_json::from_str::<JsonArg>(&new_arg) {
481        Ok(json_arg) => {
482            if let Ok(named_arg) = NamedArg::try_from(json_arg.clone()) {
483                // JSON args
484                args.insert_cl_value(named_arg.name(), named_arg.cl_value().clone());
485            }
486        }
487        Err(_) => {
488            // Simple args
489            let _ = casper_client::cli::insert_arg(&new_arg, args);
490        }
491    }
492    args
493}
494
495#[cfg(test)]
496mod tests {
497    use super::*;
498    use casper_types::U256;
499
500    #[test]
501    fn test_cl_value_to_json() {
502        let cl_value = CLValue::from_t((1, 2, 3)).unwrap();
503        let json_value = cl_value_to_json(&cl_value).unwrap();
504        assert_eq!(
505            json_value,
506            Value::Array(vec![
507                Value::Number(1.into()),
508                Value::Number(2.into()),
509                Value::Number(3.into())
510            ])
511        );
512    }
513
514    #[test]
515    fn test_get_current_timestamp() {
516        let timestamp = Some("1234567890".to_string());
517        let current_timestamp = get_current_timestamp(timestamp);
518        assert_eq!(&current_timestamp, "1970-01-15T06:56:07Z");
519    }
520
521    #[test]
522    fn test_get_blake2b_hash() {
523        let metadata = "some metadata";
524        let hash = get_blake2b_hash(metadata);
525        assert_eq!(
526            &hash,
527            "767de9efccc76bc0eef85ea81fcaa56dc7047e660c74b3dc39f84ab8c4931c0d"
528        );
529    }
530
531    #[test]
532    fn test_get_ttl_or_default() {
533        let ttl = Some("1h".to_string());
534        let ttl_value = get_ttl_or_default(ttl.as_deref());
535        assert_eq!(ttl_value, "1h".to_string());
536
537        let default_ttl = get_ttl_or_default(None);
538        assert_eq!(default_ttl, DEFAULT_TTL.to_string());
539    }
540
541    #[test]
542    fn test_parse_timestamp() {
543        let valid_timestamp = "2023-11-06T12:00:00Z";
544        let parsed_timestamp = parse_timestamp(valid_timestamp);
545        assert!(parsed_timestamp.is_ok());
546
547        let invalid_timestamp = "invalid_timestamp";
548        let parsed_timestamp = parse_timestamp(invalid_timestamp);
549        assert!(parsed_timestamp.is_err());
550    }
551
552    #[test]
553    fn test_parse_ttl() {
554        let valid_ttl = "1h";
555        let parsed_ttl = parse_ttl(valid_ttl);
556        assert!(parsed_ttl.is_ok());
557
558        let invalid_ttl = "invalid_ttl";
559        let parsed_ttl = parse_ttl(invalid_ttl);
560        assert!(parsed_ttl.is_err());
561    }
562
563    #[test]
564    fn test_get_gas_price_or_default() {
565        let gas_price = Some(100);
566        let price = get_gas_price_or_default(gas_price);
567        assert_eq!(price, 100);
568
569        let default_price = get_gas_price_or_default(None);
570        assert_eq!(default_price, DEFAULT_GAS_PRICE);
571    }
572
573    #[test]
574    fn test_get_str_or_default() {
575        let input_str = Some("test_string".to_string());
576        let result = get_str_or_default(input_str.as_ref());
577        assert_eq!(result, "test_string");
578
579        let default_str: Option<String> = None;
580        let result = get_str_or_default(default_str.as_ref());
581        assert_eq!(result, "");
582    }
583
584    #[test]
585    fn test_secret_key_generate() {
586        // Act
587        let result = secret_key_generate();
588
589        // Assert
590        assert!(result.is_ok());
591        let secret_key = result.unwrap();
592        assert_eq!(&secret_key.to_string(), "SecretKey::Ed25519");
593    }
594
595    #[test]
596    fn test_secret_key_secp256k1_generate() {
597        // Act
598        let result = secret_key_secp256k1_generate();
599
600        // Assert
601        assert!(result.is_ok());
602        let secret_key = result.unwrap();
603        assert_eq!(&secret_key.to_string(), "SecretKey::Secp256k1");
604    }
605
606    #[test]
607    fn test_secret_key_from_pem() {
608        let pem_key = "-----BEGIN PRIVATE KEY-----\nTEST\n-----END PRIVATE KEY-----";
609        let result = secret_key_from_pem(pem_key);
610        assert!(result.is_err());
611        let pem_key =
612        "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEII8ULlk1CJ12ZQ+bScjBt/IxMAZNggClWqK56D1/7CbI\n-----END PRIVATE KEY-----";
613        let result = secret_key_from_pem(pem_key);
614        assert!(result.is_ok());
615        assert_eq!(&result.unwrap().to_string(), "SecretKey::Ed25519");
616    }
617
618    #[test]
619    fn test_public_key_from_secret_key() {
620        let pem_key = "-----BEGIN PRIVATE KEY-----\nTEST\n-----END PRIVATE KEY-----";
621        let result = public_key_from_secret_key(pem_key);
622        assert!(result.is_err());
623        let pem_key =
624        "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEII8ULlk1CJ12ZQ+bScjBt/IxMAZNggClWqK56D1/7CbI-----END PRIVATE KEY-----";
625        let result = public_key_from_secret_key(pem_key);
626        assert!(result.is_ok());
627        assert_eq!(
628            result.unwrap(),
629            "01aff5c18a954604dd27d139d8e0cfc533ac3d53784d76c7a7ac5ff4039510fdf6"
630        );
631    }
632
633    #[test]
634    fn test_hex_to_uint8_vec() {
635        let hex_string = "0161e40005434ba3cd9a791a2827f5fa3ee514d1475fe72b2823cbaac9c3c71483";
636        let result = hex_to_uint8_vec(hex_string);
637        assert_eq!(
638            result,
639            vec![
640                1, 97, 228, 0, 5, 67, 75, 163, 205, 154, 121, 26, 40, 39, 245, 250, 62, 229, 20,
641                209, 71, 95, 231, 43, 40, 35, 203, 170, 201, 195, 199, 20, 131
642            ]
643        );
644    }
645
646    #[test]
647    fn test_hex_to_string() {
648        let hex_string = "48656c6c6f20436173706572";
649        let result = hex_to_string(hex_string);
650        assert_eq!(result, "Hello Casper");
651    }
652
653    #[test]
654    fn test_motes_to_cspr() {
655        let motes = "1000000000";
656        let result = motes_to_cspr(motes).unwrap();
657        assert_eq!(result, "1");
658    }
659
660    #[test]
661    fn test_json_pretty_print() {
662        #[derive(Serialize, Clone)]
663        struct TestData {
664            age: i32,
665            name: String,
666        }
667
668        let data = TestData {
669            age: 42,
670            name: "Joe".to_string(),
671        };
672
673        let result = json_pretty_print(data.clone(), None).unwrap();
674        assert_eq!(result, "{\"age\":42,\"name\":\"Joe\"}");
675
676        let result = json_pretty_print(data.clone(), Some(Verbosity::Low)).unwrap();
677        assert_eq!(result, "{\"age\":42,\"name\":\"Joe\"}");
678
679        let result = json_pretty_print(data.clone(), Some(Verbosity::Medium)).unwrap();
680        assert_eq!(result, "{\n  \"age\": 42,\n  \"name\": \"Joe\"\n}");
681
682        let result = json_pretty_print(data, Some(Verbosity::High)).unwrap();
683        assert_eq!(result, "{\n  \"age\": 42,\n  \"name\": \"Joe\"\n}");
684    }
685
686    #[test]
687    fn test_insert_arg_simple() {
688        let mut args = RuntimeArgs::new();
689        let new_arg = "message:String='Hello Casper";
690        let result_args = insert_arg(&mut args, new_arg.to_string());
691        assert_eq!(result_args.len(), 1);
692        let cl_value = result_args.get("message").unwrap();
693        let json = cl_value_to_json(cl_value).unwrap();
694        let expexted_json = Value::String("Hello Casper".to_string());
695        assert_eq!(json, expexted_json);
696    }
697
698    #[test]
699    fn test_insert_arg_json() {
700        let mut args = RuntimeArgs::new();
701        let arg_json = r#"{"name": "bar", "type": "U256", "value": 1}"#; // No brackets only one arg
702        let result_args = insert_arg(&mut args, arg_json.to_string());
703        assert_eq!(result_args.len(), 1);
704        let cl_value = result_args.get("bar").unwrap();
705        let json = cl_value_to_json(cl_value).unwrap();
706        let expexted_json = Value::String("1".to_string());
707        assert_eq!(json, expexted_json);
708    }
709
710    #[test]
711    pub fn test_make_dictionary_item_key() {
712        let key = Key::from_formatted_str(
713            "account-hash-e11bfffe63bf899ea07117af8a2bb43ef0078c0e38ebee6b6cb0b0e39c233538",
714        )
715        .unwrap();
716        let value = U256::from(1);
717        let dictionary_item_key = make_dictionary_item_key(&key, &value);
718        assert_eq!(
719            dictionary_item_key,
720            "145f6211a24c0a8af16b47e7aa58431ea25172eb402903b3c25ac92b9784c7a9".to_string()
721        );
722        let key = Key::from_formatted_str(
723            "account-hash-813428ce1a9805f1087db07e6017c6c4f5af0ee78a05591bb6577763e89b4f1f",
724        )
725        .unwrap();
726        let value = Key::from_formatted_str(
727            "account-hash-e11bfffe63bf899ea07117af8a2bb43ef0078c0e38ebee6b6cb0b0e39c233538",
728        )
729        .unwrap();
730        let dictionary_item_key = make_dictionary_item_key(&key, &value);
731        assert_eq!(
732            dictionary_item_key,
733            "1e26dc82db208943c3785c0e11b9d78b9c408fee748c78dda5a5d016840dedca".to_string()
734        );
735    }
736
737    #[test]
738    fn test_get_base64_key_from_account_hash() {
739        // Test with a known input and expected output
740        let input_hash =
741            "account-hash-b485c074cef7ccaccd0302949d2043ab7133abdb14cfa87e8392945c0bd80a5f";
742        let expected_output = "ALSFwHTO98yszQMClJ0gQ6txM6vbFM+ofoOSlFwL2Apf";
743
744        // Call the function under test
745        let result = get_base64_key_from_account_hash(input_hash).unwrap();
746
747        // Check the result against the expected output
748        assert_eq!(result, expected_output.to_string());
749    }
750
751    #[test]
752    fn test_get_base64_key_from_key_hash() {
753        // Test with a known input and expected output
754        let input_hash = "hash-b485c074cef7ccaccd0302949d2043ab7133abdb14cfa87e8392945c0bd80a5f";
755        let expected_output = "AbSFwHTO98yszQMClJ0gQ6txM6vbFM+ofoOSlFwL2Apf";
756
757        // Call the function under test
758        let result = get_base64_key_from_key_hash(input_hash).unwrap();
759
760        // Check the result against the expected output
761        assert_eq!(result, expected_output.to_string());
762    }
763}