tomusdrw / rust-web3

Ethereum JSON-RPC multi-transport client. Rust implementation of web3 library. ENS address: rust-web3.eth
MIT License
1.45k stars 465 forks source link

Issue in EIP-1193 transport via wasm #621

Open evilrobot-01 opened 2 years ago

evilrobot-01 commented 2 years ago

Hey,

Firstly thanks for the great library! I'm pretty new to Rust so have been using it to learn, particularly with wallet interaction via wasm. In testing connection with various wallets I found that Rabby (fork of Metamask) had issues when calling eth_requestAccounts. After debugging using the Rabby source, it seems it may be down to how the RequestArguments struct is passed, perhaps due to TypeScript being used by the wallet.

I stuck a breakpoint in the browser debugger near the source of the error (wallet source) and found that the RequestArguments object being passed in is just a pointer (> data line in console area of screenshot below), which then resulted in an RPC error. If I then re-ran it and manually replaced the value of the data with a javascript object (> data = {method: "eth_requestAccounts", params: []} line in screenshot), then the request was successful.

image

After replicating some of your code in my own library to debug/learn, I found that changing the type of args from RequestArguments to JsValue in the request method definition from https://github.com/tomusdrw/rust-web3/blob/8796c88c4cb95864bdfeffb40ebb061c283aca74/src/transports/eip_1193.rs#L224-L225 to the following seemed to solved this:

#[wasm_bindgen(method, catch)]
async fn request(this: &Provider, args: JsValue) -> Result<JsValue, JsValue>;

I then converted the RequestArguments struct to a JsValue via a wrapper method before calling the wasm method:

async fn request(&self, args: RequestArguments) -> Result<JsValue, Error> {
        let args = JsValue::from_serde(&args).unwrap();
        self.0.request(args).await;
        ....
}
evilrobot-01 commented 2 years ago

Also, just in case its useful, it seems you can avoid the injection of script to get the provider at https://github.com/tomusdrw/rust-web3/blob/2711cd00d51bbfa6be1996cebdd991f7ed77115c/src/transports/eip_1193.rs#L311-L315

by doing something like the following, based on https://github.com/rustwasm/wasm-bindgen/issues/2632#issuecomment-912915987. The lower casing of window is important though.

// Getters can only be declared on classes, so we need a fake type to declare it on.
#[wasm_bindgen]
#[allow(non_camel_case_types)]
type window;

#[wasm_bindgen(static_method_of = window, js_name = ethereum, getter)]
fn provider() -> Option<Provider>;

type Provider;

Not sure if there is any real difference tho really...