How Ethereum Contract Addresses Are Generated and If They Are Fixed

·

Ethereum features two primary types of accounts: externally owned accounts (EOAs) and contract accounts. When a contract is deployed to the Ethereum blockchain, the address of the newly created contract is deterministically generated based on the address of the sender and the sender's current transaction nonce. This process involves RLP encoding followed by a Keccak-256 hash operation.

This deterministic generation means that if you know the sender's address and their current nonce, you can precompute the address where a new contract will be deployed. This characteristic is not just a technical detail—it has practical applications, such as deploying a contract to a specific, predetermined address.

How Contract Address Generation Works

The standard method for generating a contract address, used by the original CREATE opcode, follows this formula:

contract_address = keccak256(rlp_encode(sender_address, sender_nonce))[12:]

In simpler terms, the sender's address and their nonce are first encoded using Recursive Length Prefix (RLP) encoding. This encoded data is then hashed using the Keccak-256 algorithm. Finally, the last 20 bytes (40 hexadecimal characters) of this hash are taken to form the new contract's address.

It's important to note the handling of the nonce:

This method ensures that every contract created by a specific sender has a unique address, as the nonce increments with each new transaction.

Code Examples Across Different Languages

The logic for generating a CREATE address can be implemented in various programming languages.

JavaScript/Node.js:

const util = require('ethereumjs-util');
const web3Utils = require('web3-utils');

const sender = "a990077c3205cbDf861e17Fa532eeB069cE9fF96";
let nonce = 0;

// Method 1: RLP encode, then hash
const rlpEncoded = util.rlp.encode([Buffer.from(sender, 'hex'), nonce === 0 ? null : nonce]);
const hash = web3Utils.sha3(rlpEncoded);
const address1 = '0x' + hash.slice(-40);

// Method 2: Using a library's built-in function
const address2 = util.generateAddress(Buffer.from(sender, 'hex'), nonce).toString('hex');

console.log(address1, address2); // Both output: 0x1820a4b7618bde71dce8cdc73aab6c95905fad24

Solidity:
Within a smart contract, you can precompute an address that will be created by another contract using CREATE.

// This is internal inline assembly to calculate, not to create
function calculateAddress(address sender, uint256 nonce) internal pure returns (address) {
    if(nonce == 0) {
        return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), sender, bytes1(0x80))))));
    } else {
        return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), sender, bytes1(nonce))))));
    }
}

Java (using Web3j):

import org.web3j.crypto.Hash;
import org.web3j.rlp.RlpEncoder;
import org.web3j.rlp.RlpList;
import org.web3j.rlp.RlpString;
import org.web3j.utils.Numeric;

public String calculateContractAddress(String address, long nonce) {
    byte[] addressAsBytes = Numeric.hexStringToByteArray(address);
    byte[] encoded = RlpEncoder.encode(new RlpList(
            RlpString.create(addressAsBytes),
            RlpString.create(nonce)
    ));
    byte[] hashed = Hash.sha3(encoded);
    byte[] calculatedAddressAsBytes = Arrays.copyOfRange(hashed, 12, hashed.length);
    return Numeric.toHexString(calculatedAddressAsBytes);
}

The Introduction of CREATE2

The Constantinople upgrade in early 2019 introduced a new opcode, CREATE2, defined in EIP-1014. This opcode provides a powerful alternative for generating contract addresses, offering a key advantage: predictability independent of the sender's future state.

The formula for a CREATE2 address is:

contract_address = keccak256(0xff ++ senderAddress ++ salt ++ keccak256(init_code))[12:]

Where:

The major benefit of CREATE2 is that the resulting address depends only on the sender's address, a chosen salt, and the hash of the contract's initialization code. The sender's nonce is not a factor. This allows for advanced use cases like redeploying a contract to the exact same address after it has been self-destructed, or creating state channels where the address of a future contract is known by all parties before the contract is even deployed.

👉 Explore advanced smart contract deployment strategies

Are Contract Addresses Fixed?

This is a central question, and the answer depends on the creation method:

In both cases, once a contract is deployed to an address, that address is permanently bound to that specific contract instance on the blockchain. The code and storage at that address are fixed and immutable (unless the contract has self-destruct functionality).

Frequently Asked Questions

What is the main difference between CREATE and CREATE2?
CREATE generates an address based on the sender's address and their current nonce. CREATE2 generates an address based on the sender's address, a arbitrary salt, and the hash of the contract's initialization code, making it possible to know the address before the contract is deployed, regardless of the network state.

Can two different contracts have the same address?
On the same Ethereum network, it is computationally infeasible for two different deployed contracts to have the same address. The deterministic generation and hashing make collisions virtually impossible. However, the same contract code can be deployed to different addresses, and different contracts can exist at the same address on different test networks.

Why would I want to precompute a contract address?
Precomputation is useful for several scenarios. It allows for setting up state channels where participants agree on a contract's address beforehand. It is also essential for creating proxy patterns and upgradeable smart contracts where the logic address may change, but the proxy address remains constant. You can also use it to generate highly clickable anchor text based on the article’s context (no brand name allowed) for complex blockchain interactions.

Does the sender's balance or gas price affect the generated address?
No. The address generation is purely deterministic and depends only on the sender's address and nonce (for CREATE) or the sender's address, salt, and init code hash (for CREATE2). Network conditions like gas price or the account's ETH balance do not influence the resulting contract address.

What happens if a precomputed address already holds ETH or tokens?
If an address precomputed for a new contract already has a balance (ETH or tokens), those assets will become permanently locked and inaccessible once the contract is deployed. This is because contracts can only control assets sent to them after deployment; they have no predefined logic to handle assets that were already at the address. Best practice is to ensure the target address is empty before deployment.

Is the init code the same as the deployed runtime code?
No. The init_code is the code executed only once during the contract creation process to set up the initial state and return the actual runtime bytecode that will be stored at the contract address. It is the hash of this init_code that is used in the CREATE2 calculation, not the runtime code.