tempo_primitives/transaction/
key_authorization.rs1use super::SignatureType;
2use crate::transaction::PrimitiveSignature;
3use alloy_consensus::crypto::RecoveryError;
4use alloy_primitives::{Address, B256, U256, keccak256};
5use alloy_rlp::Encodable;
6use core::mem;
7use reth_primitives_traits::InMemorySize;
8
9#[derive(Clone, Debug, PartialEq, Eq, Hash, alloy_rlp::RlpEncodable, alloy_rlp::RlpDecodable)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
16#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
17#[cfg_attr(feature = "reth-codec", derive(reth_codecs::Compact))]
18#[cfg_attr(test, reth_codecs::add_arbitrary_tests(compact, rlp))]
19pub struct TokenLimit {
20 pub token: Address,
22
23 pub limit: U256,
25}
26
27#[derive(Clone, Debug, PartialEq, Eq, Hash, alloy_rlp::RlpEncodable, alloy_rlp::RlpDecodable)]
37#[rlp(trailing)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
39#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
40#[cfg_attr(test, reth_codecs::add_arbitrary_tests(rlp))]
41pub struct KeyAuthorization {
42 pub chain_id: u64,
44
45 pub key_type: SignatureType,
47
48 pub key_id: Address,
50
51 pub expiry: Option<u64>,
55
56 pub limits: Option<Vec<TokenLimit>>,
61}
62
63impl KeyAuthorization {
64 pub fn signature_hash(&self) -> B256 {
66 let mut buf = Vec::new();
67 self.encode(&mut buf);
68 keccak256(&buf)
69 }
70
71 pub fn has_unlimited_spending(&self) -> bool {
73 self.limits.is_none()
74 }
75
76 pub fn never_expires(&self) -> bool {
78 self.expiry.is_none()
79 }
80
81 pub fn into_signed(self, signature: PrimitiveSignature) -> SignedKeyAuthorization {
83 SignedKeyAuthorization {
84 authorization: self,
85 signature,
86 }
87 }
88}
89
90impl InMemorySize for KeyAuthorization {
91 fn size(&self) -> usize {
92 mem::size_of::<u64>() + mem::size_of::<u8>() + mem::size_of::<Address>() + mem::size_of::<Option<u64>>() + self.limits.as_ref().map_or(0, |limits| {
97 limits.iter().map(|_limit| {
98 mem::size_of::<Address>() + mem::size_of::<U256>()
99 }).sum::<usize>()
100 })
101 }
102}
103
104#[derive(
106 Clone,
107 Debug,
108 PartialEq,
109 Eq,
110 Hash,
111 alloy_rlp::RlpEncodable,
112 alloy_rlp::RlpDecodable,
113 derive_more::Deref,
114)]
115#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
116#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
117#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
118#[rlp(trailing)]
119#[cfg_attr(test, reth_codecs::add_arbitrary_tests(compact, rlp))]
120pub struct SignedKeyAuthorization {
121 #[cfg_attr(feature = "serde", serde(flatten))]
123 #[deref]
124 pub authorization: KeyAuthorization,
125
126 pub signature: PrimitiveSignature,
128}
129
130impl SignedKeyAuthorization {
131 pub fn recover_signer(&self) -> Result<Address, RecoveryError> {
133 self.signature
134 .recover_signer(&self.authorization.signature_hash())
135 }
136}
137
138#[cfg(feature = "reth-codec")]
139impl reth_codecs::Compact for SignedKeyAuthorization {
140 fn to_compact<B>(&self, buf: &mut B) -> usize
141 where
142 B: alloy_rlp::BufMut + AsMut<[u8]>,
143 {
144 self.encode(buf);
146 self.length()
147 }
148
149 fn from_compact(mut buf: &[u8], _len: usize) -> (Self, &[u8]) {
150 let item = alloy_rlp::Decodable::decode(&mut buf)
151 .expect("Failed to decode KeyAuthorization from compact");
152 (item, buf)
153 }
154}
155
156impl reth_primitives_traits::InMemorySize for SignedKeyAuthorization {
157 fn size(&self) -> usize {
158 self.authorization.size() + self.signature.size()
159 }
160}
161
162#[cfg(any(test, feature = "arbitrary"))]
163impl<'a> arbitrary::Arbitrary<'a> for KeyAuthorization {
164 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
165 Ok(Self {
166 chain_id: u.arbitrary()?,
167 key_type: u.arbitrary()?,
168 key_id: u.arbitrary()?,
169 expiry: u.arbitrary::<Option<u64>>()?.filter(|v| *v != 0),
171 limits: u.arbitrary()?,
172 })
173 }
174}