Skip to content

Commit

Permalink
feat: Decode with iter by default (#21)
Browse files Browse the repository at this point in the history
Co-authored-by: Leigh McCulloch <[email protected]>
  • Loading branch information
willemneal and leighmcculloch authored Nov 15, 2024
1 parent 8441f83 commit 85159d5
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 1 deletion.
28 changes: 27 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
mod console_error_panic_hook;

use schemars::gen::SchemaSettings;
use std::io::Cursor;
use std::str::FromStr;
use stellar_xdr::curr::{Limits, Type, TypeVariant, WriteXdr};
use stellar_xdr::curr::{Limited, Limits, Type, TypeVariant, WriteXdr};
use wasm_bindgen::prelude::*;

/// Returns a list of XDR types.
Expand Down Expand Up @@ -44,6 +45,31 @@ pub fn guess(xdr_base64: String) -> Vec<String> {
.collect()
}

/// Decodes a stream of XDR into an array of JSONs.
///
/// Returns an array of JSON strings.
///
/// Returns a JSON string.
#[wasm_bindgen]
pub fn decode_stream(type_variant: String, xdr_base64: String) -> Result<Vec<String>, String> {
let type_variant = TypeVariant::from_str(&type_variant).map_err(|e| format!("{e}"))?;

// Base64 when decoded will have a length at or under this len.
// Ref: https://datatracker.ietf.org/doc/html/rfc4648#page-5
let decoded_max_len = xdr_base64.len() / 4 * 3;
// Limit decoding attempts to within the maximum length of the known input.
let limits = Limits::len(decoded_max_len);
let mut cursor = Limited::new(Cursor::new(xdr_base64.as_bytes()), limits);

let json = Type::read_xdr_base64_iter(type_variant, &mut cursor)
.map(|value| {
serde_json::to_string(&value.map_err(|e| format!("{e}"))?).map_err(|e| format!("{e}"))
})
.collect::<Result<Vec<_>, _>>()?;
// TODO: Return a native JS value.
Ok(json)
}

/// Decodes the XDR into JSON.
///
/// Accepts a XDR base64 string.
Expand Down
18 changes: 18 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,24 @@ fn decode_success() {
);
}

#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn decode_iter_success() {
assert_eq!(
stellar_xdr_json::decode_stream(
"ScSpecEntry".to_string(),
"AAAAAAAAAAAAAAAKaW5pdGlhbGl6ZQAAAAAAAwAAAAAAAAAPdG9rZW5fd2FzbV9oYXNoAAAAA+4AAAAgAAAAAAAAAAd0b2tlbl9hAAAAABMAAAAAAAAAB3Rva2VuX2IAAAAAEwAAAAAAAAAAAAAAAAAAAAhzaGFyZV9pZAAAAAAAAAABAAAAEwAAAAAAAAAAAAAAB2RlcG9zaXQAAAAABQAAAAAAAAACdG8AAAAAABMAAAAAAAAACWRlc2lyZWRfYQAAAAAAAAsAAAAAAAAABW1pbl9hAAAAAAAACwAAAAAAAAAJZGVzaXJlZF9iAAAAAAAACwAAAAAAAAAFbWluX2IAAAAAAAALAAAAAAAAAAAAAAAAAAAABHN3YXAAAAAEAAAAAAAAAAJ0bwAAAAAAEwAAAAAAAAAFYnV5X2EAAAAAAAABAAAAAAAAAANvdXQAAAAACwAAAAAAAAAGaW5fbWF4AAAAAAALAAAAAAAAAAAAAAAAAAAACHdpdGhkcmF3AAAABAAAAAAAAAACdG8AAAAAABMAAAAAAAAADHNoYXJlX2Ftb3VudAAAAAsAAAAAAAAABW1pbl9hAAAAAAAACwAAAAAAAAAFbWluX2IAAAAAAAALAAAAAQAAA+0AAAACAAAACwAAAAsAAAAAAAAAAAAAAAlnZXRfcnNydnMAAAAAAAAAAAAAAQAAA+0AAAACAAAACwAAAAs=".to_string(),
),
Ok([r#"{"function_v0":{"doc":"","name":"initialize","inputs":[{"doc":"","name":"token_wasm_hash","type_":{"bytes_n":{"n":32}}},{"doc":"","name":"token_a","type_":"address"},{"doc":"","name":"token_b","type_":"address"}],"outputs":[]}}"#,
r#"{"function_v0":{"doc":"","name":"share_id","inputs":[],"outputs":["address"]}}"#,
r#"{"function_v0":{"doc":"","name":"deposit","inputs":[{"doc":"","name":"to","type_":"address"},{"doc":"","name":"desired_a","type_":"i128"},{"doc":"","name":"min_a","type_":"i128"},{"doc":"","name":"desired_b","type_":"i128"},{"doc":"","name":"min_b","type_":"i128"}],"outputs":[]}}"#,
r#"{"function_v0":{"doc":"","name":"swap","inputs":[{"doc":"","name":"to","type_":"address"},{"doc":"","name":"buy_a","type_":"bool"},{"doc":"","name":"out","type_":"i128"},{"doc":"","name":"in_max","type_":"i128"}],"outputs":[]}}"#,
r#"{"function_v0":{"doc":"","name":"withdraw","inputs":[{"doc":"","name":"to","type_":"address"},{"doc":"","name":"share_amount","type_":"i128"},{"doc":"","name":"min_a","type_":"i128"},{"doc":"","name":"min_b","type_":"i128"}],"outputs":[{"tuple":{"value_types":["i128","i128"]}}]}}"#,
r#"{"function_v0":{"doc":"","name":"get_rsrvs","inputs":[],"outputs":[{"tuple":{"value_types":["i128","i128"]}}]}}"#
].iter().map(ToString::to_string).collect::<Vec<String>>()),
);
}

#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn decode_length_limit_protection() {
Expand Down

0 comments on commit 85159d5

Please sign in to comment.