alloy_provider/provider/
web3_signer.rs1use alloy_eips::Decodable2718;
2use alloy_network::{Ethereum, Network, TransactionBuilder};
3use alloy_primitives::{Address, Bytes};
4
5use super::Provider;
6
7#[derive(Debug, Clone)]
18pub struct Web3Signer<P: Provider<N> + Clone, N: Network = Ethereum> {
19 provider: P,
21 address: Address,
26 _pd: std::marker::PhantomData<N>,
27}
28
29impl<P: Provider<N> + Clone, N: Network> Web3Signer<P, N> {
30 pub const fn new(provider: P, address: Address) -> Self {
36 Self { provider, address, _pd: std::marker::PhantomData }
37 }
38
39 pub fn provider(&self) -> P {
41 self.provider.clone()
42 }
43 pub async fn sign_transaction(
53 &self,
54 mut tx: N::TransactionRequest,
55 ) -> alloy_signer::Result<Bytes> {
56 tx.set_from(self.address);
58 self.provider.sign_transaction(tx).await.map_err(alloy_signer::Error::other)
59 }
60
61 pub async fn sign_and_decode(
64 &self,
65 tx: N::TransactionRequest,
66 ) -> alloy_signer::Result<N::TxEnvelope> {
67 let raw = self.sign_transaction(tx).await?;
68 N::TxEnvelope::decode_2718(&mut raw.as_ref()).map_err(alloy_signer::Error::other)
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use crate::{ext::test::async_ci_only, Provider, ProviderBuilder};
76 use alloy_consensus::{transaction::SignerRecoverable, TxEnvelope};
77 use alloy_node_bindings::{utils::run_with_tempdir, Reth};
78 use alloy_primitives::{Address, U256};
79
80 #[tokio::test]
81 #[cfg(not(windows))]
82 async fn eth_sign_transaction() {
83 async_ci_only(|| async {
84 run_with_tempdir("reth-sign-tx", |dir| async {
85 let reth = Reth::new().dev().disable_discovery().data_dir(dir).spawn();
86 let provider = ProviderBuilder::new().connect_http(reth.endpoint_url());
87
88 let accounts = provider.get_accounts().await.unwrap();
89 let from = accounts[0];
90 let signer = Web3Signer::new(provider, from);
91
92 let tx = signer
93 .provider()
94 .transaction_request()
95 .from(from)
96 .to(Address::ZERO)
97 .value(U256::from(100))
98 .gas_limit(21000);
99
100 let signed_tx = signer.sign_transaction(tx).await.unwrap();
101
102 let tx = TxEnvelope::decode_2718(&mut signed_tx.as_ref()).unwrap();
103
104 let signer = tx.recover_signer().unwrap();
105
106 assert_eq!(signer, from);
107 })
108 .await
109 })
110 .await;
111 }
112}