diff --git a/crates/primitives/src/contract.rs b/crates/primitives/src/contract.rs
new file mode 100644
index 0000000000..fe8ddc3575
--- /dev/null
+++ b/crates/primitives/src/contract.rs
@@ -0,0 +1,147 @@
+//! Helpers for deriving contract addresses
+
+use crate::{keccak256, Address, H256, U256};
+use reth_rlp::Encodable;
+use reth_rlp_derive::RlpEncodable;
+
+/// The address for an Ethereum contract is deterministically computed from the
+/// address of its creator (sender) and how many transactions the creator has
+/// sent (nonce). The sender and nonce are RLP encoded and then hashed with Keccak-256.
+pub fn get_contract_address(sender: impl Into
, nonce: impl Into) -> Address {
+ #[derive(RlpEncodable)]
+ struct S {
+ sender: Address,
+ nonce: U256,
+ }
+ let sender = S { sender: sender.into(), nonce: nonce.into() };
+ let mut buf = Vec::new();
+ sender.encode(&mut buf);
+ let hash = keccak256(buf);
+ let addr: [u8; 20] = hash[12..].try_into().expect("correct len");
+ Address::from(addr)
+}
+
+/// Returns the CREATE2 address of a smart contract as specified in
+/// [EIP1014](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1014.md)
+///
+/// keccak256( 0xff ++ senderAddress ++ salt ++ keccak256(init_code))[12..]
+///
+/// where `salt` is always 32 bytes (a stack item).
+pub fn get_create2_address(
+ from: impl Into,
+ salt: [u8; 32],
+ init_code: impl AsRef<[u8]>,
+) -> Address {
+ let init_code_hash = keccak256(init_code);
+ get_create2_address_from_hash(from, salt, init_code_hash)
+}
+
+/// Returns the CREATE2 address of a smart contract as specified in
+/// [EIP1014](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1014.md),
+/// taking the pre-computed hash of the init code as input.
+///
+/// keccak256( 0xff ++ senderAddress ++ salt ++ keccak256(init_code))[12..]
+pub fn get_create2_address_from_hash(
+ from: impl Into,
+ salt: [u8; 32],
+ init_code_hash: impl Into,
+) -> Address {
+ let from = from.into();
+ let init_code_hash = init_code_hash.into();
+ // always 85 bytes: 0xff+20+salt+code_hash
+ let mut preimage = [0xff; 85];
+
+ // 20bytes address
+ preimage[1..21].copy_from_slice(from.as_bytes());
+ // 32bytes salt
+ preimage[21..53].copy_from_slice(&salt[..]);
+ // 32bytes code hash
+ preimage[53..].copy_from_slice(init_code_hash.as_ref());
+
+ let hash = keccak256(&preimage[..]);
+ let addr: [u8; 20] = hash[12..].try_into().expect("correct len");
+ Address::from(addr)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn contract_address() {
+ // http://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed
+ let from = "6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0".parse::().unwrap();
+ for (nonce, expected) in [
+ "cd234a471b72ba2f1ccf0a70fcaba648a5eecd8d",
+ "343c43a37d37dff08ae8c4a11544c718abb4fcf8",
+ "f778b86fa74e846c4f0a1fbd1335fe81c00a0c91",
+ "fffd933a0bc612844eaf0c6fe3e5b8e9b6c1d19c",
+ ]
+ .iter()
+ .enumerate()
+ {
+ let address = get_contract_address(from, U256::from(nonce));
+ assert_eq!(address, expected.parse::().unwrap());
+ }
+ }
+
+ #[test]
+ // Test vectors from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1014.md#examples
+ fn create2_address() {
+ for (from, salt, init_code, expected) in &[
+ (
+ "0000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "00",
+ "4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38",
+ ),
+ (
+ "deadbeef00000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "00",
+ "B928f69Bb1D91Cd65274e3c79d8986362984fDA3",
+ ),
+ (
+ "deadbeef00000000000000000000000000000000",
+ "000000000000000000000000feed000000000000000000000000000000000000",
+ "00",
+ "D04116cDd17beBE565EB2422F2497E06cC1C9833",
+ ),
+ (
+ "0000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "deadbeef",
+ "70f2b2914A2a4b783FaEFb75f459A580616Fcb5e",
+ ),
+ (
+ "00000000000000000000000000000000deadbeef",
+ "00000000000000000000000000000000000000000000000000000000cafebabe",
+ "deadbeef",
+ "60f3f640a8508fC6a86d45DF051962668E1e8AC7",
+ ),
+ (
+ "00000000000000000000000000000000deadbeef",
+ "00000000000000000000000000000000000000000000000000000000cafebabe",
+ "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
+ "1d8bfDC5D46DC4f61D6b6115972536eBE6A8854C",
+ ),
+ (
+ "0000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "",
+ "E33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0",
+ ),
+ ] {
+ // get_create2_address()
+ let from = from.parse::().unwrap();
+ let salt = hex::decode(salt).unwrap();
+ let init_code = hex::decode(init_code).unwrap();
+ let expected = expected.parse::().unwrap();
+ assert_eq!(expected, get_create2_address(from, salt.clone().try_into().unwrap(), init_code.clone()));
+
+ // get_create2_address_from_hash()
+ let init_code_hash = keccak256(init_code);
+ assert_eq!(expected, get_create2_address_from_hash(from, salt.try_into().unwrap(), init_code_hash))
+ }
+ }
+}
diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs
index 5a53052812..4685244ccb 100644
--- a/crates/primitives/src/lib.rs
+++ b/crates/primitives/src/lib.rs
@@ -15,6 +15,7 @@ mod block;
pub mod bloom;
mod chain;
pub mod constants;
+pub mod contract;
mod error;
pub mod filter;
mod forkid;