anvil_core/eth/transaction/
optimism.rs
1use alloy_primitives::{Address, Bytes, TxKind, B256, U256};
2use alloy_rlp::{Decodable, Encodable, Error as DecodeError, Header as RlpHeader};
3use op_alloy_consensus::TxDeposit;
4use serde::{Deserialize, Serialize};
5
6pub const DEPOSIT_TX_TYPE_ID: u8 = 0x7E;
7
8impl From<DepositTransaction> for TxDeposit {
9 fn from(tx: DepositTransaction) -> Self {
10 Self {
11 from: tx.from,
12 source_hash: tx.source_hash,
13 to: tx.kind,
14 mint: Some(tx.mint.to::<u128>()),
15 value: tx.value,
16 gas_limit: tx.gas_limit,
17 is_system_transaction: tx.is_system_tx,
18 input: tx.input,
19 }
20 }
21}
22
23#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
26pub struct DepositTransaction {
27 pub nonce: u64,
28 pub source_hash: B256,
29 pub from: Address,
30 pub kind: TxKind,
31 pub mint: U256,
32 pub value: U256,
33 pub gas_limit: u64,
34 pub is_system_tx: bool,
35 pub input: Bytes,
36}
37
38impl DepositTransaction {
39 pub fn nonce(&self) -> &u64 {
40 &self.nonce
41 }
42
43 pub fn hash(&self) -> B256 {
44 let mut encoded = Vec::new();
45 self.encode_2718(&mut encoded);
46 B256::from_slice(alloy_primitives::keccak256(encoded).as_slice())
47 }
48
49 pub fn recover(&self) -> Result<Address, alloy_primitives::SignatureError> {
51 Ok(self.from)
52 }
53
54 pub fn chain_id(&self) -> Option<u64> {
55 None
56 }
57
58 pub fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
59 out.put_u8(DEPOSIT_TX_TYPE_ID);
60 self.encode(out);
61 }
62
63 pub(crate) fn encode_fields(&self, out: &mut dyn alloy_rlp::BufMut) {
65 self.source_hash.encode(out);
66 self.from.encode(out);
67 self.kind.encode(out);
68 self.mint.encode(out);
69 self.value.encode(out);
70 self.gas_limit.encode(out);
71 self.is_system_tx.encode(out);
72 self.input.encode(out);
73 }
74
75 pub(crate) fn fields_len(&self) -> usize {
77 let mut len = 0;
78 len += self.source_hash.length();
79 len += self.from.length();
80 len += self.kind.length();
81 len += self.mint.length();
82 len += self.value.length();
83 len += self.gas_limit.length();
84 len += self.is_system_tx.length();
85 len += self.input.length();
86 len
87 }
88
89 pub fn decode_2718(buf: &mut &[u8]) -> Result<Self, DecodeError> {
90 use bytes::Buf;
91
92 let tx_type = *buf.first().ok_or(alloy_rlp::Error::Custom("empty slice"))?;
93
94 if tx_type != DEPOSIT_TX_TYPE_ID {
95 return Err(alloy_rlp::Error::Custom("invalid tx type: expected deposit tx type"));
96 }
97
98 buf.advance(1);
100 Self::decode(buf)
101 }
102
103 pub fn decode_inner(buf: &mut &[u8]) -> Result<Self, DecodeError> {
117 Ok(Self {
118 nonce: 0,
119 source_hash: Decodable::decode(buf)?,
120 from: Decodable::decode(buf)?,
121 kind: Decodable::decode(buf)?,
122 mint: Decodable::decode(buf)?,
123 value: Decodable::decode(buf)?,
124 gas_limit: Decodable::decode(buf)?,
125 is_system_tx: Decodable::decode(buf)?,
126 input: Decodable::decode(buf)?,
127 })
128 }
129}
130
131impl Encodable for DepositTransaction {
132 fn encode(&self, out: &mut dyn bytes::BufMut) {
133 RlpHeader { list: true, payload_length: self.fields_len() }.encode(out);
134 self.encode_fields(out);
135 }
136}
137
138impl Decodable for DepositTransaction {
139 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
140 let header = RlpHeader::decode(buf)?;
141 let remaining_len = buf.len();
142 if header.payload_length > remaining_len {
143 return Err(alloy_rlp::Error::InputTooShort);
144 }
145
146 Self::decode_inner(buf)
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn test_encode_decode() {
156 let tx = DepositTransaction {
157 nonce: 0,
158 source_hash: B256::default(),
159 from: Address::default(),
160 kind: TxKind::Call(Address::default()),
161 mint: U256::from(100),
162 value: U256::from(100),
163 gas_limit: 50000,
164 is_system_tx: false,
165 input: Bytes::default(),
166 };
167
168 let encoded_tx: Vec<u8> = alloy_rlp::encode(&tx);
169
170 let decoded_tx = DepositTransaction::decode(&mut encoded_tx.as_slice()).unwrap();
171
172 assert_eq!(tx, decoded_tx);
173 }
174 #[test]
175 fn test_encode_decode_2718() {
176 let tx = DepositTransaction {
177 nonce: 0,
178 source_hash: B256::default(),
179 from: Address::default(),
180 kind: TxKind::Call(Address::default()),
181 mint: U256::from(100),
182 value: U256::from(100),
183 gas_limit: 50000,
184 is_system_tx: false,
185 input: Bytes::default(),
186 };
187
188 let mut encoded_tx: Vec<u8> = Vec::new();
189 tx.encode_2718(&mut encoded_tx);
190
191 let decoded_tx = DepositTransaction::decode_2718(&mut encoded_tx.as_slice()).unwrap();
192
193 assert_eq!(tx, decoded_tx);
194 }
195}