1use alloy_consensus::{
2 SignableTransaction, TxEip1559, serde_bincode_compat, transaction::RlpEcdsaEncodableTx,
3};
4use alloy_primitives::{Signature, SignatureError};
5use alloy_sol_types::SolValue;
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7use serde_with::serde_as;
8use std::{ops::Deref, sync::OnceLock};
9
10use alloy_primitives::Address;
11
12use super::{Hash, Hashable, Merkleizable, merkle_tree::MerkleBuilder};
13use crate::Transaction;
14
15pub trait TxSigner {
16 fn sign_tx(&self, tx: Transaction) -> Result<Signed<Transaction>, alloy_signer::Error>;
17}
18
19pub trait Signer {
20 fn sign<T: Hashable>(&self, msg: T) -> Result<Signed<T>, alloy_signer::Error>;
21}
22
23impl<S> TxSigner for S
24where
25 S: alloy_signer::SignerSync<Signature>,
26 S: alloy_signer::Signer<Signature>,
27{
28 fn sign_tx(&self, tx: Transaction) -> Result<Signed<Transaction>, alloy_signer::Error> {
29 self.sign(tx)
30 }
31}
32
33impl<S> Signer for S
34where
35 S: alloy_signer::SignerSync<Signature>,
36 S: alloy_signer::Signer<Signature>,
37{
38 fn sign<T: Hashable>(&self, msg: T) -> Result<Signed<T>, alloy_signer::Error> {
39 let signature = self.sign_hash_sync(&msg.hash_custom())?;
40 Ok(Signed {
41 signed: msg,
42 signature,
43 signer: self.address(),
44 hash: OnceLock::new(),
45 })
46 }
47}
48
49#[non_exhaustive]
56#[derive(Clone, Debug, PartialEq, Eq)]
57pub struct Signed<T> {
58 pub signed: T,
59 pub signature: Signature,
60 pub signer: Address,
61 pub hash: OnceLock<Hash>,
62}
63
64impl<T> Signed<T>
65where
66 T: SignableTransaction<Signature>,
67{
68 pub unsafe fn new_unchecked(signed: T, signature: Signature, signer: Address) -> Self {
74 debug_assert_eq!(
75 signer,
76 signature
77 .recover_address_from_prehash(&signed.signature_hash())
78 .unwrap(),
79 "Signer address does not match the signature's recovered address"
80 );
81 Signed {
82 signed,
83 signature,
84 signer,
85 hash: OnceLock::new(),
86 }
87 }
88}
89
90impl Serialize for Signed<Transaction> {
91 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
92 where
93 S: Serializer,
94 {
95 #[serde_as]
96 #[derive(Serialize)]
97 struct Helper<'a> {
98 #[serde_as(as = "serde_bincode_compat::transaction::TxEip1559")]
99 signed: &'a Transaction,
100 signature: &'a Signature,
101 }
102
103 Helper {
104 signed: &self.signed,
105 signature: &self.signature,
106 }
107 .serialize(serializer)
108 }
109}
110
111impl<'de> Deserialize<'de> for Signed<Transaction> {
112 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
113 where
114 D: Deserializer<'de>,
115 {
116 #[serde_as]
117 #[derive(Deserialize)]
118 struct Helper {
119 #[serde_as(as = "serde_bincode_compat::transaction::TxEip1559")]
120 signed: Transaction,
121 signature: Signature,
122 }
123 let Helper { signed, signature } = Helper::deserialize(deserializer)?;
124
125 let signer =
126 alloy_consensus::Signed::new_unchecked(signed.clone(), signature, signed.hash_custom())
127 .recover_signer()
128 .map_err(serde::de::Error::custom)?;
129
130 Ok(Signed {
131 signed,
132 signature,
133 signer,
134 hash: OnceLock::new(),
135 })
136 }
137}
138
139impl<T: Hashable> Deref for Signed<T> {
140 type Target = T;
141
142 fn deref(&self) -> &Self::Target {
143 &self.signed
144 }
145}
146
147impl<T: RlpEcdsaEncodableTx> Hashable for Signed<T> {
149 fn hash_custom(&self) -> Hash {
150 *self
151 .hash
152 .get_or_init(|| self.signed.tx_hash(&self.signature))
153 }
154}
155
156impl TryFrom<alloy_consensus::Signed<TxEip1559, Signature>> for Signed<Transaction> {
157 type Error = SignatureError;
158
159 fn try_from(value: alloy_consensus::Signed<TxEip1559>) -> Result<Self, Self::Error> {
160 let signer = value.recover_signer()?;
161
162 Ok(Signed {
163 signature: *value.signature(),
164 signed: value.strip_signature(),
165 signer,
166 hash: OnceLock::new(),
167 })
168 }
169}
170
171impl<T: Merkleizable + Hashable> Merkleizable for Signed<T> {
172 fn append_leaves(&self, builder: &mut MerkleBuilder) {
173 builder.add_merkleizable("signed", &self.signed);
174 builder.add_field("signer", self.signer.abi_encode().hash_custom());
175 }
176}
177
178#[cfg(feature = "arbitrary")]
179impl<'a, T: arbitrary::Arbitrary<'a> + Hashable + SignableTransaction<Signature>>
180 arbitrary::Arbitrary<'a> for Signed<T>
181{
182 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
183 use alloy_signer::SignerSync;
184 let signed = T::arbitrary(u)?;
185 let signer = alloy_signer_local::PrivateKeySigner::random();
186 let signature = signer.sign_hash_sync(&signed.signature_hash()).unwrap();
187 Ok(Signed {
188 signed,
189 signature,
190 signer: signer.address(),
191 hash: OnceLock::new(),
192 })
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199 use arbitrary::Arbitrary;
200 use bincode::config::standard;
201
202 fn arbitrary_signed_tx() -> Signed<Transaction> {
203 let bytes: [u8; 1024] = rand::random();
204 Signed::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap()
205 }
206
207 #[test]
208 fn signed_serialization() {
209 let mut signed = arbitrary_signed_tx();
210 let signer = signed.signer;
211 signed.signer = Default::default(); let serialized = serde_json::to_string(&signed).unwrap();
214 let deserialized: Signed<Transaction> = serde_json::from_str(&serialized).unwrap();
215
216 assert_eq!(signed.signed, deserialized.signed);
217 assert_eq!(signer, deserialized.signer);
218 assert_eq!(signed.signature, deserialized.signature);
219 }
220
221 #[test]
222 fn signed_serialization_with_bincode() {
223 let mut signed = arbitrary_signed_tx();
224 let signer = signed.signer;
225 signed.signer = Default::default(); let serialized = bincode::serde::encode_to_vec(&signed, standard()).unwrap();
228 let (deserialized, _): (Signed<Transaction>, _) =
229 bincode::serde::decode_from_slice(&serialized, standard()).unwrap();
230
231 assert_eq!(signed.signed, deserialized.signed);
232 assert_eq!(signer, deserialized.signer);
233 assert_eq!(signed.signature, deserialized.signature);
234 }
235
236 #[test]
237 fn signed_new_unchecked() {
238 let signed = arbitrary_signed_tx();
239
240 let new_signed = unsafe {
241 Signed::new_unchecked(signed.signed.clone(), signed.signature, signed.signer)
242 };
243
244 assert_eq!(new_signed, signed);
245 }
246}