tomusdrw/rust-web3

Issue in EIP-1193 transport via wasm

Opened this issue · 1 comments

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

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

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;
        ....
}

Also, just in case its useful, it seems you can avoid the injection of script to get the provider at

#[wasm_bindgen(inline_js = "export function get_provider_js() {return window.ethereum}")]
extern "C" {
#[wasm_bindgen(catch)]
fn get_provider_js() -> Result<Option<Provider>, JsValue>;
}

by doing something like the following, based on rustwasm/wasm-bindgen#2632 (comment). 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...