1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
use alloy_eips::eip2718::Encodable2718;
use alloy_primitives::{bytes, Address, B256};
use alloy_rlp::{Decodable, Encodable};
use derive_more::{AsRef, Deref};
/// Signed transaction with recovered signer.
#[derive(Debug, Clone, PartialEq, Hash, Eq, AsRef, Deref)]
pub struct Recovered<T> {
/// Signer of the transaction
signer: Address,
/// Signed transaction
#[deref]
#[as_ref]
tx: T,
}
impl<T> Recovered<T> {
/// Signer of transaction recovered from signature
pub const fn signer(&self) -> Address {
self.signer
}
/// Reference to the signer of transaction recovered from signature
pub const fn signer_ref(&self) -> &Address {
&self.signer
}
/// Returns a reference to the transaction.
pub const fn tx(&self) -> &T {
&self.tx
}
/// Transform back to the transaction.
pub fn into_tx(self) -> T {
self.tx
}
/// Clone the inner transaction.
pub fn clone_tx(&self) -> T
where
T: Clone,
{
self.tx.clone()
}
/// Dissolve Self to its component
pub fn into_parts(self) -> (T, Address) {
(self.tx, self.signer)
}
/// Create [`Recovered`] from the given transaction and [`Address`] of the signer.
///
/// Note: This does not check if the signer is the actual signer of the transaction.
#[inline]
pub const fn new_unchecked(tx: T, signer: Address) -> Self {
Self { tx, signer }
}
/// Applies the given closure to the inner transactions.
pub fn map_transaction<Tx>(self, f: impl FnOnce(T) -> Tx) -> Recovered<Tx> {
Recovered::new_unchecked(f(self.tx), self.signer)
}
}
impl<T: Encodable> Encodable for Recovered<T> {
/// This encodes the transaction _with_ the signature, and an rlp header.
fn encode(&self, out: &mut dyn bytes::BufMut) {
self.tx.encode(out)
}
fn length(&self) -> usize {
self.tx.length()
}
}
impl<T: Decodable + SignerRecoverable> Decodable for Recovered<T> {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let tx = T::decode(buf)?;
let signer = tx.recover_signer().map_err(|_| {
alloy_rlp::Error::Custom("Unable to recover decoded transaction signer.")
})?;
Ok(Self::new_unchecked(tx, signer))
}
}
impl<T: Encodable2718> Encodable2718 for Recovered<T> {
fn type_flag(&self) -> Option<u8> {
self.tx.type_flag()
}
fn encode_2718_len(&self) -> usize {
self.tx.encode_2718_len()
}
fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
self.tx.encode_2718(out)
}
fn trie_hash(&self) -> B256 {
self.tx.trie_hash()
}
}
/// A type that can recover the signer of a transaction.
///
/// This is a helper trait that only provides the ability to recover the signer (address) of a
/// transaction.
pub trait SignerRecoverable {
/// Recover signer from signature and hash.
///
/// Returns an error if the transaction's signature is invalid following [EIP-2](https://eips.ethereum.org/EIPS/eip-2).
///
/// Note:
///
/// This can fail for some early ethereum mainnet transactions pre EIP-2, use
/// [`Self::recover_signer_unchecked`] if you want to recover the signer without ensuring that
/// the signature has a low `s` value.
fn recover_signer(&self) -> Result<Address, alloy_primitives::SignatureError>;
/// Recover signer from signature and hash _without ensuring that the signature has a low `s`
/// value_.
///
/// Returns an error if the transaction's signature is invalid.
fn recover_signer_unchecked(&self) -> Result<Address, alloy_primitives::SignatureError>;
}