Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace JsValue::into/from_serde with serde-wasm-bindgen #678

Merged
merged 4 commits into from
Jun 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ url = { version = "2.1", optional = true }
## EIP-1193
js-sys = { version = "0.3.45", optional = true }
### This is a transitive dependency, only here so we can turn on its wasm_bindgen feature
rand = { version = "0.8.1", optional = true }
getrandom = { version = "0.2", features = ["js"], optional = true }
wasm-bindgen = { version = "0.2.68", optional = true, features = ["serde-serialize"] }
rand = { version = "0.8.1", optional = true }
serde-wasm-bindgen = { version = "0.4.3", optional = true }
wasm-bindgen = { version = "0.2.68", optional = true }
wasm-bindgen-futures = { version = "0.4.18", optional = true }

[dev-dependencies]
Expand All @@ -69,7 +70,7 @@ tokio-stream = { version = "0.1", features = ["net"] }

[features]
default = ["http-tls", "signing", "ws-tls-tokio", "ipc-tokio"]
wasm = ["js-sys", "wasm-bindgen", "wasm-bindgen-futures", "futures-timer/wasm-bindgen", "rand", "getrandom"]
wasm = ["futures-timer/wasm-bindgen", "getrandom", "js-sys", "rand", "serde-wasm-bindgen", "wasm-bindgen", "wasm-bindgen-futures"]
eip-1193 = ["wasm"]
_http_base = ["reqwest", "bytes", "url", "base64", "headers"]
http = ["_http_base"]
Expand Down
36 changes: 19 additions & 17 deletions src/transports/eip_1193.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ use jsonrpc_core::{
types::request::{Call, MethodCall},
};
use serde::{
de::{value::StringDeserializer, IntoDeserializer},
Deserialize,
de::{value::StringDeserializer, DeserializeOwned, IntoDeserializer},
Deserialize, Serialize,
};
use serde_wasm_bindgen::Serializer;
use std::{cell::RefCell, collections::BTreeMap, rc::Rc};
use wasm_bindgen::{prelude::*, JsCast};

Expand All @@ -41,7 +42,7 @@ impl Eip1193 {
let subscriptions: Subscriptions = Subscriptions::default();
let subscriptions_for_closure = subscriptions.clone();
let msg_handler = Closure::wrap(Box::new(move |evt_js: JsValue| {
let evt = evt_js.into_serde::<MessageEvent>().expect("Couldn't parse event data");
let evt = deserialize_from_js::<MessageEvent>(evt_js).expect("Couldn't parse event data");
log::trace!("Message from provider: {:?}", evt);
match evt.event_type.as_str() {
"eth_subscription" => {
Expand Down Expand Up @@ -70,9 +71,7 @@ impl Eip1193 {
/// be closed when the `Eip1193` is dropped.
pub fn connect_stream(&self) -> impl Stream<Item = Option<String>> {
self.handle_ad_hoc_event("connect", |evt_js| {
let evt = evt_js
.into_serde::<ConnectEvent>()
.expect("couldn't parse connect event");
let evt = deserialize_from_js::<ConnectEvent>(evt_js).expect("couldn't parse connect event");
evt.chain_id
})
}
Expand All @@ -81,7 +80,7 @@ impl Eip1193 {
/// above.
pub fn disconnect_stream(&self) -> impl Stream<Item = jsonrpc_core::Error> {
self.handle_ad_hoc_event("disconnect", |evt_js| {
evt_js.into_serde().expect("deserializing disconnect error failed")
deserialize_from_js(evt_js).expect("deserializing disconnect error failed")
})
}

Expand Down Expand Up @@ -179,7 +178,7 @@ impl Transport for Eip1193 {
..
}) => {
let js_params =
js_sys::Array::from(&JsValue::from_serde(&params).expect("couldn't send method params via JSON"));
js_sys::Array::from(&serialize_to_js(&params).expect("couldn't send method params via JSON"));
let copy = self.provider_and_listeners.borrow().provider.clone();
Box::pin(async move {
copy.request_wrapped(RequestArguments {
Expand Down Expand Up @@ -240,7 +239,6 @@ impl Provider {
fn parse_response(resp: Result<JsValue, JsValue>) -> error::Result<serde_json::value::Value> {
// Fix #544
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RPCErrorExtra {
/// Code
pub code: RPCErrorCode,
Expand All @@ -263,8 +261,8 @@ impl Provider {
}

let parsed_value = resp
.map(|res| res.into_serde())
.map_err(|err| err.into_serde::<RPCErrorExtra>());
.map(deserialize_from_js)
.map_err(deserialize_from_js::<RPCErrorExtra>);
match parsed_value {
Ok(Ok(res)) => Ok(res),
Err(Ok(err)) => Err(Error::Rpc(err.into())),
Expand Down Expand Up @@ -333,21 +331,29 @@ impl RequestArguments {
}
}

fn serialize_to_js<T: Serialize>(value: &T) -> Result<JsValue, serde_wasm_bindgen::Error> {
value.serialize(&Serializer::json_compatible())
}

fn deserialize_from_js<T: DeserializeOwned>(value: JsValue) -> Result<T, serde_wasm_bindgen::Error> {
serde_wasm_bindgen::from_value(value)
}

#[cfg(test)]
mod tests {
use super::*;
use wasm_bindgen_test::*;

fn json_to_js(json: &str) -> JsValue {
let json_value = serde_json::from_str::<serde_json::Value>(json).unwrap();
let js_value = JsValue::from_serde(&json_value).unwrap();
let js_value = serialize_to_js(&json_value).unwrap();
js_value
}

#[wasm_bindgen_test]
fn parses_valid_response_correctly() {
let value = serde_json::from_str::<serde_json::Value>(r#"[1, false, null, "string"]"#).unwrap();
let response = Ok(JsValue::from_serde(&value).unwrap());
let response = Ok(serialize_to_js(&value).unwrap());
let expected_result = Ok(value);
assert_eq!(Provider::parse_response(response), expected_result);

Expand All @@ -368,10 +374,6 @@ mod tests {
Provider::parse_response(Err(json_to_js(r#"{"code": "red", "message": ""}"#))),
Err(Error::InvalidResponse(_))
));
assert!(matches!(
Provider::parse_response(Err(json_to_js(r#"{"code": 0, "message": "", "extra": true}"#))),
Err(Error::InvalidResponse(_))
));
assert!(matches!(
Provider::parse_response(Err(json_to_js(r#"{}"#))),
Err(Error::InvalidResponse(_))
Expand Down