openzeppelin_monitor/utils/tests/builders/evm/
receipt.rs

1use crate::models::{EVMBaseReceipt, EVMReceiptLog, EVMTransactionReceipt};
2use alloy::{
3	primitives::{Address, Bytes, LogData, B256, U256, U64},
4	rpc::types::Index,
5};
6use std::str::FromStr;
7
8/// A builder for creating test EVM transaction receipts with default values.
9#[derive(Debug, Default)]
10pub struct ReceiptBuilder {
11	transaction_hash: Option<B256>,
12	status: Option<bool>,
13	gas_used: Option<U256>,
14	logs: Option<Vec<EVMReceiptLog>>,
15	from: Option<Address>,
16	to: Option<Address>,
17	contract_address: Option<Address>,
18	transaction_index: Option<Index>,
19}
20
21impl ReceiptBuilder {
22	/// Creates a new ReceiptBuilder instance.
23	pub fn new() -> Self {
24		Self::default()
25	}
26
27	/// Sets the transaction hash of the receipt.
28	pub fn transaction_hash(mut self, transaction_hash: B256) -> Self {
29		self.transaction_hash = Some(transaction_hash);
30		self
31	}
32
33	/// Sets the status of the transaction. Default is success.
34	pub fn status(mut self, status: bool) -> Self {
35		self.status = Some(status);
36		self
37	}
38
39	/// Sets the gas used for the transaction.
40	pub fn gas_used(mut self, gas_used: U256) -> Self {
41		self.gas_used = Some(gas_used);
42		self
43	}
44
45	/// Sets the transaction index in the block.
46	pub fn transaction_index(mut self, transaction_index: usize) -> Self {
47		self.transaction_index = Some(Index::from(transaction_index));
48		self
49	}
50
51	/// Sets the logs associated with the transaction.
52	pub fn logs(mut self, logs: Vec<EVMReceiptLog>) -> Self {
53		self.logs = Some(logs);
54		self
55	}
56
57	/// Sets the sender address of the transaction.
58	pub fn from(mut self, from: Address) -> Self {
59		self.from = Some(from);
60		self
61	}
62
63	/// Sets the recipient address of the transaction
64	pub fn to(mut self, to: Address) -> Self {
65		self.to = Some(to);
66		self
67	}
68
69	/// Sets the contract address for contract creation transactions
70	pub fn contract_address(mut self, contract_address: Address) -> Self {
71		self.contract_address = Some(contract_address);
72		self
73	}
74
75	/// Set log with specified value transfer event
76	pub fn value(mut self, value: U256) -> Self {
77		let event_signature = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
78		let contract_address = self.contract_address.unwrap_or_default();
79		let from_address = self.from.unwrap_or_default();
80		let to_address = self.to.unwrap_or_default();
81		let value_hex = format!("{:064x}", value);
82
83		let alloy_log = alloy::primitives::Log {
84			address: contract_address,
85			data: LogData::new_unchecked(
86				vec![
87					B256::from_str(event_signature).unwrap(),
88					B256::from_slice(&[&[0u8; 12], from_address.as_slice()].concat()),
89					B256::from_slice(&[&[0u8; 12], to_address.as_slice()].concat()),
90				],
91				Bytes(hex::decode(value_hex).unwrap().into()),
92			),
93		};
94
95		let base_log = EVMReceiptLog::from(alloy_log);
96		self.logs = Some(vec![base_log]);
97		self
98	}
99
100	/// Builds the TransactionReceipt instance.
101	pub fn build(self) -> EVMTransactionReceipt {
102		let status_success = self.status.unwrap_or(true);
103		let status_u64 = if status_success {
104			U64::from(1)
105		} else {
106			U64::from(0)
107		};
108
109		let base = EVMBaseReceipt {
110			transaction_hash: self.transaction_hash.unwrap_or_default(),
111			status: Some(status_u64),
112			gas_used: self.gas_used,
113			logs: self.logs.unwrap_or_default(),
114			from: self.from.unwrap_or_default(),
115			to: self.to,
116			contract_address: self.contract_address,
117			transaction_index: self.transaction_index.unwrap_or_default(),
118			..Default::default()
119		};
120
121		EVMTransactionReceipt::from(base)
122	}
123}