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: implement Pairing API #3

Open
wants to merge 81 commits into
base: kdf
Choose a base branch
from
Open

feat: implement Pairing API #3

wants to merge 81 commits into from

Conversation

borngraced
Copy link
Member

@borngraced borngraced commented Sep 3, 2024

This PR implements the WalletConnect Pairing API, enabling secure communication between dApps and wallets. It manages pairing requests, responses, and lifecycle events (creating, deleting, extending, and pinging pairings).
Key features:

cargo run --example pairing --features="example"

Test overview:

  • Establishes WebSocket connection
  • Creates pairing with PairingClient
  • Handles pairing requests (delete, extend, ping)
  • Shuts down on Ctrl+C signal

The test demonstrates the full lifecycle of a WalletConnect pairing, from establishment to termination, using the pairing_api and relay_client crates.

https://specs.walletconnect.com/2.0/specs/clients/core/pairing/
https://specs.walletconnect.com/2.0/specs/clients/core/crypto/crypto-keys
https://specs.walletconnect.com/2.0/specs/clients/core/pairing/data-structures
https://specs.walletconnect.com/2.0/specs/clients/core/pairing/pairing-api

@borngraced borngraced self-assigned this Sep 3, 2024
Copy link
Collaborator

@shamardy shamardy left a comment

Choose a reason for hiding this comment

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

Huge work! First review iteration from my side.

wc_common/src/crypto.rs Show resolved Hide resolved
wc_common/src/crypto.rs Show resolved Hide resolved
pairing_api/src/pairing.rs Outdated Show resolved Hide resolved
pairing_api/src/pairing.rs Outdated Show resolved Hide resolved
pairing_api/src/pairing.rs Outdated Show resolved Hide resolved
pairing_api/src/pairing.rs Outdated Show resolved Hide resolved
pairing_api/src/pairing.rs Outdated Show resolved Hide resolved
pairing_api/src/pairing.rs Outdated Show resolved Hide resolved
pairing_api/src/pairing.rs Outdated Show resolved Hide resolved
Copy link
Collaborator

@shamardy shamardy left a comment

Choose a reason for hiding this comment

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

Next review iteration!

@@ -9,6 +9,7 @@ chrono = { version = "0.4", default-features = false, features = [
"clock",
] }
anyhow = "1.0.86"
dashmap = "6.1.0"
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't understand the need of using dashmap, we will not have that many pairings to need a new dep for high concurrent operations.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This has not been addressed yet.

Copy link
Member Author

Choose a reason for hiding this comment

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

done

pairing_api/src/pairing.rs Outdated Show resolved Hide resolved
pairing_api/src/pairing.rs Outdated Show resolved Hide resolved

/// Calculates and validates the current Unix timestamp
/// to use as a base for pairing expiry times.
fn calc_expiry(&self) -> Result<u64, PairingClientError> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The name here keeps confusing me, it returns current timestamp not expiry.

Copy link
Member Author

Choose a reason for hiding this comment

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

renamed to calc_expiry_timestamp as it's main task is to calculate and return expiry timestamp.

Copy link
Collaborator

Choose a reason for hiding this comment

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

But again, this calculates the current timestamp only, we use it later to add a duration to it to calculate expiry but what the function does is unrelated to expiry at all and can be used for other purposes if needed.

Copy link
Member Author

Choose a reason for hiding this comment

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

renamed.

pairing_api/src/pairing.rs Outdated Show resolved Hide resolved
pairing_api/src/pairing.rs Outdated Show resolved Hide resolved
pairing_api/src/uri.rs Show resolved Hide resolved
pairing_api/Cargo.toml Outdated Show resolved Hide resolved
Comment on lines 46 to 47
/// Pairing Delete error code.
const PAIRING_DELETE_ERROR_CODE: i64 = 6000;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Something we need to do when writing doc comments is not to add unnecessary ones, this is the same as the const name and not needed. If a comment doesn't explain something not obvious then it's not needed. For pub items we need doc comments, so we should try to write something that makes it clearer to the user of the sdk.


/// Calculates and validates the current Unix timestamp
/// to use as a base for pairing expiry times.
fn calc_expiry(&self) -> Result<u64, PairingClientError> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

