Skip to content

Commit 13223ac

Browse files
committed
feat: move wallet data serialization logic into rust methods
1 parent 1ad389c commit 13223ac

File tree

3 files changed

+87
-30
lines changed

3 files changed

+87
-30
lines changed

Diff for: examples/wasm/js/index.js

+2-19
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,10 @@ const Store = {
88
console.log("No data to save");
99
return;
1010
}
11-
const serializedStaged = JSON.stringify(data, (key, value) => {
12-
if (value instanceof Map) {
13-
return {
14-
dataType: 'Map',
15-
value: Array.from(value.entries())
16-
};
17-
}
18-
return value;
19-
});
20-
localStorage.setItem("walletData", serializedStaged);
11+
localStorage.setItem("walletData", data); // data is already a JSON string
2112
},
2213
load: () => {
23-
const walletDataString = localStorage.getItem("walletData");
24-
// Convert serialized Maps back to Map objects when loading
25-
const walletData = JSON.parse(walletDataString, (key, value) => {
26-
if (value?.dataType === 'Map') {
27-
return new Map(value.value);
28-
}
29-
return value;
30-
});
31-
return walletData;
14+
return localStorage.getItem("walletData"); // return the JSON string directly
3215
}
3316
}
3417
// --8<-- [end:store]

Diff for: examples/wasm/rust/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ wasm-bindgen-futures = "0.4.45"
1616
js-sys = "0.3.72"
1717
web-sys = { version = "0.3.72", features = ["console"] }
1818
serde-wasm-bindgen = "0.6.5"
19+
serde_json = "1.0"
1920

2021
# The `console_error_panic_hook` crate provides better debugging of panics by
2122
# logging them with `console.error`. This is great for development, but requires

Diff for: examples/wasm/rust/src/lib.rs

+84-11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::iter::FromIterator;
12
use bdk_esplora::{
23
esplora_client::{self, AsyncClient},
34
EsploraAsyncExt,
@@ -6,6 +7,7 @@ use bdk_wallet::{chain::Merge, bitcoin::Network, ChangeSet, KeychainKind, Wallet
67
use js_sys::Date;
78
use wasm_bindgen::prelude::*;
89
use serde_wasm_bindgen::{from_value, to_value};
10+
use serde_json::{self, Value};
911

1012
const PARALLEL_REQUESTS: usize = 1;
1113

@@ -71,15 +73,18 @@ impl WalletWrapper {
7173
})
7274
}
7375

74-
pub fn load(changeset: JsValue, url: &str, external_descriptor: &str, internal_descriptor: &str) -> JsResult<WalletWrapper> {
75-
let changeset = from_value(changeset)?;
76+
pub fn load(changeset_str: &str, url: &str, external_descriptor: &str, internal_descriptor: &str) -> JsResult<WalletWrapper> {
77+
// Parse the JSON string and restore maps
78+
let changeset_value: Value = serde_json::from_str(changeset_str)?;
79+
let restored_value = restore_maps(changeset_value);
80+
let changeset: ChangeSet = serde_json::from_value(restored_value)?;
81+
7682
let wallet_opt = Wallet::load()
7783
.descriptor(KeychainKind::External, Some(external_descriptor.to_string()))
7884
.descriptor(KeychainKind::Internal, Some(internal_descriptor.to_string()))
7985
.extract_keys()
8086
.load_wallet_no_persist(changeset)?;
8187

82-
8388
let wallet = match wallet_opt {
8489
Some(wallet) => wallet,
8590
None => return Err(JsError::new("Failed to load wallet, check the changeset")),
@@ -144,24 +149,92 @@ impl WalletWrapper {
144149
}
145150

146151
// --8<-- [start:store]
147-
pub fn take_staged(&mut self) -> JsResult<JsValue> {
152+
pub fn take_staged(&mut self) -> JsResult<String> {
148153
match self.wallet.take_staged() {
149154
Some(changeset) => {
150-
Ok(to_value(&changeset)?)
155+
// First convert to a generic Value that we can modify
156+
let mut value = serde_json::to_value(&changeset)?;
157+
158+
// Handle Map serialization
159+
transform_maps(&mut value);
160+
161+
// Convert to JSON string
162+
Ok(serde_json::to_string(&value)?)
151163
}
152-
None => Ok(JsValue::null()),
164+
None => Ok("null".to_string()),
153165
}
154166
}
155167

156-
pub fn take_merged(&mut self, previous: JsValue) -> JsResult<JsValue> {
168+
pub fn take_merged(&mut self, previous: String) -> JsResult<String> {
157169
match self.wallet.take_staged() {
158170
Some(curr_changeset) => {
159-
let mut changeset: ChangeSet = from_value(previous)?;
160-
changeset.merge(curr_changeset);
161-
Ok(to_value(&changeset)?)
171+
// Parse the previous JSON string
172+
let previous_value: Value = serde_json::from_str(&previous)?;
173+
174+
// Convert back from our custom Map format
175+
let mut previous_changeset: ChangeSet =
176+
serde_json::from_value(restore_maps(previous_value))?;
177+
178+
previous_changeset.merge(curr_changeset);
179+
180+
// Convert to Value and handle Map serialization
181+
let mut final_value = serde_json::to_value(&previous_changeset)?;
182+
transform_maps(&mut final_value);
183+
184+
// Convert to JSON string
185+
Ok(serde_json::to_string(&final_value)?)
162186
}
163-
None => Ok(JsValue::null()),
187+
None => Ok("null".to_string()),
164188
}
165189
}
166190
// --8<-- [end:store]
167191
}
192+
193+
fn transform_maps(value: &mut Value) {
194+
match value {
195+
Value::Object(map) => {
196+
for (_, v) in map.iter_mut() {
197+
transform_maps(v);
198+
}
199+
}
200+
Value::Array(arr) => {
201+
for v in arr.iter_mut() {
202+
transform_maps(v);
203+
}
204+
}
205+
Value::Object(obj) if obj.contains_key("entries") => {
206+
// This assumes Map-like structures have an "entries" field
207+
*value = Value::Object(serde_json::Map::from_iter([
208+
("dataType".to_string(), Value::String("Map".to_string())),
209+
("value".to_string(), obj["entries"].clone()),
210+
]));
211+
}
212+
_ => {}
213+
}
214+
}
215+
216+
fn restore_maps(mut value: Value) -> Value {
217+
match &value {
218+
Value::Object(map) => {
219+
if map.get("dataType").and_then(Value::as_str) == Some("Map") {
220+
if let Some(entries) = map.get("value") {
221+
let mut new_obj = serde_json::Map::new();
222+
new_obj.insert("entries".to_string(), entries.clone());
223+
Value::Object(new_obj)
224+
} else {
225+
value
226+
}
227+
} else {
228+
let mut new_map = serde_json::Map::new();
229+
for (k, v) in map {
230+
new_map.insert(k.clone(), restore_maps(v.clone()));
231+
}
232+
Value::Object(new_map)
233+
}
234+
}
235+
Value::Array(arr) => {
236+
Value::Array(arr.iter().map(|v| restore_maps(v.clone())).collect())
237+
}
238+
_ => value,
239+
}
240+
}

0 commit comments

Comments
 (0)