alloy_zksync/wallet/
mod.rs1use alloy::consensus::SignableTransaction;
4use alloy::network::{Network, NetworkWallet, TxSigner};
5use alloy::primitives::Address;
6
7use crate::network::{Zksync, tx_envelope::TxEnvelope, unsigned_tx::TypedTransaction};
8
9use alloy::primitives::Signature;
10use std::{collections::BTreeMap, sync::Arc};
11
12#[derive(Clone, Default)]
14pub struct ZksyncWallet {
15 default: Address,
16 signers: BTreeMap<Address, Arc<dyn TxSigner<Signature> + Send + Sync>>,
17}
18
19impl std::fmt::Debug for ZksyncWallet {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 f.debug_struct("ZksyncWallet")
22 .field("default_signer", &self.default)
23 .field("credentials", &self.signers.len())
24 .finish()
25 }
26}
27
28impl<S> From<S> for ZksyncWallet
29where
30 S: TxSigner<Signature> + Send + Sync + 'static,
31{
32 fn from(signer: S) -> Self {
33 Self::new(signer)
34 }
35}
36
37impl ZksyncWallet {
38 pub fn new<S>(signer: S) -> Self
40 where
41 S: TxSigner<Signature> + Send + Sync + 'static,
42 {
43 let mut this = Self::default();
44 this.register_default_signer(signer);
45 this
46 }
47
48 pub fn register_signer<S>(&mut self, signer: S)
54 where
55 S: TxSigner<Signature> + Send + Sync + 'static,
56 {
57 self.signers.insert(signer.address(), Arc::new(signer));
58 }
59
60 pub fn register_default_signer<S>(&mut self, signer: S)
67 where
68 S: TxSigner<Signature> + Send + Sync + 'static,
69 {
70 self.default = signer.address();
71 self.register_signer(signer);
72 }
73
74 pub fn default_signer(&self) -> Arc<dyn TxSigner<Signature> + Send + Sync + 'static> {
76 self.signers
77 .get(&self.default)
78 .cloned()
79 .expect("invalid signer")
80 }
81
82 pub fn signer_by_address(
84 &self,
85 address: Address,
86 ) -> Option<Arc<dyn TxSigner<Signature> + Send + Sync + 'static>> {
87 self.signers.get(&address).cloned()
88 }
89
90 #[doc(alias = "sign_tx_inner")]
91 async fn sign_transaction_inner(
92 &self,
93 sender: Address,
94 tx: &mut dyn SignableTransaction<Signature>,
95 ) -> alloy::signers::Result<Signature> {
96 self.signer_by_address(sender)
97 .ok_or_else(|| {
98 alloy::signers::Error::other(format!("Missing signing credential for {sender}"))
99 })?
100 .sign_transaction(tx)
101 .await
102 }
103}
104
105impl<N> NetworkWallet<N> for ZksyncWallet
106where
107 N: Network<
108 UnsignedTx = alloy::consensus::TypedTransaction,
109 TxEnvelope = alloy::consensus::TxEnvelope,
110 >,
111{
112 fn default_signer_address(&self) -> Address {
113 self.default
114 }
115
116 fn has_signer_for(&self, address: &Address) -> bool {
117 self.signers.contains_key(address)
118 }
119
120 fn signer_addresses(&self) -> impl Iterator<Item = Address> {
121 self.signers.keys().copied()
122 }
123
124 #[doc(alias = "sign_tx_from")]
125 async fn sign_transaction_from(
126 &self,
127 sender: Address,
128 tx: alloy::consensus::TypedTransaction,
129 ) -> alloy::signers::Result<alloy::consensus::TxEnvelope> {
130 match tx {
131 alloy::consensus::TypedTransaction::Legacy(mut t) => {
132 let sig = self.sign_transaction_inner(sender, &mut t).await?;
133 Ok(t.into_signed(sig).into())
134 }
135 alloy::consensus::TypedTransaction::Eip2930(mut t) => {
136 let sig = self.sign_transaction_inner(sender, &mut t).await?;
137 Ok(t.into_signed(sig).into())
138 }
139 alloy::consensus::TypedTransaction::Eip1559(mut t) => {
140 let sig = self.sign_transaction_inner(sender, &mut t).await?;
141 Ok(t.into_signed(sig).into())
142 }
143 alloy::consensus::TypedTransaction::Eip4844(mut t) => {
144 let sig = self.sign_transaction_inner(sender, &mut t).await?;
145 Ok(t.into_signed(sig).into())
146 }
147 alloy::consensus::TypedTransaction::Eip7702(mut t) => {
148 let sig = self.sign_transaction_inner(sender, &mut t).await?;
149 Ok(t.into_signed(sig).into())
150 }
151 }
152 }
153}
154
155impl NetworkWallet<Zksync> for ZksyncWallet {
156 fn default_signer_address(&self) -> Address {
157 self.default
158 }
159
160 fn has_signer_for(&self, address: &Address) -> bool {
161 self.signers.contains_key(address)
162 }
163
164 fn signer_addresses(&self) -> impl Iterator<Item = Address> {
165 self.signers.keys().copied()
166 }
167
168 #[doc(alias = "sign_tx_from")]
169 async fn sign_transaction_from(
170 &self,
171 sender: Address,
172 tx: TypedTransaction,
173 ) -> alloy::signers::Result<TxEnvelope> {
174 match tx {
175 TypedTransaction::Native(t) => {
176 let sig = <Self as NetworkWallet<alloy::network::Ethereum>>::sign_transaction_from(
177 self, sender, t,
178 )
179 .await?;
180 Ok(TxEnvelope::Native(sig))
181 }
182 TypedTransaction::Eip712(mut t) => {
183 let sig = self.sign_transaction_inner(sender, &mut t).await?;
184 Ok(TxEnvelope::Eip712(t.into_signed(sig)))
185 }
186 }
187 }
188}