From c2d94276dd80ee4db75a09bb27131608eb28de33 Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Tue, 7 Apr 2026 17:08:53 +0200 Subject: [PATCH 01/14] Register recovery agent from the signup service --- .../src/issuers/pop_backend_client.rs | 36 +++++++++++++ .../src/issuers/recovery_bindings_manager.rs | 51 ++++++++++++++++--- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/walletkit-core/src/issuers/pop_backend_client.rs b/walletkit-core/src/issuers/pop_backend_client.rs index 8e59f585..6c48df87 100644 --- a/walletkit-core/src/issuers/pop_backend_client.rs +++ b/walletkit-core/src/issuers/pop_backend_client.rs @@ -13,6 +13,13 @@ pub struct ManageRecoveryBindingRequest { /// The authenticator's leaf index in the World ID Merkle tree. #[serde(rename = "leafIndex")] pub leaf_index: u64, + /// The signature of the recovery agent update. + pub signature: String, + /// The nonce of the recovery agent update. + pub nonce: String, + /// The checksummed hex address of the new recovery agent (e.g. `"0x1234…"`). + #[serde(rename = "newRecoveryAgent")] + pub new_recovery_agent: String, } #[derive(Deserialize)] @@ -216,9 +223,13 @@ mod tests { let mut server = mockito::Server::new_async().await; let url = server.url(); + let new_recovery_agent = "0x1234567890abcdef".to_string(); let request = ManageRecoveryBindingRequest { sub: "test-sub-123".to_string(), leaf_index: 42, + signature: "0x1234567890abcdef".to_string(), + nonce: "0x1234567890abcdef1".to_string(), + new_recovery_agent: new_recovery_agent.clone(), }; let mock = server @@ -226,6 +237,9 @@ mod tests { .match_body(mockito::Matcher::Json(serde_json::json!({ "sub": "test-sub-123", "leafIndex": 42, + "signature": "0x1234567890abcdef", + "nonce": "0x1234567890abcdef1", + "newRecoveryAgent": "0x1234567890abcdef", }))) .match_header("X-Auth-Signature", "security_token") .match_header("X-Auth-Challenge", "challenge") @@ -254,9 +268,13 @@ mod tests { let mut server = mockito::Server::new_async().await; let url = server.url(); + let new_recovery_agent = "0x1234567890abcdef".to_string(); let request = ManageRecoveryBindingRequest { sub: "test-sub-123".to_string(), leaf_index: 42, + signature: "0x1234567890abcdef".to_string(), + nonce: "0x1234567890abcdef1".to_string(), + new_recovery_agent: new_recovery_agent.clone(), }; let mock = server @@ -264,6 +282,9 @@ mod tests { .match_body(mockito::Matcher::Json(serde_json::json!({ "sub": "test-sub-123", "leafIndex": 42, + "signature": "0x1234567890abcdef", + "nonce": "0x1234567890abcdef1", + "newRecoveryAgent": "0x1234567890abcdef", }))) .match_header("X-Auth-Signature", "security_token") .match_header("X-Auth-Challenge", "challenge") @@ -300,6 +321,10 @@ mod tests { let request = ManageRecoveryBindingRequest { sub: "test-sub-123".to_string(), leaf_index: 42, + signature: "0x1234567890abcdef".to_string(), + nonce: "0x1234567890abcdef1".to_string(), + new_recovery_agent: "0x0000000000000000000000000000000000000000" + .to_string(), }; let mock = server @@ -307,6 +332,9 @@ mod tests { .match_body(mockito::Matcher::Json(serde_json::json!({ "sub": "test-sub-123", "leafIndex": 42, + "signature": "0x1234567890abcdef", + "nonce": "0x1234567890abcdef1", + "newRecoveryAgent": "0x0000000000000000000000000000000000000000", }))) .match_header("X-Auth-Signature", "security_token") .match_header("X-Auth-Challenge", "challenge") @@ -335,9 +363,14 @@ mod tests { let mut server = mockito::Server::new_async().await; let url = server.url(); + let new_recovery_agent = + "0x0000000000000000000000000000000000000000".to_string(); let request = ManageRecoveryBindingRequest { sub: "test-sub-123".to_string(), leaf_index: 42, + signature: "0x1234567890abcdef".to_string(), + nonce: "0x1234567890abcdef1".to_string(), + new_recovery_agent: new_recovery_agent.clone(), }; let mock = server @@ -345,6 +378,9 @@ mod tests { .match_body(mockito::Matcher::Json(serde_json::json!({ "sub": "test-sub-123", "leafIndex": 42, + "signature": "0x1234567890abcdef", + "nonce": "0x1234567890abcdef1", + "newRecoveryAgent": "0x0000000000000000000000000000000000000000", }))) .match_header("X-Auth-Signature", "security_token") .match_header("X-Auth-Challenge", "challenge") diff --git a/walletkit-core/src/issuers/recovery_bindings_manager.rs b/walletkit-core/src/issuers/recovery_bindings_manager.rs index 9e240efe..76846401 100644 --- a/walletkit-core/src/issuers/recovery_bindings_manager.rs +++ b/walletkit-core/src/issuers/recovery_bindings_manager.rs @@ -18,7 +18,8 @@ use crate::issuers::pop_backend_client::ManageRecoveryBindingRequest; use crate::issuers::PopBackendClient; use crate::Environment; use alloy_primitives::keccak256; - +use std::string::String; +const ZERO_ADDRESS: &str = "0x0000000000000000000000000000000000000000"; /// Client for registering and unregistering recovery agents with the `PoP` backend. /// /// Each instance is bound to a specific [`Environment`] (staging or production), @@ -66,6 +67,7 @@ impl RecoveryBindingManager { /// * `authenticator` — The authenticator whose signing key authorizes the request. /// * `leaf_index` — The authenticator's leaf index in the World ID Merkle tree. /// * `sub` — Hex-encoded subject identifier of the recovery agent to register. + /// * `new_recovery_agent` — The checksummed hex address of the new recovery agent (e.g. `"0x1234…"`). /// /// # Errors /// @@ -76,9 +78,19 @@ impl RecoveryBindingManager { authenticator: &Authenticator, leaf_index: u64, sub: String, + new_recovery_agent: String, ) -> Result<(), WalletKitError> { let challenge = self.pop_backend_client.get_challenge().await?; - let request = ManageRecoveryBindingRequest { sub, leaf_index }; + let sig_recovery_update = authenticator + .danger_sign_initiate_recovery_agent_update(new_recovery_agent.clone()) + .await?; + let request = ManageRecoveryBindingRequest { + sub, + leaf_index, + signature: format!("0x{}", hex::encode(sig_recovery_update.signature)), + nonce: sig_recovery_update.nonce.to_string(), + new_recovery_agent, + }; let security_token = Self::generate_recovery_agent_security_token( authenticator, &request, @@ -109,7 +121,17 @@ impl RecoveryBindingManager { leaf_index: u64, sub: String, ) -> Result<(), WalletKitError> { - let request = ManageRecoveryBindingRequest { sub, leaf_index }; + let new_recovery_agent = ZERO_ADDRESS.to_string(); + let sig_recovery_update = authenticator + .danger_sign_initiate_recovery_agent_update(new_recovery_agent.clone()) + .await?; + let request = ManageRecoveryBindingRequest { + sub, + leaf_index, + signature: format!("0x{}", hex::encode(sig_recovery_update.signature)), + nonce: sig_recovery_update.nonce.to_string(), + new_recovery_agent, + }; let challenge = self.pop_backend_client.get_challenge().await?; let security_token = Self::generate_recovery_agent_security_token( authenticator, @@ -224,6 +246,8 @@ mod tests { // Mock the recovery binding registration endpoint let url_path = "/api/v1/recovery-binding".to_string(); + let new_recovery_agent = + "0x1000000000000000000000000000000000000000".to_string(); let mock = pop_api_server .mock("POST", url_path.as_str()) @@ -232,9 +256,11 @@ mod tests { mockito::Matcher::Regex(".*".to_string()), ) .match_header("X-Auth-Challenge", challenge.as_str()) - .match_body(mockito::Matcher::Json(serde_json::json!({ + .match_body(mockito::Matcher::PartialJson(serde_json::json!({ "sub": sub.as_str(), "leafIndex": leaf_index, + "newRecoveryAgent": new_recovery_agent.as_str(), + }))) .with_status(201) .with_body("{}") @@ -254,7 +280,12 @@ mod tests { create_test_authenticator(&private_key_bytes, rpc_url).await; let result = recovery_binding_manager - .bind_recovery_agent(&authenticator, leaf_index, sub.clone()) + .bind_recovery_agent( + &authenticator, + leaf_index, + sub.clone(), + new_recovery_agent.clone(), + ) .await; assert!( result.is_ok(), @@ -285,10 +316,16 @@ mod tests { .unwrap(); log::info!("message_bytes: {:?}", hex::encode(message_bytes.clone())); assert_eq!(hex::encode(message_bytes.clone()), "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2000000000000002aabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"); - + let signature = "0x01".to_string(); + let nonce = "0x02".to_string(); + let new_recovery_agent = + "0x1000000000000000000000000000000000000000".to_string(); let request = ManageRecoveryBindingRequest { sub: sub.clone(), leaf_index, + signature: signature.clone(), + nonce: nonce.clone(), + new_recovery_agent: new_recovery_agent.clone(), }; let (mock_eth_server, eth_mock) = create_mock_eth_server().await; let rpc_url = mock_eth_server.url(); @@ -354,6 +391,8 @@ mod tests { }) .to_string(), ) + .expect_at_least(1) + .expect_at_most(2) .create_async() .await; (mock_eth_server, mock) From ede2a446a56ffc63ced1b673bc9b40faa0b40442 Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Tue, 7 Apr 2026 18:21:32 +0200 Subject: [PATCH 02/14] Rename newRecoveryAgent to recoveryAgent --- .../src/issuers/pop_backend_client.rs | 30 +++++++++---------- .../src/issuers/recovery_bindings_manager.rs | 20 ++++++------- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/walletkit-core/src/issuers/pop_backend_client.rs b/walletkit-core/src/issuers/pop_backend_client.rs index 6c48df87..18847150 100644 --- a/walletkit-core/src/issuers/pop_backend_client.rs +++ b/walletkit-core/src/issuers/pop_backend_client.rs @@ -17,9 +17,9 @@ pub struct ManageRecoveryBindingRequest { pub signature: String, /// The nonce of the recovery agent update. pub nonce: String, - /// The checksummed hex address of the new recovery agent (e.g. `"0x1234…"`). - #[serde(rename = "newRecoveryAgent")] - pub new_recovery_agent: String, + /// The checksummed hex address of the recovery agent (e.g. `"0x1234…"`). + #[serde(rename = "recoveryAgent")] + pub recovery_agent: String, } #[derive(Deserialize)] @@ -223,13 +223,13 @@ mod tests { let mut server = mockito::Server::new_async().await; let url = server.url(); - let new_recovery_agent = "0x1234567890abcdef".to_string(); + let recovery_agent = "0x1234567890abcdef".to_string(); let request = ManageRecoveryBindingRequest { sub: "test-sub-123".to_string(), leaf_index: 42, signature: "0x1234567890abcdef".to_string(), nonce: "0x1234567890abcdef1".to_string(), - new_recovery_agent: new_recovery_agent.clone(), + recovery_agent: recovery_agent.clone(), }; let mock = server @@ -239,7 +239,7 @@ mod tests { "leafIndex": 42, "signature": "0x1234567890abcdef", "nonce": "0x1234567890abcdef1", - "newRecoveryAgent": "0x1234567890abcdef", + "recoveryAgent": "0x1234567890abcdef", }))) .match_header("X-Auth-Signature", "security_token") .match_header("X-Auth-Challenge", "challenge") @@ -268,13 +268,13 @@ mod tests { let mut server = mockito::Server::new_async().await; let url = server.url(); - let new_recovery_agent = "0x1234567890abcdef".to_string(); + let recovery_agent = "0x1234567890abcdef".to_string(); let request = ManageRecoveryBindingRequest { sub: "test-sub-123".to_string(), leaf_index: 42, signature: "0x1234567890abcdef".to_string(), nonce: "0x1234567890abcdef1".to_string(), - new_recovery_agent: new_recovery_agent.clone(), + recovery_agent: recovery_agent.clone(), }; let mock = server @@ -284,7 +284,7 @@ mod tests { "leafIndex": 42, "signature": "0x1234567890abcdef", "nonce": "0x1234567890abcdef1", - "newRecoveryAgent": "0x1234567890abcdef", + "recoveryAgent": "0x1234567890abcdef", }))) .match_header("X-Auth-Signature", "security_token") .match_header("X-Auth-Challenge", "challenge") @@ -323,8 +323,7 @@ mod tests { leaf_index: 42, signature: "0x1234567890abcdef".to_string(), nonce: "0x1234567890abcdef1".to_string(), - new_recovery_agent: "0x0000000000000000000000000000000000000000" - .to_string(), + recovery_agent: "0x0000000000000000000000000000000000000000".to_string(), }; let mock = server @@ -334,7 +333,7 @@ mod tests { "leafIndex": 42, "signature": "0x1234567890abcdef", "nonce": "0x1234567890abcdef1", - "newRecoveryAgent": "0x0000000000000000000000000000000000000000", + "recoveryAgent": "0x0000000000000000000000000000000000000000", }))) .match_header("X-Auth-Signature", "security_token") .match_header("X-Auth-Challenge", "challenge") @@ -363,14 +362,13 @@ mod tests { let mut server = mockito::Server::new_async().await; let url = server.url(); - let new_recovery_agent = - "0x0000000000000000000000000000000000000000".to_string(); + let recovery_agent = "0x0000000000000000000000000000000000000000".to_string(); let request = ManageRecoveryBindingRequest { sub: "test-sub-123".to_string(), leaf_index: 42, signature: "0x1234567890abcdef".to_string(), nonce: "0x1234567890abcdef1".to_string(), - new_recovery_agent: new_recovery_agent.clone(), + recovery_agent: recovery_agent.clone(), }; let mock = server @@ -380,7 +378,7 @@ mod tests { "leafIndex": 42, "signature": "0x1234567890abcdef", "nonce": "0x1234567890abcdef1", - "newRecoveryAgent": "0x0000000000000000000000000000000000000000", + "recoveryAgent": "0x0000000000000000000000000000000000000000", }))) .match_header("X-Auth-Signature", "security_token") .match_header("X-Auth-Challenge", "challenge") diff --git a/walletkit-core/src/issuers/recovery_bindings_manager.rs b/walletkit-core/src/issuers/recovery_bindings_manager.rs index 76846401..ee8b535b 100644 --- a/walletkit-core/src/issuers/recovery_bindings_manager.rs +++ b/walletkit-core/src/issuers/recovery_bindings_manager.rs @@ -89,7 +89,7 @@ impl RecoveryBindingManager { leaf_index, signature: format!("0x{}", hex::encode(sig_recovery_update.signature)), nonce: sig_recovery_update.nonce.to_string(), - new_recovery_agent, + recovery_agent: new_recovery_agent.clone(), }; let security_token = Self::generate_recovery_agent_security_token( authenticator, @@ -121,16 +121,16 @@ impl RecoveryBindingManager { leaf_index: u64, sub: String, ) -> Result<(), WalletKitError> { - let new_recovery_agent = ZERO_ADDRESS.to_string(); + let recovery_agent = ZERO_ADDRESS.to_string(); let sig_recovery_update = authenticator - .danger_sign_initiate_recovery_agent_update(new_recovery_agent.clone()) + .danger_sign_initiate_recovery_agent_update(recovery_agent.clone()) .await?; let request = ManageRecoveryBindingRequest { sub, leaf_index, signature: format!("0x{}", hex::encode(sig_recovery_update.signature)), nonce: sig_recovery_update.nonce.to_string(), - new_recovery_agent, + recovery_agent: recovery_agent.clone(), }; let challenge = self.pop_backend_client.get_challenge().await?; let security_token = Self::generate_recovery_agent_security_token( @@ -246,8 +246,7 @@ mod tests { // Mock the recovery binding registration endpoint let url_path = "/api/v1/recovery-binding".to_string(); - let new_recovery_agent = - "0x1000000000000000000000000000000000000000".to_string(); + let recovery_agent = "0x1000000000000000000000000000000000000000".to_string(); let mock = pop_api_server .mock("POST", url_path.as_str()) @@ -259,7 +258,7 @@ mod tests { .match_body(mockito::Matcher::PartialJson(serde_json::json!({ "sub": sub.as_str(), "leafIndex": leaf_index, - "newRecoveryAgent": new_recovery_agent.as_str(), + "recoveryAgent": recovery_agent.as_str(), }))) .with_status(201) @@ -284,7 +283,7 @@ mod tests { &authenticator, leaf_index, sub.clone(), - new_recovery_agent.clone(), + recovery_agent.clone(), ) .await; assert!( @@ -318,14 +317,13 @@ mod tests { assert_eq!(hex::encode(message_bytes.clone()), "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2000000000000002aabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"); let signature = "0x01".to_string(); let nonce = "0x02".to_string(); - let new_recovery_agent = - "0x1000000000000000000000000000000000000000".to_string(); + let recovery_agent = "0x1000000000000000000000000000000000000000".to_string(); let request = ManageRecoveryBindingRequest { sub: sub.clone(), leaf_index, signature: signature.clone(), nonce: nonce.clone(), - new_recovery_agent: new_recovery_agent.clone(), + recovery_agent: recovery_agent.clone(), }; let (mock_eth_server, eth_mock) = create_mock_eth_server().await; let rpc_url = mock_eth_server.url(); From d40893d6b79b8adbf660a2cc18f0257550b06f05 Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Wed, 8 Apr 2026 10:46:51 +0200 Subject: [PATCH 03/14] Add register recovery binding command --- walletkit-cli/src/commands/mod.rs | 12 ++++- .../src/commands/recovery_binding.rs | 49 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 walletkit-cli/src/commands/recovery_binding.rs diff --git a/walletkit-cli/src/commands/mod.rs b/walletkit-cli/src/commands/mod.rs index 81c7461b..c1f6e28f 100644 --- a/walletkit-cli/src/commands/mod.rs +++ b/walletkit-cli/src/commands/mod.rs @@ -4,14 +4,15 @@ mod auth; mod credential; mod proof; mod recovery_agent; +mod recovery_binding; mod wallet; - use std::path::PathBuf; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; use clap::{Parser, Subcommand}; use eyre::WrapErr as _; + use walletkit_core::storage::{cache_embedded_groth16_material, CredentialStore}; use walletkit_core::Authenticator; @@ -104,6 +105,12 @@ pub enum Command { #[command(subcommand)] action: recovery_agent::RecoveryAgentCommand, }, + /// Recovery binding management. + #[command(name = "recovery-binding")] + RecoveryBinding { + #[command(subcommand)] + action: recovery_binding::RecoveryBindingCommand, + }, } /// Resolves the wallet root directory, defaulting to `~/.walletkit`. @@ -240,5 +247,8 @@ pub async fn run(cli: Cli) -> eyre::Result<()> { Command::Credential { action } => credential::run(&cli, action).await, Command::Proof { action } => proof::run(&cli, action).await, Command::RecoveryAgent { action } => recovery_agent::run(&cli, action).await, + Command::RecoveryBinding { action } => { + recovery_binding::run(&cli, action).await + } } } diff --git a/walletkit-cli/src/commands/recovery_binding.rs b/walletkit-cli/src/commands/recovery_binding.rs new file mode 100644 index 00000000..1b916b32 --- /dev/null +++ b/walletkit-cli/src/commands/recovery_binding.rs @@ -0,0 +1,49 @@ +//! `walletkit recovery-agent` subcommands — recovery agent management. + +use clap::Subcommand; + +use super::{init_authenticator, Cli}; +use walletkit_core::issuers::RecoveryBindingManager; +use walletkit_core::Environment; + +#[derive(Subcommand)] +pub enum RecoveryBindingCommand { + /// Register bindings for a recovery agent. + RegisterBindings { + /// Checksummed hex address of the recovery agent (e.g. "0x1234…"). + sub: String, + }, + UnregisterBindings { + sub: String, + }, +} + +pub async fn run(cli: &Cli, action: &RecoveryBindingCommand) -> eyre::Result<()> { + let (authenticator, _store) = init_authenticator(cli).await?; + let leaf_index = authenticator.leaf_index(); + + match action { + RecoveryBindingCommand::RegisterBindings { sub } => { + let recovery_agent_address = + Environment::Staging.poh_recovery_agent_address(); + let recovery_binding_manager = + RecoveryBindingManager::new(&Environment::Staging).unwrap(); + recovery_binding_manager + .bind_recovery_agent( + &authenticator, + leaf_index, + sub.clone(), + recovery_agent_address.clone(), + ) + .await?; + } + RecoveryBindingCommand::UnregisterBindings { sub } => { + let recovery_binding_manager = + RecoveryBindingManager::new(&Environment::Staging).unwrap(); + recovery_binding_manager + .unbind_recovery_agent(&authenticator, leaf_index, sub.clone()) + .await?; + } + } + Ok(()) +} From 179ef399d7f23c95fb25fdf4a6bc632fd6be4fb3 Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Wed, 8 Apr 2026 11:09:33 +0200 Subject: [PATCH 04/14] Add sub and leaf index params --- walletkit-cli/src/commands/mod.rs | 3 +- .../src/commands/recovery_binding.rs | 28 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/walletkit-cli/src/commands/mod.rs b/walletkit-cli/src/commands/mod.rs index c1f6e28f..85dc8a7c 100644 --- a/walletkit-cli/src/commands/mod.rs +++ b/walletkit-cli/src/commands/mod.rs @@ -248,7 +248,8 @@ pub async fn run(cli: Cli) -> eyre::Result<()> { Command::Proof { action } => proof::run(&cli, action).await, Command::RecoveryAgent { action } => recovery_agent::run(&cli, action).await, Command::RecoveryBinding { action } => { - recovery_binding::run(&cli, action).await + let environment = resolve_environment(&cli)?; + recovery_binding::run(&cli, action, &environment).await } } } diff --git a/walletkit-cli/src/commands/recovery_binding.rs b/walletkit-cli/src/commands/recovery_binding.rs index 1b916b32..c2b0464a 100644 --- a/walletkit-cli/src/commands/recovery_binding.rs +++ b/walletkit-cli/src/commands/recovery_binding.rs @@ -10,38 +10,36 @@ use walletkit_core::Environment; pub enum RecoveryBindingCommand { /// Register bindings for a recovery agent. RegisterBindings { + leaf_index: u64, /// Checksummed hex address of the recovery agent (e.g. "0x1234…"). sub: String, }, UnregisterBindings { + leaf_index: u64, sub: String, }, } -pub async fn run(cli: &Cli, action: &RecoveryBindingCommand) -> eyre::Result<()> { +pub async fn run( + cli: &Cli, + action: &RecoveryBindingCommand, + environment: &Environment, +) -> eyre::Result<()> { let (authenticator, _store) = init_authenticator(cli).await?; - let leaf_index = authenticator.leaf_index(); match action { - RecoveryBindingCommand::RegisterBindings { sub } => { - let recovery_agent_address = - Environment::Staging.poh_recovery_agent_address(); + RecoveryBindingCommand::RegisterBindings { leaf_index, sub } => { let recovery_binding_manager = - RecoveryBindingManager::new(&Environment::Staging).unwrap(); + RecoveryBindingManager::new(environment).unwrap(); recovery_binding_manager - .bind_recovery_agent( - &authenticator, - leaf_index, - sub.clone(), - recovery_agent_address.clone(), - ) + .bind_recovery_agent(&authenticator, leaf_index.clone(), sub.clone()) .await?; } - RecoveryBindingCommand::UnregisterBindings { sub } => { + RecoveryBindingCommand::UnregisterBindings { leaf_index, sub } => { let recovery_binding_manager = - RecoveryBindingManager::new(&Environment::Staging).unwrap(); + RecoveryBindingManager::new(environment).unwrap(); recovery_binding_manager - .unbind_recovery_agent(&authenticator, leaf_index, sub.clone()) + .unbind_recovery_agent(&authenticator, *leaf_index, sub.clone()) .await?; } } From f17530f984b577e59104b5c9be6b6a38b2875bd6 Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Wed, 8 Apr 2026 11:18:00 +0200 Subject: [PATCH 05/14] Simplify bind recovery agent API --- .../src/issuers/recovery_bindings_manager.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/walletkit-core/src/issuers/recovery_bindings_manager.rs b/walletkit-core/src/issuers/recovery_bindings_manager.rs index ee8b535b..5487b77a 100644 --- a/walletkit-core/src/issuers/recovery_bindings_manager.rs +++ b/walletkit-core/src/issuers/recovery_bindings_manager.rs @@ -27,6 +27,7 @@ const ZERO_ADDRESS: &str = "0x0000000000000000000000000000000000000000"; #[derive(uniffi::Object)] pub struct RecoveryBindingManager { pop_backend_client: PopBackendClient, + recovery_agent_address: String, } #[uniffi::export] @@ -43,7 +44,8 @@ impl RecoveryBindingManager { Environment::Production => "https://app.orb.worldcoin.org", } .to_string(); - Self::new_with_base_url(base_url.as_str()) + let recovery_agent_address = environment.poh_recovery_agent_address(); + Self::new_with_base_url(base_url.as_str(), recovery_agent_address.as_str()) } /// Creates a new `RecoveryBindingManager` for the specified base URL and user agent. @@ -52,9 +54,9 @@ impl RecoveryBindingManager { /// /// Returns an error if the HTTP client cannot be built. #[uniffi::constructor] - pub fn new_with_base_url(base_url: &str) -> Result { + pub fn new_with_base_url(base_url: &str, recovery_agent_address: &str) -> Result { let pop_backend_client = PopBackendClient::new(base_url.to_string()); - Ok(Self { pop_backend_client }) + Ok(Self { pop_backend_client, recovery_agent_address: recovery_agent_address.to_string() }) } } @@ -78,18 +80,17 @@ impl RecoveryBindingManager { authenticator: &Authenticator, leaf_index: u64, sub: String, - new_recovery_agent: String, ) -> Result<(), WalletKitError> { let challenge = self.pop_backend_client.get_challenge().await?; let sig_recovery_update = authenticator - .danger_sign_initiate_recovery_agent_update(new_recovery_agent.clone()) + .danger_sign_initiate_recovery_agent_update(self.recovery_agent_address.clone()) .await?; let request = ManageRecoveryBindingRequest { sub, leaf_index, signature: format!("0x{}", hex::encode(sig_recovery_update.signature)), nonce: sig_recovery_update.nonce.to_string(), - recovery_agent: new_recovery_agent.clone(), + recovery_agent: self.recovery_agent_address.clone(), }; let security_token = Self::generate_recovery_agent_security_token( authenticator, @@ -267,7 +268,7 @@ mod tests { .await; let recovery_binding_manager = - RecoveryBindingManager::new_with_base_url(pop_api_server.url().as_str()) + RecoveryBindingManager::new_with_base_url(pop_api_server.url().as_str(), recovery_agent.as_str()) .unwrap(); let private_key = @@ -283,7 +284,6 @@ mod tests { &authenticator, leaf_index, sub.clone(), - recovery_agent.clone(), ) .await; assert!( From dd8ef28fa460481b0af08afabd015bef05943f62 Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Wed, 8 Apr 2026 11:19:54 +0200 Subject: [PATCH 06/14] Fix formatting --- .../src/issuers/recovery_bindings_manager.rs | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/walletkit-core/src/issuers/recovery_bindings_manager.rs b/walletkit-core/src/issuers/recovery_bindings_manager.rs index 5487b77a..908504eb 100644 --- a/walletkit-core/src/issuers/recovery_bindings_manager.rs +++ b/walletkit-core/src/issuers/recovery_bindings_manager.rs @@ -54,9 +54,15 @@ impl RecoveryBindingManager { /// /// Returns an error if the HTTP client cannot be built. #[uniffi::constructor] - pub fn new_with_base_url(base_url: &str, recovery_agent_address: &str) -> Result { + pub fn new_with_base_url( + base_url: &str, + recovery_agent_address: &str, + ) -> Result { let pop_backend_client = PopBackendClient::new(base_url.to_string()); - Ok(Self { pop_backend_client, recovery_agent_address: recovery_agent_address.to_string() }) + Ok(Self { + pop_backend_client, + recovery_agent_address: recovery_agent_address.to_string(), + }) } } @@ -83,7 +89,9 @@ impl RecoveryBindingManager { ) -> Result<(), WalletKitError> { let challenge = self.pop_backend_client.get_challenge().await?; let sig_recovery_update = authenticator - .danger_sign_initiate_recovery_agent_update(self.recovery_agent_address.clone()) + .danger_sign_initiate_recovery_agent_update( + self.recovery_agent_address.clone(), + ) .await?; let request = ManageRecoveryBindingRequest { sub, @@ -267,9 +275,11 @@ mod tests { .create_async() .await; - let recovery_binding_manager = - RecoveryBindingManager::new_with_base_url(pop_api_server.url().as_str(), recovery_agent.as_str()) - .unwrap(); + let recovery_binding_manager = RecoveryBindingManager::new_with_base_url( + pop_api_server.url().as_str(), + recovery_agent.as_str(), + ) + .unwrap(); let private_key = "d1995ace62b15d907bfb351ffe3cac57a8a84089a1b034101d2d7c78da415d58"; @@ -280,11 +290,7 @@ mod tests { create_test_authenticator(&private_key_bytes, rpc_url).await; let result = recovery_binding_manager - .bind_recovery_agent( - &authenticator, - leaf_index, - sub.clone(), - ) + .bind_recovery_agent(&authenticator, leaf_index, sub.clone()) .await; assert!( result.is_ok(), From 03659337a48cc021f61ec864db3c9759d3488a9e Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Wed, 8 Apr 2026 12:16:54 +0200 Subject: [PATCH 07/14] Address clippy warnings --- walletkit-cli/src/commands/recovery_binding.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/walletkit-cli/src/commands/recovery_binding.rs b/walletkit-cli/src/commands/recovery_binding.rs index c2b0464a..a081cc0d 100644 --- a/walletkit-cli/src/commands/recovery_binding.rs +++ b/walletkit-cli/src/commands/recovery_binding.rs @@ -32,7 +32,7 @@ pub async fn run( let recovery_binding_manager = RecoveryBindingManager::new(environment).unwrap(); recovery_binding_manager - .bind_recovery_agent(&authenticator, leaf_index.clone(), sub.clone()) + .bind_recovery_agent(&authenticator, *leaf_index, sub.clone()) .await?; } RecoveryBindingCommand::UnregisterBindings { leaf_index, sub } => { From b8c36eab3579bc24ab5b225d486a9913c03dabf6 Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Wed, 8 Apr 2026 14:23:09 +0200 Subject: [PATCH 08/14] Add recovery agent param to bind_recovery_agent method --- .../src/commands/recovery_binding.rs | 8 ++++- .../src/issuers/recovery_bindings_manager.rs | 36 ++++++++----------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/walletkit-cli/src/commands/recovery_binding.rs b/walletkit-cli/src/commands/recovery_binding.rs index a081cc0d..8c74d003 100644 --- a/walletkit-cli/src/commands/recovery_binding.rs +++ b/walletkit-cli/src/commands/recovery_binding.rs @@ -29,10 +29,16 @@ pub async fn run( match action { RecoveryBindingCommand::RegisterBindings { leaf_index, sub } => { + let recovery_agent_address = environment.poh_recovery_agent_address(); let recovery_binding_manager = RecoveryBindingManager::new(environment).unwrap(); recovery_binding_manager - .bind_recovery_agent(&authenticator, *leaf_index, sub.clone()) + .bind_recovery_agent( + &authenticator, + *leaf_index, + sub.clone(), + recovery_agent_address.clone(), + ) .await?; } RecoveryBindingCommand::UnregisterBindings { leaf_index, sub } => { diff --git a/walletkit-core/src/issuers/recovery_bindings_manager.rs b/walletkit-core/src/issuers/recovery_bindings_manager.rs index 908504eb..6f6e3111 100644 --- a/walletkit-core/src/issuers/recovery_bindings_manager.rs +++ b/walletkit-core/src/issuers/recovery_bindings_manager.rs @@ -27,7 +27,6 @@ const ZERO_ADDRESS: &str = "0x0000000000000000000000000000000000000000"; #[derive(uniffi::Object)] pub struct RecoveryBindingManager { pop_backend_client: PopBackendClient, - recovery_agent_address: String, } #[uniffi::export] @@ -44,8 +43,7 @@ impl RecoveryBindingManager { Environment::Production => "https://app.orb.worldcoin.org", } .to_string(); - let recovery_agent_address = environment.poh_recovery_agent_address(); - Self::new_with_base_url(base_url.as_str(), recovery_agent_address.as_str()) + Self::new_with_base_url(base_url.as_str()) } /// Creates a new `RecoveryBindingManager` for the specified base URL and user agent. @@ -54,15 +52,9 @@ impl RecoveryBindingManager { /// /// Returns an error if the HTTP client cannot be built. #[uniffi::constructor] - pub fn new_with_base_url( - base_url: &str, - recovery_agent_address: &str, - ) -> Result { + pub fn new_with_base_url(base_url: &str) -> Result { let pop_backend_client = PopBackendClient::new(base_url.to_string()); - Ok(Self { - pop_backend_client, - recovery_agent_address: recovery_agent_address.to_string(), - }) + Ok(Self { pop_backend_client }) } } @@ -86,19 +78,18 @@ impl RecoveryBindingManager { authenticator: &Authenticator, leaf_index: u64, sub: String, + recovery_agent_address: String, ) -> Result<(), WalletKitError> { let challenge = self.pop_backend_client.get_challenge().await?; let sig_recovery_update = authenticator - .danger_sign_initiate_recovery_agent_update( - self.recovery_agent_address.clone(), - ) + .danger_sign_initiate_recovery_agent_update(recovery_agent_address.clone()) .await?; let request = ManageRecoveryBindingRequest { sub, leaf_index, signature: format!("0x{}", hex::encode(sig_recovery_update.signature)), nonce: sig_recovery_update.nonce.to_string(), - recovery_agent: self.recovery_agent_address.clone(), + recovery_agent: recovery_agent_address.clone(), }; let security_token = Self::generate_recovery_agent_security_token( authenticator, @@ -275,11 +266,9 @@ mod tests { .create_async() .await; - let recovery_binding_manager = RecoveryBindingManager::new_with_base_url( - pop_api_server.url().as_str(), - recovery_agent.as_str(), - ) - .unwrap(); + let recovery_binding_manager = + RecoveryBindingManager::new_with_base_url(pop_api_server.url().as_str()) + .unwrap(); let private_key = "d1995ace62b15d907bfb351ffe3cac57a8a84089a1b034101d2d7c78da415d58"; @@ -290,7 +279,12 @@ mod tests { create_test_authenticator(&private_key_bytes, rpc_url).await; let result = recovery_binding_manager - .bind_recovery_agent(&authenticator, leaf_index, sub.clone()) + .bind_recovery_agent( + &authenticator, + leaf_index, + sub.clone(), + recovery_agent.clone(), + ) .await; assert!( result.is_ok(), From 8f8e7de9d9566fd416d9563c8bd84a6287b885b2 Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Wed, 8 Apr 2026 14:33:04 +0200 Subject: [PATCH 09/14] Update walletkit-cli/src/commands/recovery_binding.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub Trąd --- walletkit-cli/src/commands/recovery_binding.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/walletkit-cli/src/commands/recovery_binding.rs b/walletkit-cli/src/commands/recovery_binding.rs index 8c74d003..4e2ee8b5 100644 --- a/walletkit-cli/src/commands/recovery_binding.rs +++ b/walletkit-cli/src/commands/recovery_binding.rs @@ -11,7 +11,6 @@ pub enum RecoveryBindingCommand { /// Register bindings for a recovery agent. RegisterBindings { leaf_index: u64, - /// Checksummed hex address of the recovery agent (e.g. "0x1234…"). sub: String, }, UnregisterBindings { From 13d8b4c9b6c3ed4c765d5434a3c45d4c2392ef59 Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Wed, 8 Apr 2026 14:33:38 +0200 Subject: [PATCH 10/14] Update walletkit-core/src/issuers/recovery_bindings_manager.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub Trąd --- walletkit-core/src/issuers/recovery_bindings_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/walletkit-core/src/issuers/recovery_bindings_manager.rs b/walletkit-core/src/issuers/recovery_bindings_manager.rs index 6f6e3111..421561b9 100644 --- a/walletkit-core/src/issuers/recovery_bindings_manager.rs +++ b/walletkit-core/src/issuers/recovery_bindings_manager.rs @@ -67,7 +67,7 @@ impl RecoveryBindingManager { /// * `authenticator` — The authenticator whose signing key authorizes the request. /// * `leaf_index` — The authenticator's leaf index in the World ID Merkle tree. /// * `sub` — Hex-encoded subject identifier of the recovery agent to register. - /// * `new_recovery_agent` — The checksummed hex address of the new recovery agent (e.g. `"0x1234…"`). + /// * `recovery_agent_address` — The checksummed hex address of the new recovery agent (e.g. `"0x1234…"`). /// /// # Errors /// From 26a9650ba74582f79af2cbfca1a980a66f11a7bf Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Wed, 8 Apr 2026 14:33:50 +0200 Subject: [PATCH 11/14] Update walletkit-core/src/issuers/recovery_bindings_manager.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub Trąd --- walletkit-core/src/issuers/recovery_bindings_manager.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/walletkit-core/src/issuers/recovery_bindings_manager.rs b/walletkit-core/src/issuers/recovery_bindings_manager.rs index 421561b9..3ce98c01 100644 --- a/walletkit-core/src/issuers/recovery_bindings_manager.rs +++ b/walletkit-core/src/issuers/recovery_bindings_manager.rs @@ -19,6 +19,7 @@ use crate::issuers::PopBackendClient; use crate::Environment; use alloy_primitives::keccak256; use std::string::String; + const ZERO_ADDRESS: &str = "0x0000000000000000000000000000000000000000"; /// Client for registering and unregistering recovery agents with the `PoP` backend. /// From 2ecc7eee04c7ffac4abe5a14e58c390d135e2d35 Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Wed, 8 Apr 2026 14:39:47 +0200 Subject: [PATCH 12/14] Use alloy zero address --- walletkit-core/src/issuers/recovery_bindings_manager.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/walletkit-core/src/issuers/recovery_bindings_manager.rs b/walletkit-core/src/issuers/recovery_bindings_manager.rs index 3ce98c01..b84d4cca 100644 --- a/walletkit-core/src/issuers/recovery_bindings_manager.rs +++ b/walletkit-core/src/issuers/recovery_bindings_manager.rs @@ -18,9 +18,9 @@ use crate::issuers::pop_backend_client::ManageRecoveryBindingRequest; use crate::issuers::PopBackendClient; use crate::Environment; use alloy_primitives::keccak256; +use alloy_primitives::Address; use std::string::String; -const ZERO_ADDRESS: &str = "0x0000000000000000000000000000000000000000"; /// Client for registering and unregistering recovery agents with the `PoP` backend. /// /// Each instance is bound to a specific [`Environment`] (staging or production), @@ -122,7 +122,7 @@ impl RecoveryBindingManager { leaf_index: u64, sub: String, ) -> Result<(), WalletKitError> { - let recovery_agent = ZERO_ADDRESS.to_string(); + let recovery_agent = Address::ZERO.to_string(); let sig_recovery_update = authenticator .danger_sign_initiate_recovery_agent_update(recovery_agent.clone()) .await?; From 7ffd951e68613095e96c077825da876ac585b491 Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Wed, 8 Apr 2026 14:40:23 +0200 Subject: [PATCH 13/14] Update walletkit-core/src/issuers/recovery_bindings_manager.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub Trąd --- walletkit-core/src/issuers/recovery_bindings_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/walletkit-core/src/issuers/recovery_bindings_manager.rs b/walletkit-core/src/issuers/recovery_bindings_manager.rs index b84d4cca..f8792cb6 100644 --- a/walletkit-core/src/issuers/recovery_bindings_manager.rs +++ b/walletkit-core/src/issuers/recovery_bindings_manager.rs @@ -131,7 +131,7 @@ impl RecoveryBindingManager { leaf_index, signature: format!("0x{}", hex::encode(sig_recovery_update.signature)), nonce: sig_recovery_update.nonce.to_string(), - recovery_agent: recovery_agent.clone(), + recovery_agent, }; let challenge = self.pop_backend_client.get_challenge().await?; let security_token = Self::generate_recovery_agent_security_token( From b5105b5a26825dc27521581233fea16d4d6a7ce3 Mon Sep 17 00:00:00 2001 From: Elena Gryaznova Date: Wed, 8 Apr 2026 14:52:39 +0200 Subject: [PATCH 14/14] Take leaf index from the authenticat --- .../src/commands/recovery_binding.rs | 9 ++-- .../src/issuers/recovery_bindings_manager.rs | 46 ++++++++----------- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/walletkit-cli/src/commands/recovery_binding.rs b/walletkit-cli/src/commands/recovery_binding.rs index 4e2ee8b5..e3263f3d 100644 --- a/walletkit-cli/src/commands/recovery_binding.rs +++ b/walletkit-cli/src/commands/recovery_binding.rs @@ -10,11 +10,9 @@ use walletkit_core::Environment; pub enum RecoveryBindingCommand { /// Register bindings for a recovery agent. RegisterBindings { - leaf_index: u64, sub: String, }, UnregisterBindings { - leaf_index: u64, sub: String, }, } @@ -27,24 +25,23 @@ pub async fn run( let (authenticator, _store) = init_authenticator(cli).await?; match action { - RecoveryBindingCommand::RegisterBindings { leaf_index, sub } => { + RecoveryBindingCommand::RegisterBindings { sub } => { let recovery_agent_address = environment.poh_recovery_agent_address(); let recovery_binding_manager = RecoveryBindingManager::new(environment).unwrap(); recovery_binding_manager .bind_recovery_agent( &authenticator, - *leaf_index, sub.clone(), recovery_agent_address.clone(), ) .await?; } - RecoveryBindingCommand::UnregisterBindings { leaf_index, sub } => { + RecoveryBindingCommand::UnregisterBindings { sub } => { let recovery_binding_manager = RecoveryBindingManager::new(environment).unwrap(); recovery_binding_manager - .unbind_recovery_agent(&authenticator, *leaf_index, sub.clone()) + .unbind_recovery_agent(&authenticator, sub.clone()) .await?; } } diff --git a/walletkit-core/src/issuers/recovery_bindings_manager.rs b/walletkit-core/src/issuers/recovery_bindings_manager.rs index f8792cb6..04c04925 100644 --- a/walletkit-core/src/issuers/recovery_bindings_manager.rs +++ b/walletkit-core/src/issuers/recovery_bindings_manager.rs @@ -66,7 +66,6 @@ impl RecoveryBindingManager { /// # Arguments /// /// * `authenticator` — The authenticator whose signing key authorizes the request. - /// * `leaf_index` — The authenticator's leaf index in the World ID Merkle tree. /// * `sub` — Hex-encoded subject identifier of the recovery agent to register. /// * `recovery_agent_address` — The checksummed hex address of the new recovery agent (e.g. `"0x1234…"`). /// @@ -77,11 +76,11 @@ impl RecoveryBindingManager { pub async fn bind_recovery_agent( &self, authenticator: &Authenticator, - leaf_index: u64, sub: String, recovery_agent_address: String, ) -> Result<(), WalletKitError> { let challenge = self.pop_backend_client.get_challenge().await?; + let leaf_index = authenticator.leaf_index(); let sig_recovery_update = authenticator .danger_sign_initiate_recovery_agent_update(recovery_agent_address.clone()) .await?; @@ -109,7 +108,6 @@ impl RecoveryBindingManager { /// # Arguments /// /// * `authenticator` — The authenticator whose signing key authorizes the request. - /// * `leaf_index` — The authenticator's leaf index in the World ID Merkle tree. /// * `sub` — Hex-encoded subject identifier of the recovery agent to remove. /// /// # Errors @@ -119,9 +117,9 @@ impl RecoveryBindingManager { pub async fn unbind_recovery_agent( &self, authenticator: &Authenticator, - leaf_index: u64, sub: String, ) -> Result<(), WalletKitError> { + let leaf_index = authenticator.leaf_index(); let recovery_agent = Address::ZERO.to_string(); let sig_recovery_update = authenticator .danger_sign_initiate_recovery_agent_update(recovery_agent.clone()) @@ -229,7 +227,6 @@ mod tests { #[tokio::test] async fn test_recovery_agent_token_generator_success() { let mut pop_api_server = mockito::Server::new_async().await; - let leaf_index = 42; let sub = "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890" .to_string(); @@ -248,7 +245,14 @@ mod tests { // Mock the recovery binding registration endpoint let url_path = "/api/v1/recovery-binding".to_string(); let recovery_agent = "0x1000000000000000000000000000000000000000".to_string(); - + let private_key = + "d1995ace62b15d907bfb351ffe3cac57a8a84089a1b034101d2d7c78da415d58"; + let private_key_bytes = hex::decode(private_key).unwrap(); + let (mock_eth_server, eth_mock) = create_mock_eth_server().await; + let rpc_url = mock_eth_server.url(); + let authenticator = + create_test_authenticator(&private_key_bytes, rpc_url).await; + let leaf_index = authenticator.leaf_index(); let mock = pop_api_server .mock("POST", url_path.as_str()) .match_header( @@ -271,21 +275,8 @@ mod tests { RecoveryBindingManager::new_with_base_url(pop_api_server.url().as_str()) .unwrap(); - let private_key = - "d1995ace62b15d907bfb351ffe3cac57a8a84089a1b034101d2d7c78da415d58"; - let private_key_bytes = hex::decode(private_key).unwrap(); - let (mock_eth_server, eth_mock) = create_mock_eth_server().await; - let rpc_url = mock_eth_server.url(); - let authenticator = - create_test_authenticator(&private_key_bytes, rpc_url).await; - let result = recovery_binding_manager - .bind_recovery_agent( - &authenticator, - leaf_index, - sub.clone(), - recovery_agent.clone(), - ) + .bind_recovery_agent(&authenticator, sub.clone(), recovery_agent.clone()) .await; assert!( result.is_ok(), @@ -301,7 +292,6 @@ mod tests { #[tokio::test] async fn test_recovery_bindings_signature() { - let leaf_index = 42; let sub = "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890" .to_string(); let challenge = @@ -310,7 +300,11 @@ mod tests { let private_key = "d1995ace62b15d907bfb351ffe3cac57a8a84089a1b034101d2d7c78da415d58"; let private_key_bytes = hex::decode(private_key).unwrap(); - + let (mock_eth_server, eth_mock) = create_mock_eth_server().await; + let rpc_url = mock_eth_server.url(); + let authenticator = + create_test_authenticator(&private_key_bytes, rpc_url).await; + let leaf_index = authenticator.leaf_index(); let message_bytes = RecoveryBindingManager::create_bytes_to_sign(&challenge, leaf_index, &sub) .unwrap(); @@ -326,11 +320,6 @@ mod tests { nonce: nonce.clone(), recovery_agent: recovery_agent.clone(), }; - let (mock_eth_server, eth_mock) = create_mock_eth_server().await; - let rpc_url = mock_eth_server.url(); - - let authenticator = - create_test_authenticator(&private_key_bytes, rpc_url).await; let security_token = RecoveryBindingManager::generate_recovery_agent_security_token( &authenticator, @@ -338,6 +327,7 @@ mod tests { &challenge, ) .unwrap(); + assert!( !security_token.is_empty(), "Expected success, but got error: {security_token:?}" @@ -386,7 +376,7 @@ mod tests { serde_json::json!({ "jsonrpc": "2.0", "id": 1, - "result": "0x0000000000000000000000000000000000000000000000000000000000000001" + "result": "0x000000000000000000000000000000000000000000000000000000000000002a" }) .to_string(), )