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

feat: create a simple Sign API example on top of the WS client #48

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

silvestrst-crypto
Copy link

@silvestrst-crypto silvestrst-crypto commented Oct 27, 2023

Description

This change adds Sign API framework, and a simple example client to demonstrate pairing and session creation capabilities.

This change introduces the following functionality:

  • Sign API payload serializable/deserializable data types
  • Payload encryption and decryption
  • Session Diffie-Hellman key derivation
  • Pairing URI parsing
  • Simple WS based client

Resolves #47

How Has This Been Tested?

  • Use example client to pair and establish the session with an example DApp:
    - Click on "Goerli" and then "connect"
    - In a new pop-up, click "New Pairing"
    - Copy the Pairing URI
    - In the terminal, cd path/to/WalletConnectRust
    - .../WalletConnectRust$ cargo run --example session "<copied URI>"
    - DApp should now display the session window
    - In the DApp click disconnect

image

  • Unittests (partial)

Due Diligence

  • Breaking change
  • Requires a documentation update
  • Requires a e2e/integration test update

TODO

  • Typed errors instead of unnamed anyhow errors
  • More unittests
  • Implement Core Pairing API. Not related to Sign API, but makes sense to add.
  • Add relevant information to README.md
  • Better documentation, code comments and function descriptions
  • crypto/session.rs refactor

Additional information

WCv2 uses layered approach. The relay protocol messages (currently only IRN, but there might be other in future), are used to carry the useful payload. In terms of this change the useful payload is Sign API messages.

Useful materials:
https://specs.walletconnect.com/2.0/specs/clients/core/pairing
https://specs.walletconnect.com/2.0/specs/clients/sign/session-proposal

https://specs.walletconnect.com/2.0/specs/servers/relay/relay-server-rpc
https://specs.walletconnect.com/2.0/specs/clients/sign/rpc-methods

@silvestrst-crypto silvestrst-crypto marked this pull request as draft October 27, 2023 09:31
sign_api/src/rpc.rs Outdated Show resolved Hide resolved
Comment on lines +1 to +2
//! The crate exports common types used when interacting with messages between
//! clients. This also includes communication over HTTP between relays.
Copy link
Author

Choose a reason for hiding this comment

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

Bad Copy/Paste, should be changed to an appropriate description.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this module copy-pasted from relay_rpc? I think we should somehow reuse the existing one

Copy link
Author

Choose a reason for hiding this comment

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

That is a good point. In fact the way I initially started working on this change, was copy paste the entire rpc.rs and then change bits and pieces that I need for sign_api.

I ran into some issues, and wasn't sure how to appropriate certain traits, errors, etc.. for my use-case.

In the end I decided it will be easier for me to loosely base it on the relay rpc.rs, and see if some common functionality can be refactored post fact after this change lands in the follow-ups. It should be easier, rather than doing two things at once - will probably result in some code, files shifting around.

Comment on lines +60 to +69
pub fn validate(&self) -> Result<(), ValidationError> {
match self {
Self::Request(request) => request.validate(),
Self::Response(response) => response.validate(),
}
}
Copy link
Author

Choose a reason for hiding this comment

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

Should add more request/response specific validations.

@silvestrst-crypto silvestrst-crypto force-pushed the silvestrs/sign-api-latest branch from 968a167 to 0a1df16 Compare November 2, 2023 17:03
@silvestrst-crypto silvestrst-crypto marked this pull request as ready for review November 2, 2023 17:09
@silvestrst-crypto
Copy link
Author

@heilhead , apologies for names dropping! The repository doesn't look very active, so this is my attempt to get some attention to the PR. Would you please be able to give this change a quick review, or maybe assign someone? Thanks!

@heilhead
Copy link
Collaborator

heilhead commented Nov 7, 2023

Hi @silvestrst-crypto, thanks for the PR! Sorry we didn't see it earlier. We'll try to review it in the next few days hopefully.

@silvestrst-crypto
Copy link
Author

gentle ping

@heilhead
Copy link
Collaborator