But again, this calculates the current timestamp only, we use it later to add a duration to it to calculate expiry but what the function does is unrelated to expiry at all and can be used for other purposes if needed.

@laruh
Copy link
Member

laruh commented Nov 29, 2024

@borngraced ps signature tests started to fail

@laruh
Copy link
Member

laruh commented Nov 29, 2024

Btw noticed WalletConnectRs is actively using alloy with foundry(forge) in their project, a good example to learn from (as we should move to alloy in kdf, instead of using old web3 crate)

@borngraced
Copy link
Member Author

@borngraced ps signature tests started to fail

AFAIK, only CI is failing.. I will check ✔️

@laruh
Copy link
Member

laruh commented Nov 29, 2024

@borngraced ps signature tests started to fail

AFAIK, only CI is failing.. I will check ✔️

I have this locally too, run this command

cargo test --workspace --all-features

image

@laruh
Copy link
Member

laruh commented Nov 29, 2024

@borngraced

just need to add --broadcast flag in deploy_contract function (test_helpers.rs)

    let mut args = vec![
        "create",
        "--contracts=relay_rpc/contracts",
        contract_name,
        "--rpc-url",
        rpc_url.as_str(),
        "--private-key",
        &key_encoded,
        "--cache-path",
        &cache_folder,
        "--out",
        &out_folder,
        "--broadcast",
    ];

UPD: strange that Smith (author of the code) didnt add --broadcast flag (it submits the transaction to the blockchain specified by the --rpc-url argument), it is safe to add this flag as they use anvil.
anvil is foundry's built-in Ethereum development node, so the deployment transaction will be submitted to that local blockchain.

    #[tokio::test]
    async fn test_eip1271_pass() {
        let (_anvil, rpc_url, private_key) = spawn_anvil().await;
        let contract_address = deploy_contract(
            &rpc_url,
            &private_key,
            EIP1271_MOCK_CONTRACT,
            Some(&Address::from_private_key(&private_key).to_string()),
        )
        .await;
        // the rest of the code
    }

pub async fn spawn_anvil() -> (AnvilInstance, Url, SigningKey) {
    let anvil = Anvil::at(format_foundry_dir("bin/anvil")).spawn();
    let provider = anvil.endpoint().parse().unwrap();
    let private_key = anvil.keys().first().unwrap().clone();
    (
        anvil,
        provider,
        SigningKey::from_bytes(&private_key.to_bytes()).unwrap(),
    )
}

@borngraced
Copy link
Member Author

@borngraced

just need to add --broadcast flag in deploy_contract function (test_helpers.rs)

    let mut args = vec![
        "create",
        "--contracts=relay_rpc/contracts",
        contract_name,
        "--rpc-url",
        rpc_url.as_str(),
        "--private-key",
        &key_encoded,
        "--cache-path",
        &cache_folder,
        "--out",
        &out_folder,
        "--broadcast",
    ];

UPD: strange that Smith (author of the code) didnt add --broadcast flag (it submits the transaction to the blockchain specified by the --rpc-url argument), it is safe to add this flag as they use anvil. anvil is foundry's built-in Ethereum development node, so the deployment transaction will be submitted to that local blockchain.

    #[tokio::test]
    async fn test_eip1271_pass() {
        let (_anvil, rpc_url, private_key) = spawn_anvil().await;
        let contract_address = deploy_contract(
            &rpc_url,
            &private_key,
            EIP1271_MOCK_CONTRACT,
            Some(&Address::from_private_key(&private_key).to_string()),
        )
        .await;
        // the rest of the code
    }

pub async fn spawn_anvil() -> (AnvilInstance, Url, SigningKey) {
    let anvil = Anvil::at(format_foundry_dir("bin/anvil")).spawn();
    let provider = anvil.endpoint().parse().unwrap();
    let private_key = anvil.keys().first().unwrap().clone();
    (
        anvil,
        provider,
        SigningKey::from_bytes(&private_key.to_bytes()).unwrap(),
    )
}

I wonder how this has suddenly become a problem perhaps an update has happened somewhere in CI. fix anyways.. thanks

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.

4 participants