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

Create JS/Kotlin/etc. bindings for bitcoin_client_rs #111

Open
bigspider opened this issue Feb 3, 2023 · 3 comments
Open

Create JS/Kotlin/etc. bindings for bitcoin_client_rs #111

bigspider opened this issue Feb 3, 2023 · 3 comments

Comments

@bigspider
Copy link
Collaborator

It would be very useful to create bindings from the rust library to various targets that developers need - especially JS and JVM-based.

@bigspider
Copy link
Collaborator Author

I did some experiments in trying to create JS bindings with wasm-bindgen. Unsuccessful so far, leaving some notes for future reference.

===

I did manage to use the transport object from JS code(from @ledgerhq/hw-transport-node-hid in a Rust class, in turn exported to JS run in node.

===

A limitation of wasm-bindgen is that it cannot export objects with type parameters; therefore, a wrapper of BitcoinClient<Transport> seems necessary, e.g. a struct like:

#[wasm_bindgen]
pub struct BitcoinClientJS {
    client: BitcoinClient<Transport>,
}

I tried to import a transport object from JS and implement the Transport trait

#[wasm_bindgen]
extern "C" {
    pub type TransportJS;

    #[wasm_bindgen(method)]
    pub async fn send(this: &TransportJS, cla: u8, ins: u8, p1: u8, p2: u8, data: &[u8])
        -> JsValue;
}

#[async_trait]
impl Transport for TransportJS {
    type Error = Box<dyn Error>;

    async fn exchange(&self, command: &APDUCommand) -> Result<(StatusWord, Vec<u8>), Self::Error> {
        todo!()
    }
}

That should be possible as per the initial experiment above, but I couldn't make it work; apart from some painful limitations of wasm-bindgen on the allowed returned types for the public members, I hit a roadblock when I started getting errors when trying to implement exchange for TransportJS, like:

55 |       async fn exchange(&self, command: &APDUCommand) -> Result<(StatusWord, Vec<u8>), Self::Error> {
   |  ___________________________________________________________________________________________________^
56 | |         let result = self
57 | |             .send(command.cla, command.ins, command.p1, command.p2, &vec![])
58 | |             .await;
...  |
63 | |         }
64 | |     }
   | |_____^ future created by async block is not `Send`

I don't know how to fix this; attempts to wrap things in Arc or Mutex failed, I couldn't get it to compile.

===

A second attempt to avoid having to call JS code from Rust world initially seemed promising, but the existing implementation of the Transport class depend on the ledger-transport-hid crate, which in turn depends on hidapi that does not compile to the wasm32-unknown-unknown; not sure if this is solvable at all, so this approach is probably not worth pursuing.

error: failed to run custom build command for `hidapi v1.5.0`

...

Caused by: failed to execute `cargo build`: exited with exit status: 101
  full command: "cargo" "build" "--lib" "--release" "--target" "wasm32-unknown-unknown"

@edouardparis
Copy link
Contributor

I found this:
https://stackoverflow.com/questions/71217860/how-to-call-an-async-javascript-import-function-from-webassembly-rust-in-a-nod
Maybe it can help you solve your problem. (Sharing here because I cannot post links on the Ledger discord)

@bigspider
Copy link
Collaborator Author

Thanks @edouardparis, I didn't manage even in that way, either − but it's a useful reference for this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants