Skip to content

Conversation

@riverKanies
Copy link
Contributor

@riverKanies riverKanies commented Mar 12, 2025

WIP!

Closes #46

!!! Attention !!!

There is no immediate plan to move forward with these WASM bindings at this time. Here are some notes on the current state of them, hopefully this will make it easy enough to revisit in the future:

We never found an exciting use case for the WASM bindings, so I’m not planning to get a grant to work on them. To even get a change to rust-payjoin merged to support them I’d need to fully update them to include the v0.23.0 persistence changes, that’s a lot of work I have no motivation to do.

rn bindings work as shown in this demo: GitHub - riverKanies/payjoin-wasm-example-app at v1 which depends on npm modules generated by wasm-pack for bdk-wasm and payjoin-ffi (see deps for links to those module repos)

the actual Bindings are generated by this branch of payjoin-ffi:
Wasm bindings by riverKanies · Pull Request #49 · LtbLightning/payjoin-ffi at commit 1ca33df084694f34e0a7412193cd5a1ab595c292

the PR links to my local version of rust-payjoin for dev/testing, the version used to build payjoin-ffi is Use web_time::SystemTime by riverKanies · Pull Request #596 · payjoin/rust-payjoin (but we probably want to do something more like Add Receiver.new_with_time by riverKanies · Pull Request #594 · payjoin/rust-payjoin tho)

unfortunately it seems this is the state I’ll have to leave it in for now as updating for merge and then ongoing maintenance is not currently justified by any actual integrations of the bindings.

also one outstanding question for these bindings is how to manage ohttp key fetching, Dan commented:
"you can compile a TLS stack to wasm by including the rustls dependency. It's a duplicate dep, since the browser already has TLS that it doesn't let you access, but it is a complete security story. I'm not sure if you can use HTTPS-in-HTTPS with CONNECT method to do it but you can definitely do HTTPS-in-WSS to, as demonstrated in Mutiny"

!!! End !!!

Original comment:

WASM bindings are now building (only on Uri type rn)

the payjoinError depended on io so I modified that to just handle strings for now, need to sort out what we actually want to do here

@DanGould
Copy link
Contributor

DanGould commented Mar 12, 2025

payjoin/io pulls in reqwest, which is not going to work in wasm. You're going to want to feature gate that (perhaps with payjoin-ffi's own io feature and NOT enable it for the wasm targets.

Comment on lines +1 to +3
[env]
AR = "/opt/homebrew/opt/llvm/bin/llvm-ar"
CC = "/opt/homebrew/opt/llvm/bin/clang" No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not everyone building is going to use homebrew. You probably don't want to commit your own environment here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah this is something we've been noting in the readme on wasm libs since it's mac specific

@riverKanies
Copy link
Contributor Author

riverKanies commented Mar 12, 2025

Original error:
Seems it's almost building the wasm bindings but hitting this error on the Proxy:

error[E0432]: unresolved import `reqwest::Proxy`
   --> /Users/river/.cargo/registry/src/index.crates.io-6f17d22bba15001f/payjoin-0.22.0/src/io.rs:21:27
    |
21  |     use reqwest::{Client, Proxy};
    |                           ^^^^^ no `Proxy` in the root
    |
note: found an item that was configured out
   --> /Users/river/.cargo/registry/src/index.crates.io-6f17d22bba15001f/reqwest-0.12.9/src/lib.rs:348:27
    |
348 |     pub use self::proxy::{Proxy,NoProxy};
    |                           ^^^^^
note: the item is gated here
   --> /Users/river/.cargo/registry/src/index.crates.io-6f17d22bba15001f/reqwest-0.12.9/src/lib.rs:337:1
    |