@silvestrst-crypto Hey! Apologies for not getting back with the review, as I'm on holidays right now.

@xDarksome @farazdagi @chris13524 Can one of you guys please have a look at this?

@arein
Copy link
Contributor

arein commented Nov 27, 2023

@silvestrst-crypto can you please also share your use case of how you're intending of using this? 🙏

Copy link
Contributor

@farazdagi farazdagi left a comment

Choose a reason for hiding this comment

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

Absolutely marvellous work, thank you!
I will do another review pass today -- but overall looks really great. I had some minor comments.

NB: Sorry for keeping you waiting for review for so long, will make sure we progress swiftly from this point on :)

sign_api/src/crypto/payload.rs Outdated Show resolved Hide resolved
},
})
}
_ => anyhow::bail!("Invalid envelope type: {}", envelope_type),
Copy link
Contributor

Choose a reason for hiding this comment

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

Generally we use typed errors and avoid using anyhow::bail. For instance, relay_client/src/error.rs is the way we typically define errors, so for consistency's sake please consider defining Sign API error types.

NB: More or less, error types in pairing_uri is what I am after here.

Copy link
Author

Choose a reason for hiding this comment

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

Done, here and in all other sign_api submodules.

sign_api/src/pairing_uri.rs Outdated Show resolved Hide resolved
sign_api/src/rpc/params/session_event.rs Outdated Show resolved Hide resolved
sign_api/src/rpc/params/session_request.rs Outdated Show resolved Hide resolved
pub struct SessionSettleRequest {
pub relay: Relay,
pub controller: Controller,
pub namespaces: SettleNamespaces,
Copy link
Contributor

Choose a reason for hiding this comment

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

The optional specialNamespaces are omitted here. Not a big deal though.

sign_api/src/rpc/params/session_settle.rs Outdated Show resolved Hide resolved
@farazdagi
Copy link
Contributor

From your todo list, I'd consider typed errors + Readme update + probably a bit more unit tests for this PR. Anything else, let's tackle as separate PRs.

image

Copy link
Contributor

@xDarksome xDarksome left a comment

Choose a reason for hiding this comment

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

Putting my 5 cents
I started to review, but then got distracted.

impl Debug for SessionKey {
/// Custom debug to hide the symmetrical key.
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WalletConnectUrl")
Copy link
Contributor

Choose a reason for hiding this comment

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

I presume this is a refactoring artifact 😄
Also, consider using https://crates.io/crates/secrecy

Copy link
Author

Choose a reason for hiding this comment

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

Indeed, bad copy paste from pairing_uri.rs.

That's a good point, I will look into that crate, haven't yet one so.

url::Url,
};

lazy_static! {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think lazy_static is somewhat deprecated in favor of once_cell::Lazy

Copy link
Author

Choose a reason for hiding this comment

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

Moved inside parse_topic_and_version. This function will not be called to often, so "caching" the regex it is not that important.

Done.

Comment on lines +1 to +2
//! The crate exports common types used when interacting with messages between
//! clients. This also includes communication over HTTP between relays.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this module copy-pasted from relay_rpc? I think we should somehow reuse the existing one

@silvestrst-crypto
Copy link
Author

Thank you guys for your reviews! I will hopefully aim to go through the comments properly tomorrow and fix them up.

@silvestrst-crypto
Copy link
Author

silvestrst-crypto commented Nov 28, 2023

@silvestrst-crypto can you please also share your use case of how you're intending of using this? 🙏

We have an internal Rust project, where we are planning on using WalletConnect v2 to do DeFI operations, which is the main reason for tackling the Sign API at this point 🙂

@silvestrst-crypto silvestrst-crypto force-pushed the silvestrs/sign-api-latest branch from 0a1df16 to cd232c6 Compare November 29, 2023 16:48
Copy link
Author

@silvestrst-crypto silvestrst-crypto left a comment

Choose a reason for hiding this comment

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

Thank you guys for your reviews!

This is the first pass where I have tackled some of the review comments, I will handle the rest in next few passes.

Summary:

  • Switches to typed errors rather than anyhow::Error
  • Changed Namespace memebrs from Vec to BTreeSet
  • Fixed-up some naming comments in payload.rs
  • Noticed that I had logic errors in the payload.rs when parsing decoded data (was wrong in a way that it still worked). Fixed it now.

I have also realised that Namespace needs more validation logic in accordance to the spec.

When you got through comments, could you guys only resolve those that you are happy with, but keep open those that you think are still "not there yet". This should make the review process a bit easier for both parties. Thanks!

sign_api/src/crypto/payload.rs Outdated Show resolved Hide resolved
sign_api/src/rpc/params/session_settle.rs Outdated Show resolved Hide resolved
},
})
}
_ => anyhow::bail!("Invalid envelope type: {}", envelope_type),
Copy link
Author

