use crate::address::Address;
use crate::rlp::{pack_rlp, RlpToken};
use num256::Uint256;
use sha3::{Digest, Keccak256};
pub fn calculate_contract_address(deployer: Address, nonce: Uint256) -> Address {
let rlp_data = pack_rlp(vec![RlpToken::List(vec![
RlpToken::String(deployer.as_bytes().to_vec()),
RlpToken::from(nonce),
])]);
let hash = Keccak256::digest(&rlp_data);
Address::from_slice(&hash[12..]).expect("Slice is exactly 20 bytes")
}
pub fn calculate_contract_address_create2(
deployer: Address,
salt: [u8; 32],
init_code_hash: [u8; 32],
) -> Address {
let mut data = Vec::with_capacity(85);
data.push(0xff);
data.extend_from_slice(deployer.as_bytes());
data.extend_from_slice(&salt);
data.extend_from_slice(&init_code_hash);
let hash = Keccak256::digest(&data);
Address::from_slice(&hash[12..]).expect("Slice is exactly 20 bytes")
}
pub fn hash_init_code(init_code: &[u8]) -> [u8; 32] {
let hash = Keccak256::digest(init_code);
let mut result = [0u8; 32];
result.copy_from_slice(&hash);
result
}
pub fn validate_init_code_size(init_code: &[u8]) -> bool {
const MAX_INIT_CODE_SIZE: usize = 49_152; init_code.len() <= MAX_INIT_CODE_SIZE
}
pub fn calculate_init_code_gas(init_code_size: usize) -> Uint256 {
const GAS_PER_WORD: u64 = 2;
const WORD_SIZE: usize = 32;
let words = init_code_size.div_ceil(WORD_SIZE);
Uint256::from(words as u64) * Uint256::from(GAS_PER_WORD)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::utils::bytes_to_hex_str;
#[test]
fn test_calculate_contract_address_nonce_0() {
let deployer: Address = "0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0"
.parse()
.unwrap();
let nonce = Uint256::from(0u8);
let expected: Address = "0xcd234a471b72ba2f1ccf0a70fcaba648a5eecd8d"
.parse()
.unwrap();
let result = calculate_contract_address(deployer, nonce);
assert_eq!(result, expected);
}
#[test]
fn test_calculate_contract_address_nonce_1() {
let deployer: Address = "0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0"
.parse()
.unwrap();
let nonce = Uint256::from(1u8);
let expected: Address = "0x343c43a37d37dff08ae8c4a11544c718abb4fcf8"
.parse()
.unwrap();
let result = calculate_contract_address(deployer, nonce);
assert_eq!(result, expected);
}
#[test]
fn test_calculate_contract_address_nonce_2() {
let deployer: Address = "0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0"
.parse()
.unwrap();
let nonce = Uint256::from(2u8);
let expected: Address = "0xf778b86fa74e846c4f0a1fbd1335fe81c00a0c91"
.parse()
.unwrap();
let result = calculate_contract_address(deployer, nonce);
assert_eq!(result, expected);
}
#[test]
fn test_calculate_contract_address_high_nonce() {
let deployer: Address = "0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0"
.parse()
.unwrap();
let nonce = Uint256::from(1000u32);
let result = calculate_contract_address(deployer, nonce);
assert_eq!(result.as_bytes().len(), 20);
}
#[test]
fn test_calculate_contract_address_create2_zero() {
let deployer: Address = "0x0000000000000000000000000000000000000000"
.parse()
.unwrap();
let salt = [0u8; 32];
let init_code_hash = [0u8; 32];
let expected: Address = "0xffc4f52f884a02bcd5716744cd622127366f2edf"
.parse()
.unwrap();
let result = calculate_contract_address_create2(deployer, salt, init_code_hash);
assert_eq!(result, expected);
}
#[test]
fn test_calculate_contract_address_create2_custom() {
let deployer: Address = "0xdeadbeef00000000000000000000000000000000"
.parse()
.unwrap();
let salt = [0u8; 32];
let init_code_hash = [0u8; 32];
let expected: Address = "0x85f15e045e1244ac03289b48448249dc0a34aa30"
.parse()
.unwrap();
let result = calculate_contract_address_create2(deployer, salt, init_code_hash);
assert_eq!(result, expected);
}
#[test]
fn test_calculate_contract_address_create2_different_salt() {
let deployer: Address = "0x0000000000000000000000000000000000000000"
.parse()
.unwrap();
let mut salt = [0u8; 32];
salt[31] = 1; let init_code_hash = [0u8; 32];
let result1 = calculate_contract_address_create2(deployer, [0u8; 32], init_code_hash);
let result2 = calculate_contract_address_create2(deployer, salt, init_code_hash);
assert_ne!(result1, result2);
}
#[test]
fn test_hash_init_code() {
let init_code = vec![0x60, 0x80, 0x60, 0x40, 0x52];
let hash = hash_init_code(&init_code);
assert_eq!(hash.len(), 32);
let hash2 = hash_init_code(&init_code);
assert_eq!(hash, hash2);
let different_code = vec![0x60, 0x80, 0x60, 0x40, 0x53];
let hash3 = hash_init_code(&different_code);
assert_ne!(hash, hash3);
}
#[test]
fn test_hash_init_code_empty() {
let init_code = vec![];
let hash = hash_init_code(&init_code);
assert_eq!(hash.len(), 32);
let expected = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470";
assert_eq!(bytes_to_hex_str(&hash), expected);
}
#[test]
fn test_validate_init_code_size_valid() {
let code = vec![0u8; 1000]; assert!(validate_init_code_size(&code));
let code = vec![0u8; 49_152]; assert!(validate_init_code_size(&code));
}
#[test]
fn test_validate_init_code_size_invalid() {
let code = vec![0u8; 49_153]; assert!(!validate_init_code_size(&code));
let code = vec![0u8; 100_000]; assert!(!validate_init_code_size(&code));
}
#[test]
fn test_validate_init_code_size_empty() {
let code = vec![];
assert!(validate_init_code_size(&code));
}
#[test]
fn test_calculate_init_code_gas() {
assert_eq!(calculate_init_code_gas(0), Uint256::from(0u8));
assert_eq!(calculate_init_code_gas(1), Uint256::from(2u8));
assert_eq!(calculate_init_code_gas(32), Uint256::from(2u8));
assert_eq!(calculate_init_code_gas(33), Uint256::from(4u8));
assert_eq!(calculate_init_code_gas(64), Uint256::from(4u8));
assert_eq!(calculate_init_code_gas(100), Uint256::from(8u8));
assert_eq!(calculate_init_code_gas(1000), Uint256::from(64u8));
}
#[test]
fn test_calculate_init_code_gas_max_size() {
assert_eq!(calculate_init_code_gas(49_152), Uint256::from(3072u64));
}
}