anvil/evm/
celo_precompile.rs1use alloy_evm::precompiles::{DynPrecompile, PrecompileInput};
15use alloy_primitives::{Address, U256, address};
16use revm::precompile::{PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult};
17
18pub const CELO_TRANSFER_ADDRESS: Address = address!("0x00000000000000000000000000000000000000fd");
19
20const CELO_TRANSFER_GAS_COST: u64 = 9000;
22
23pub fn precompile() -> DynPrecompile {
25 DynPrecompile::new_stateful(PrecompileId::custom("celo transfer"), celo_transfer_precompile)
26}
27
28pub fn celo_transfer_precompile(input: PrecompileInput<'_>) -> PrecompileResult {
32 if input.gas < CELO_TRANSFER_GAS_COST {
34 return Err(PrecompileError::OutOfGas);
35 }
36
37 if input.data.len() != 96 {
39 return Err(PrecompileError::Other(format!(
40 "Invalid input length for Celo transfer precompile: expected 96 bytes, got {}",
41 input.data.len()
42 )));
43 }
44
45 let from_bytes = &input.data[12..32];
47 let to_bytes = &input.data[44..64];
48 let value_bytes = &input.data[64..96];
49
50 let from_address = Address::from_slice(from_bytes);
51 let to_address = Address::from_slice(to_bytes);
52 let value = U256::from_be_slice(value_bytes);
53
54 let mut internals = input.internals;
56
57 {
59 let from_account = match internals.load_account(from_address) {
60 Ok(account) => account,
61 Err(e) => {
62 return Err(PrecompileError::Other(format!("Failed to load from account: {e:?}")));
63 }
64 };
65
66 if from_account.data.info.balance < value {
68 return Err(PrecompileError::Other("Insufficient balance".into()));
69 }
70
71 from_account.data.info.balance -= value;
73 }
74
75 {
77 let to_account = match internals.load_account(to_address) {
78 Ok(account) => account,
79 Err(e) => {
80 return Err(PrecompileError::Other(format!("Failed to load to account: {e:?}")));
81 }
82 };
83
84 if to_account.data.info.balance.checked_add(value).is_none() {
86 return Err(PrecompileError::Other("Balance overflow in to account".into()));
87 }
88
89 to_account.data.info.balance += value;
91 }
92
93 Ok(PrecompileOutput::new(CELO_TRANSFER_GAS_COST, alloy_primitives::Bytes::new()))
95}