Choose a reason for hiding this comment

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

Done, here and in all other sign_api submodules.

impl Debug for SessionKey {
/// Custom debug to hide the symmetrical key.
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WalletConnectUrl")
Copy link
Author

Choose a reason for hiding this comment

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

Indeed, bad copy paste from pairing_uri.rs.

That's a good point, I will look into that crate, haven't yet one so.

Comment on lines +1 to +2
//! The crate exports common types used when interacting with messages between
//! clients. This also includes communication over HTTP between relays.
Copy link
Author

Choose a reason for hiding this comment

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

That is a good point. In fact the way I initially started working on this change, was copy paste the entire rpc.rs and then change bits and pieces that I need for sign_api.

I ran into some issues, and wasn't sure how to appropriate certain traits, errors, etc.. for my use-case.

In the end I decided it will be easier for me to loosely base it on the relay rpc.rs, and see if some common functionality can be refactored post fact after this change lands in the follow-ups. It should be easier, rather than doing two things at once - will probably result in some code, files shifting around.

sign_api/src/rpc/params/shared_types.rs Outdated Show resolved Hide resolved
@silvestrst-crypto silvestrst-crypto force-pushed the silvestrs/sign-api-latest branch from cd232c6 to 7296dc8 Compare December 5, 2023 18:03
Copy link
Author

@silvestrst-crypto silvestrst-crypto left a comment

Choose a reason for hiding this comment

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

This is a second part of the review comments addressing:

  • Fixed SessionRequestRequest to match the spec (was missing an optional field, and params were changed to serde_json::Value)
  • Fixed SessionEventRequest to match the spec (data was changed to serde_json::Value)
  • Simple serealize/deserialize unittests were added for the above two bullet-points
  • Some other minor comment were fixed

Will try to address the remaining comments by the end of the week.

sign_api/src/pairing_uri.rs Outdated Show resolved Hide resolved
url::Url,
};

