Skip to content

Commit 48aa667

Browse files
authored
feat: guardian typescript bindings (#246)
1 parent c26c70f commit 48aa667

File tree

16 files changed

+1006
-16
lines changed

16 files changed

+1006
-16
lines changed

packages/sdk-platforms/rust/zksync-sso-erc4337/crates/zksync-sso-erc4337-core/src/erc4337/account/modular_smart_account/guardian/remove.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ use alloy::{
2020

2121
#[derive(Clone)]
2222
pub struct RemoveGuardianParams<P: Provider + Send + Sync + Clone> {
23-
guardian_executor: Address,
24-
guardian_to_remove: Address,
25-
account_address: Address,
26-
entry_point_address: Address,
27-
paymaster: Option<PaymasterParams>,
28-
provider: P,
29-
bundler_client: BundlerClient,
30-
signer: Signer,
23+
pub guardian_executor: Address,
24+
pub guardian_to_remove: Address,
25+
pub account_address: Address,
26+
pub entry_point_address: Address,
27+
pub paymaster: Option<PaymasterParams>,
28+
pub provider: P,
29+
pub bundler_client: BundlerClient,
30+
pub signer: Signer,
3131
}
3232

3333
pub async fn remove_guardian<P>(

packages/sdk-platforms/rust/zksync-sso-erc4337/crates/zksync-sso-erc4337-core/src/erc4337/account/modular_smart_account/session.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ pub mod signature_wasm;
1111
pub mod state;
1212
pub mod status;
1313

14-
pub mod contract;
14+
pub(crate) mod contract;

packages/sdk-platforms/rust/zksync-sso-erc4337/crates/zksync-sso-erc4337-core/src/erc4337/utils/alto_test_utils.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,7 @@ impl AltoTestHelper {
8484
use crate::erc4337::bundler::{
8585
config::BundlerConfig, pimlico::client::BundlerClient,
8686
};
87-
assert!(self.port != 4337);
8887
let bundler_url = format!("http://127.0.0.1:{}", self.port);
89-
assert!(!bundler_url.contains(":4337"));
9088
let config = BundlerConfig::new(bundler_url);
9189
BundlerClient::new(config)
9290
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod modular_smart_account;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod guardian;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pub mod accept;
2+
pub mod list;
3+
pub mod propose;
4+
pub mod recovery;
5+
pub mod remove;
6+
pub mod status;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
use crate::wasm_transport::WasmHttpTransport;
2+
use alloy::{
3+
network::EthereumWallet,
4+
primitives::Address,
5+
providers::ProviderBuilder,
6+
signers::local::PrivateKeySigner,
7+
};
8+
use alloy_rpc_client::RpcClient;
9+
use wasm_bindgen::prelude::*;
10+
use wasm_bindgen_futures::future_to_promise;
11+
use zksync_sso_erc4337_core::erc4337::account::modular_smart_account::guardian::accept::{
12+
accept_guardian, AcceptGuardianParams,
13+
};
14+
15+
/// Accept a proposed guardian for a smart account
16+
///
17+
/// This function allows a guardian to accept their proposed role for a smart account.
18+
/// The guardian must sign the transaction using their private key.
19+
///
20+
/// # Parameters
21+
/// * `rpc_url` - RPC URL for the blockchain network
22+
/// * `guardian_executor` - Address of the GuardianExecutor contract
23+
/// * `account` - Address of the smart account
24+
/// * `guardian_private_key` - Private key of the guardian (0x-prefixed hex string)
25+
///
26+
/// # Returns
27+
/// Promise that resolves to the transaction receipt hash as a hex string
28+
#[wasm_bindgen]
29+
pub fn accept_guardian_wasm(
30+
rpc_url: String,
31+
guardian_executor: String,
32+
account: String,
33+
guardian_private_key: String,
34+
) -> js_sys::Promise {
35+
future_to_promise(async move {
36+
// Parse addresses
37+
let guardian_executor_addr = match guardian_executor.parse::<Address>()
38+
{
39+
Ok(addr) => addr,
40+
Err(e) => {
41+
return Err(JsValue::from_str(&format!(
42+
"Invalid guardian executor address: {}",
43+
e
44+
)));
45+
}
46+
};
47+
48+
let account_addr = match account.parse::<Address>() {
49+
Ok(addr) => addr,
50+
Err(e) => {
51+
return Err(JsValue::from_str(&format!(
52+
"Invalid account address: {}",
53+
e
54+
)));
55+
}
56+
};
57+
58+
// Parse guardian private key
59+
let guardian_key = match guardian_private_key
60+
.trim_start_matches("0x")
61+
.parse::<PrivateKeySigner>()
62+
{
63+
Ok(signer) => signer,
64+
Err(e) => {
65+
return Err(JsValue::from_str(&format!(
66+
"Invalid guardian private key: {}",
67+
e
68+
)));
69+
}
70+
};
71+
72+
let guardian_wallet = EthereumWallet::from(guardian_key);
73+
74+
// Create transport and provider with wallet
75+
let transport = WasmHttpTransport::new(rpc_url);
76+
let client = RpcClient::new(transport.clone(), false);
77+
let guardian_provider = ProviderBuilder::new()
78+
.wallet(guardian_wallet)
79+
.connect_client(client);
80+
81+
// Call the core function
82+
match accept_guardian(AcceptGuardianParams {
83+
guardian_executor: guardian_executor_addr,
84+
account: account_addr,
85+
guardian_provider,
86+
})
87+
.await
88+
{
89+
Ok(receipt) => {
90+
let tx_hash = receipt.transaction_hash;
91+
Ok(JsValue::from_str(&format!("0x{:x}", tx_hash)))
92+
}
93+
Err(e) => Err(JsValue::from_str(&format!(
94+
"Failed to accept guardian: {}",
95+
e
96+
))),
97+
}
98+
})
99+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use crate::wasm_transport::WasmHttpTransport;
2+
use alloy::primitives::Address;
3+
use alloy::providers::ProviderBuilder;
4+
use alloy_rpc_client::RpcClient;
5+
use wasm_bindgen::prelude::*;
6+
use wasm_bindgen_futures::future_to_promise;
7+
use zksync_sso_erc4337_core::erc4337::account::modular_smart_account::guardian::list::get_guardians_list;
8+
9+
/// Get the list of guardians for a smart account
10+
///
11+
/// # Parameters
12+
/// * `rpc_url` - RPC URL for the blockchain network
13+
/// * `account_address` - Address of the smart account
14+
/// * `guardian_executor_address` - Address of the GuardianExecutor contract
15+
///
16+
/// # Returns
17+
/// Promise that resolves to a JSON array of guardian addresses (hex strings)
18+
#[wasm_bindgen]
19+
pub fn get_guardians_list_wasm(
20+
rpc_url: String,
21+
account_address: String,
22+
guardian_executor_address: String,
23+
) -> js_sys::Promise {
24+
future_to_promise(async move {
25+
// Parse addresses
26+
let account_addr = match account_address.parse::<Address>() {
27+
Ok(addr) => addr,
28+
Err(e) => {
29+
return Err(JsValue::from_str(&format!(
30+
"Invalid account address: {}",
31+
e
32+
)));
33+
}
34+
};
35+
36+
let guardian_executor_addr =
37+
match guardian_executor_address.parse::<Address>() {
38+
Ok(addr) => addr,
39+
Err(e) => {
40+
return Err(JsValue::from_str(&format!(
41+
"Invalid guardian executor address: {}",
42+
e
43+
)));
44+
}
45+
};
46+
47+
// Create transport and provider
48+
let transport = WasmHttpTransport::new(rpc_url);
49+
let client = RpcClient::new(transport.clone(), false);
50+
let provider = ProviderBuilder::new().connect_client(client);
51+
52+
// Call the core function
53+
match get_guardians_list(account_addr, guardian_executor_addr, provider)
54+
.await
55+
{
56+
Ok(guardians) => {
57+
let addresses: Vec<String> = guardians
58+
.iter()
59+
.map(|addr| format!("0x{:x}", addr))
60+
.collect();
61+
let json = serde_json::to_string(&addresses).map_err(|e| {
62+
JsValue::from_str(&format!(
63+
"Failed to serialize guardians list: {}",
64+
e
65+
))
66+
})?;
67+
Ok(JsValue::from_str(&json))
68+
}
69+
Err(e) => Err(JsValue::from_str(&format!(
70+
"Failed to get guardians list: {}",
71+
e
72+
))),
73+
}
74+
})
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
use crate::wasm_transport::WasmHttpTransport;
2+
use alloy::{
3+
network::EthereumWallet, primitives::Address, providers::ProviderBuilder,
4+
signers::local::PrivateKeySigner,
5+
};
6+
use alloy_rpc_client::RpcClient;
7+
use wasm_bindgen::prelude::*;
8+
use wasm_bindgen_futures::future_to_promise;
9+
use zksync_sso_erc4337_core::erc4337::{
10+
account::modular_smart_account::guardian::propose::{
11+
ProposeGuardianParams, propose_guardian,
12+
},
13+
bundler::{config::BundlerConfig, pimlico::client::BundlerClient},
14+
signer::create_eoa_signer,
15+
};
16+
17+
/// Propose a new guardian for a smart account
18+
///
19+
/// This function creates a user operation to propose a new guardian.
20+
/// The account owner must sign the transaction.
21+
///
22+
/// # Parameters
23+
/// * `config` - SendTransactionConfig with RPC URL, bundler URL, and entry point
24+
/// * `guardian_executor` - Address of the GuardianExecutor contract
25+
/// * `new_guardian` - Address of the guardian to propose
26+
/// * `account` - Address of the smart account
27+
/// * `eoa_validator_address` - Address of the EOA validator module
28+
/// * `eoa_private_key` - Private key of the account owner (0x-prefixed hex string)
29+
///
30+
/// # Returns
31+
/// Promise that resolves to the user operation receipt hash as a hex string
32+
#[wasm_bindgen]
33+
pub fn propose_guardian_wasm(
34+
config: crate::SendTransactionConfig,
35+
guardian_executor: String,
36+
new_guardian: String,
37+
account: String,
38+
eoa_validator_address: String,
39+
eoa_private_key: String,
40+
) -> js_sys::Promise {
41+
future_to_promise(async move {
42+
// Parse addresses
43+
let guardian_executor_addr = match guardian_executor.parse::<Address>()
44+
{
45+
Ok(addr) => addr,
46+
Err(e) => {
47+
return Err(JsValue::from_str(&format!(
48+
"Invalid guardian executor address: {}",
49+
e
50+
)));
51+
}
52+
};
53+
54+
let new_guardian_addr = match new_guardian.parse::<Address>() {
55+
Ok(addr) => addr,
56+
Err(e) => {
57+
return Err(JsValue::from_str(&format!(
58+
"Invalid new guardian address: {}",
59+
e
60+
)));
61+
}
62+
};
63+
64+
let account_addr = match account.parse::<Address>() {
65+
Ok(addr) => addr,
66+
Err(e) => {
67+
return Err(JsValue::from_str(&format!(
68+
"Invalid account address: {}",
69+
e
70+
)));
71+
}
72+
};
73+
74+
let entry_point_addr =
75+
match config.entry_point_address().parse::<Address>() {
76+
Ok(addr) => addr,
77+
Err(e) => {
78+
return Err(JsValue::from_str(&format!(
79+
"Invalid entry point address: {}",
80+
e
81+
)));
82+
}
83+
};
84+
85+
let eoa_validator_addr = match eoa_validator_address.parse::<Address>()
86+
{
87+
Ok(addr) => addr,
88+
Err(e) => {
89+
return Err(JsValue::from_str(&format!(
90+
"Invalid EOA validator address: {}",
91+
e
92+
)));
93+
}
94+
};
95+
96+
// Parse EOA private key
97+
let eoa_key = match eoa_private_key
98+
.trim_start_matches("0x")
99+
.parse::<PrivateKeySigner>()
100+
{
101+
Ok(signer) => signer,
102+
Err(e) => {
103+
return Err(JsValue::from_str(&format!(
104+
"Invalid EOA private key: {}",
105+
e
106+
)));
107+
}
108+
};
109+
110+
let eoa_wallet = EthereumWallet::from(eoa_key.clone());
111+
112+
// Create transport and provider
113+
let transport = WasmHttpTransport::new(config.rpc_url());
114+
let client = RpcClient::new(transport.clone(), false);
115+
let provider =
116+
ProviderBuilder::new().wallet(eoa_wallet).connect_client(client);
117+
118+
// Create bundler client
119+
let bundler_client = {
120+
let bundler_config = BundlerConfig::new(config.bundler_url());
121+
BundlerClient::new(bundler_config)
122+
};
123+
124+
// Create EOA signer
125+
let eoa_key_str = format!("0x{}", hex::encode(eoa_key.to_bytes()));
126+
let signer = match create_eoa_signer(eoa_key_str, eoa_validator_addr) {
127+
Ok(signer) => signer,
128+
Err(e) => {
129+
return Err(JsValue::from_str(&format!(
130+
"Failed to create EOA signer: {}",
131+
e
132+
)));
133+
}
134+
};
135+
136+
// Call the core function
137+
match propose_guardian(ProposeGuardianParams {
138+
guardian_executor: guardian_executor_addr,
139+
new_guardian: new_guardian_addr,
140+
account: account_addr,
141+
entry_point: entry_point_addr,
142+
paymaster: None,
143+
provider,
144+
bundler_client,
145+
signer,
146+
})
147+
.await
148+
{
149+
Ok(receipt) => {
150+
let tx_hash = receipt.receipt.transaction_hash;
151+
Ok(JsValue::from_str(&tx_hash))
152+
}
153+
Err(e) => Err(JsValue::from_str(&format!(
154+
"Failed to propose guardian: {}",
155+
e
156+
))),
157+
}
158+
})
159+
}

0 commit comments

Comments
 (0)