1
+ use std:: iter:: FromIterator ;
1
2
use bdk_esplora:: {
2
3
esplora_client:: { self , AsyncClient } ,
3
4
EsploraAsyncExt ,
@@ -6,6 +7,7 @@ use bdk_wallet::{chain::Merge, bitcoin::Network, ChangeSet, KeychainKind, Wallet
6
7
use js_sys:: Date ;
7
8
use wasm_bindgen:: prelude:: * ;
8
9
use serde_wasm_bindgen:: { from_value, to_value} ;
10
+ use serde_json:: { self , Value } ;
9
11
10
12
const PARALLEL_REQUESTS : usize = 1 ;
11
13
@@ -71,15 +73,18 @@ impl WalletWrapper {
71
73
} )
72
74
}
73
75
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
+
76
82
let wallet_opt = Wallet :: load ( )
77
83
. descriptor ( KeychainKind :: External , Some ( external_descriptor. to_string ( ) ) )
78
84
. descriptor ( KeychainKind :: Internal , Some ( internal_descriptor. to_string ( ) ) )
79
85
. extract_keys ( )
80
86
. load_wallet_no_persist ( changeset) ?;
81
87
82
-
83
88
let wallet = match wallet_opt {
84
89
Some ( wallet) => wallet,
85
90
None => return Err ( JsError :: new ( "Failed to load wallet, check the changeset" ) ) ,
@@ -144,24 +149,92 @@ impl WalletWrapper {
144
149
}
145
150
146
151
// --8<-- [start:store]
147
- pub fn take_staged ( & mut self ) -> JsResult < JsValue > {
152
+ pub fn take_staged ( & mut self ) -> JsResult < String > {
148
153
match self . wallet . take_staged ( ) {
149
154
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) ?)
151
163
}
152
- None => Ok ( JsValue :: null ( ) ) ,
164
+ None => Ok ( " null" . to_string ( ) ) ,
153
165
}
154
166
}
155
167
156
- pub fn take_merged ( & mut self , previous : JsValue ) -> JsResult < JsValue > {
168
+ pub fn take_merged ( & mut self , previous : String ) -> JsResult < String > {
157
169
match self . wallet . take_staged ( ) {
158
170
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) ?)
162
186
}
163
- None => Ok ( JsValue :: null ( ) ) ,
187
+ None => Ok ( " null" . to_string ( ) ) ,
164
188
}
165
189
}
166
190
// --8<-- [end:store]
167
191
}
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