lazy_static! {
Copy link
Author

Choose a reason for hiding this comment

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

Moved inside parse_topic_and_version. This function will not be called to often, so "caching" the regex it is not that important.

Done.

sign_api/src/rpc.rs Outdated Show resolved Hide resolved
sign_api/src/rpc/params/session_event.rs Outdated Show resolved Hide resolved
sign_api/src/rpc/params/session_request.rs Outdated Show resolved Hide resolved
sign_api/src/rpc/params/session_settle.rs Outdated Show resolved Hide resolved
examples/session.rs Outdated Show resolved Hide resolved
Copy link
Member

@chris13524 chris13524 left a comment

Choose a reason for hiding this comment

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

First of all, thanks for the contribution! We really appreciate it 🥇

Second, can you add a section to the root README for the sign_api crate? We also need to add a warning to that; the Rust team doesn't work on the client SDKs so the amount of rigor here is far less than e.g. our JavaScript, Kotlin, or Swift SDKs have gone through. Those SDKs are also continually improved with new features and fixes, so the Rust version will likely not be getting any of these updates unless a community member contributes it. This could change in the future if there is sufficient interest in the Rust SDK, but for now we cannot dedicate resources to keep this maintained. Can you add a note to the readme like:

Warning: this Rust Sign API SDK is community-maintained and may be lacking features and stability or security fixes that other versions of the Sign API SDK receive. We strongly recommend using the JavaScript or other Sign API SDKs instead.

@silvestrst-crypto
Copy link
Author

First of all, thanks for the contribution! We really appreciate it 🥇

Second, can you add a section to the root README for the sign_api crate? We also need to add a warning to that; the Rust team doesn't work on the client SDKs so the amount of rigor here is far less than e.g. our JavaScript, Kotlin, or Swift SDKs have gone through. Those SDKs are also continually improved with new features and fixes, so the Rust version will likely not be getting any of these updates unless a community member contributes it. This could change in the future if there is sufficient interest in the Rust SDK, but for now we cannot dedicate resources to keep this maintained. Can you add a note to the readme like:

Warning: this Rust Sign API SDK is community-maintained and may be lacking features and stability or security fixes that other versions of the Sign API SDK receive. We strongly recommend using the JavaScript or other Sign API SDKs instead.

Good idea, I understand, thanks!

@silvestrst-crypto silvestrst-crypto force-pushed the silvestrs/sign-api-latest branch from 7296dc8 to 04b51d5 Compare December 19, 2023 16:43
@silvestrst-crypto
Copy link
Author

In the latest push I have:

  • added simple serialization/deserialization unittests for the parameters
  • done significant ProposeNamespaces refactor and added unittests
  • renamed Namespaces to ProposeNamespaces and moved them together with SettleNamespaces under their own sub-foleders in shred_types
  • Fixed up TTL for session_request, it's unix_timestamp_in_secs() + TTL

@silvestrst-crypto silvestrst-crypto force-pushed the silvestrs/sign-api-latest branch from 04b51d5 to fc737a0 Compare December 19, 2023 18:42
@silvestrst-crypto
Copy link
Author

In the latest push:

  • I have moved session example into sign_api crate

This change adds WalletConnect v2 Sign API, as per:
https://specs.walletconnect.com/2.0/specs/clients/sign/

Please note that although the specification is fairly thorough, there
are some inconsistencies. This implementation is derived from specs,
analyzing ws traffic in browsers devtools, as well as the original
WalletConnect JavaScript client at:
https://github.com/WalletConnect/walletconnect-monorepo

Design decisions:

Modularity:
- RPC and crypto modules are not dependent on each other, so client
  implementations don't have to use their own crypto implementation.

Closes: reown-com#47
This client implements pairing and session flows:
https://specs.walletconnect.com/2.0/specs/clients/core/pairing
https://specs.walletconnect.com/2.0/specs/clients/sign/session-proposal

Supported actions:
- pairing
- session establishment
- session delete
- ping

This example could be expanded to handle multiple sessions.

Caution:
The purpose of this example is demonstration of core Sign API
functionality. However, it shouldn't be used in production, as might
exhibit some race conditions such as with session deletion, etc...
@silvestrst-crypto silvestrst-crypto force-pushed the silvestrs/sign-api-latest branch from 5046727 to 489e2e3 Compare December 20, 2023 06:54
@silvestrst-crypto
Copy link
Author

In the latest push:

  • Added README.md to the sign_api crate
  • Rebased my changes on upstream main

@nopestack
Copy link

Hi @silvestrst-crypto, thank you for your hard work on this PR 💪 . I was wondering if you had made any progress addressing the feedback from my colleagues and if you'd like to continue working on this issue?

@silvestrst-crypto
Copy link
Author

Hi @nopestack , lately I am quite busy, so put it on hold, but if anyone is planning on using it, I can slowly start moving it forward in spare time. Thanks!

@dougEfresh
Copy link

@nopestack I think it is best to move this code to an isolated repo, and depend on wallet-connect-rust .
I think this would speed up development and I'm willing to help. Besides, I do not think the maintainers have interest in merging this.

@nopestack nopestack marked this pull request as draft July 31, 2024 20:00
@nopestack
Copy link

Marking this as draft in the meantime as work is paused and we cannot prioritize it at the moment. Worth revisiting it later @xDarksome @chris13524

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.

Add Sign API
9 participants