foundry_evm_networks/celo/
transfer.rs1use std::borrow::Cow;
15
16use alloy_evm::precompiles::{DynPrecompile, PrecompileInput};
17use alloy_primitives::{Address, U256, address};
18use revm::precompile::{PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult};
19
20pub const CELO_TRANSFER_ADDRESS: Address = address!("0x00000000000000000000000000000000000000fd");
22
23pub static PRECOMPILE_ID_CELO_TRANSFER: PrecompileId =
25 PrecompileId::Custom(Cow::Borrowed("celo transfer"));
26
27const CELO_TRANSFER_GAS_COST: u64 = 9000;
29
30pub fn precompile() -> DynPrecompile {
32 DynPrecompile::new_stateful(PRECOMPILE_ID_CELO_TRANSFER.clone(), celo_transfer_precompile)
33}
34
35pub fn celo_transfer_precompile(input: PrecompileInput<'_>) -> PrecompileResult {
39 if input.gas < CELO_TRANSFER_GAS_COST {
41 return Err(PrecompileError::OutOfGas);
42 }
43
44 if input.data.len() != 96 {
46 return Err(PrecompileError::Other(format!(
47 "Invalid input length for Celo transfer precompile: expected 96 bytes, got {}",
48 input.data.len()
49 )));
50 }
51
52 let from_bytes = &input.data[12..32];
54 let to_bytes = &input.data[44..64];
55 let value_bytes = &input.data[64..96];
56
57 let from_address = Address::from_slice(from_bytes);
58 let to_address = Address::from_slice(to_bytes);
59 let value = U256::from_be_slice(value_bytes);
60
61 let mut internals = input.internals;
63
64 {
66 let from_account = match internals.load_account(from_address) {
67 Ok(account) => account,
68 Err(e) => {
69 return Err(PrecompileError::Other(format!("Failed to load from account: {e:?}")));
70 }
71 };
72
73 if from_account.data.info.balance < value {
75 return Err(PrecompileError::Other("Insufficient balance".into()));
76 }
77
78 from_account.data.info.balance -= value;
80 }
81
82 {
84 let to_account = match internals.load_account(to_address) {
85 Ok(account) => account,
86 Err(e) => {
87 return Err(PrecompileError::Other(format!("Failed to load to account: {e:?}")));
88 }
89 };
90
91 if to_account.data.info.balance.checked_add(value).is_none() {
93 return Err(PrecompileError::Other("Balance overflow in to account".into()));
94 }
95
96 to_account.data.info.balance += value;
98 }
99
100 Ok(PrecompileOutput::new(CELO_TRANSFER_GAS_COST, alloy_primitives::Bytes::new()))
102}