337 | / if_hyper! {
338 | |     #[cfg(test)]
339 | |     #[macro_use]
340 | |     extern crate doc_comment;
...   |
367 | |     mod util;
368 | | }
    | |_^
    = note: this error originates in the macro `if_hyper` (in Nightly builds, run with -Z macro-backtrace for more info)

   Compiling bitcoin-ffi v0.1.2 (https://github.com/bitcoindevkit/bitcoin-ffi.git?rev=4cd8e644dbf4e001d71d5fffb232480fa5ff2246#4cd8e644)
error[E0599]: no method named `proxy` found for struct `ClientBuilder` in the current scope
  --> /Users/river/.cargo/registry/src/index.crates.io-6f17d22bba15001f/payjoin-0.22.0/src/io.rs:26:36
   |
26 |     let client = Client::builder().proxy(proxy).build()?;
   |                                    ^^^^^ method not found in `ClientBuilder`

More helpful notes from Dan:
"""
I suggest ignoring fetch_ohttp_keys to start

There's a separate https-in-websocket implementation and support on the relay so we can avoid it in the browser

That implementation is here: https://github.com/MutinyWallet/mutiny-node/pull/820/files#diff-9bd1c92f85da5773c1cf3b66662d28004dd0c00ab719781af7d7a77aa712fb20R140-R187 and could be part of a wasm feature exclusive function

You could get ohttp-keys out of band and encode the binary in your js blob to make smoke tests work without JIT fetching that's done with fetch_ohttp_keys

Gotta just disable the io feature on the wasm path so reqwest isn't a dependency. I left a comment
"""

@riverKanies
Copy link
Contributor Author

@DanGould I noted your comment:
"You could get ohttp-keys out of band and encode the binary in your js blob to make smoke tests work without JIT fetching that's done with fetch_ohttp_keys"
But I do not yet fully understand what would be involved here. I need to get ohttp keys to init a Receiver so I can test wasm bindings. I think it'd be easiest if I could get them as a string I can just hard code in js to start. But I'm not yet familiar with the ohttp protocol so I have some questions. Should I just get some ohttp keys using the payjoin-cli? are they 'ephemeral' keys so to speak, what I mean is: anyone who has them can act on behalf of the user essentially? Are there considerations about keys expiring? For the hackathon we will need to address this in some semi-robust way.

You also mentioned the possibility of passing keys through bip21 OH1 param, who would be doing the passing here? would this be an additional QR shared between receiver and sender? I was thinking keys come from the relay. Anyway, I'm working to understand this better now, but any hints would be appreciated

@DanGould
Copy link
Contributor

Should I just get some ohttp keys using the payjoin-cli?

Read fetch_ohttp_keys to get the binary (file). You can get it with a GET request in your browser or with curl

are they 'ephemeral' keys so to speak, what I mean is: anyone who has them can act on behalf of the user essentially?

Which user?

OhttpKeys (OHTTP Key Configurations ) replace TLS certificates.

Are there considerations about keys expiring? For the hackathon we will need to address this in some semi-robust way.

Yes, they expire, but are long lived so hard coding will work for demo purposes. If you control the directory server for the purposes of a demo you control when the keys are refreshed.

You also mentioned the possibility of passing keys through bip21 OH1 param, who would be doing the passing here? would this be an additional QR shared between receiver and sender? I was thinking keys come from the relay.

OH1... in a bip21 fragment is a bech32 encoding of the OHTTP Keys. That can be read in the source. No additional QR, it's already in the bip21, and I wouldn't bother with QR scanning for a simple demo. Just use the URI text. OhttpKeys come from the Directory.

@riverKanies
Copy link
Contributor Author

Should I just get some ohttp keys using the payjoin-cli?

Read fetch_ohttp_keys to get the binary (file). You can get it with a GET request in your browser or with curl

Are there considerations about keys expiring? For the hackathon we will need to address this in some semi-robust way.

Yes, they expire, but are long lived so hard coding will work for demo purposes. If you control the directory server for the purposes of a demo you control when the keys are refreshed.

ok cool, makes sense now. they are gateway keys, not session keys. I added a convenience method to the cli for this payjoin/rust-payjoin#589

Experimenting with exposing just the Uri type with WASM bindings first

Want to test "wasm" feature flag for WASM specific modifications to methods

the .cargo/config settings are mac specific

Hitting issue with the proxy
Need to sort out how to handle errors
Just remove redundant (hopefully) rlib type
starting with only string inputs/outputs

err: getting null rust pointer in browser when trying to call .id() or .to_json()
Need to pass in system time from JS conotext for WASM

todo: turst current time logic into a helper method
wrap PdkRequest and make js getters

err: currently getting a timeout error when actually making the request,
probably the url or body is the issue
@darioAnongba
Copy link

little comment:reqwest should work in the browser when targeting wasm @DanGould

@DanGould
Copy link
Contributor

@darioAnongba I had used reqwest in this mutiny payjoin implementation. The only place it's used in the payjoin library is with the io feature for fetch via HTTPS-in-HTTP (CONNECT tunnel) which I'm not sure I could get working with reqwest compiled to wasm.

@DanGould
Copy link
Contributor

What's the plan for rebase / review here? It'd be nice if there were some piece of this we could start with, like a feature that enables just a small surface of the API, maybe even a single struct since reviewing it all at once is going to be a lot harder, and the underlying payjoin-ffi crate keeps changing making rebases harder as the tip of this diverges.

the browser demo is fully working now

only supports v2
doesn't yet fully validate checks
limited options
@riverKanies
Copy link
Contributor Author

https://mutinynet.com/tx/f90380bdb2284a7586a386017177257d2454aab100f2a21d5ed2a6e3baf48f6e
demo complete. here's first payjoin with wasm bindings

I'll start looking at merge conflicts to rebase and work up a minimal smaller pr to start.
also quite a bit of cleanup, and this does not yet include full functionality, just happy path for v2 with normal defaults pretty much

Required enabling OhttpKeys constructor from bytes
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

Successfully merging this pull request may close these issues.

Support WASM with wasm_bindgen and conditional compilation

3 participants