133

How is the address of an Ethereum contract computed? What use cases are there for knowing a contract's address in advance?

1
  • In addition to @eth answer it should be noted that you take last 20 bytes. Apr 17, 2018 at 17:54

7 Answers 7

142

EDIT Sept 2023: CREATE2 information clarified.

EDIT January 2022: Updated Solidity syntax to ^0.8.0.

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.

From pyethereum:

def mk_contract_address(sender, nonce):
    return sha3(rlp.encode([normalize_address(sender), nonce]))[12:]

In Solidity:

nonce0= address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, bytes1(0x80))))));
nonce1= address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, bytes1(0x01))))));

Example with some discussion:

For sender 0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0, the contract addresses that it will create are the following:

nonce0= "0xcd234a471b72ba2f1ccf0a70fcaba648a5eecd8d"
nonce1= "0x343c43a37d37dff08ae8c4a11544c718abb4fcf8"
nonce2= "0xf778b86fa74e846c4f0a1fbd1335fe81c00a0c91"
nonce3= "0xfffd933a0bc612844eaf0c6fe3e5b8e9b6c1d19c"

In Java with Web3j:

private String calculateContractAddress(String address, long nonce){
    byte[] addressAsBytes = Numeric.hexStringToByteArray(address);

    byte[] calculatedAddressAsBytes =
            Hash.sha3(RlpEncoder.encode(
                    new RlpList(
                            RlpString.create(addressAsBytes),
                            RlpString.create((nonce)))));

    calculatedAddressAsBytes = Arrays.copyOfRange(calculatedAddressAsBytes,
            12, calculatedAddressAsBytes.length);
    String calculatedAddressAsHex = Numeric.toHexString(calculatedAddressAsBytes);
    return calculatedAddressAsHex;
}

Note: As per EIP 161 A Specification contract accounts are initiated with nonce = 1 (in the mainnet). So the first contract address, created by another contract, will be computed with non-zero nonce.


CREATE2

A new opcode, CREATE2 was added in EIP-1014 that is another way that a contract can be created.

For contract created by CREATE2 its address will be:

keccak256( 0xff ++ address(this) ++ salt ++ keccak256(init_code))[12:]

More information will be added here and for the meantime see EIP-1014.

16
  • 6
    For the usecase part, you could mention something about prefunding contracts Jan 30, 2016 at 2:11
  • 4
    What if the creator is a contract itself? Has the address also a nonce? Is it increased by every call it makes or only with the creation of new contacts? Or is the address and nonce of tx.origin relevant? Jan 30, 2016 at 5:41
  • 3
    @mKoeppelmann: Same computation if creator is a contract; nonce increases every single transaction an account makes (new contract/account would start at nonce 0), and the address and nonce of earlier senders (such as tx.origin) do not affect address of new contract.
    – eth
    Jan 30, 2016 at 7:04
  • 2
    @eth: "nonce increases every single transaction" this is what confuses me, because in the definition in the yellowpaper only human controlled accounts can make transactions. A transaction is something that is signed with a private key. Contracts can only make calls that are triggered by transactions. So I wonder what "calls" increase the nonce of a contract. All calls or only calls that create a new contract? Jan 30, 2016 at 19:21
  • 3
    @StevenRoose Yes, contracts have nonces. A nonce of a contract is only incremented when that contract creates another contract. It's in separate question Martin asked ethereum.stackexchange.com/questions/764/… :)
    – eth
    Jul 17, 2017 at 20:08
19

Thanks to eth's answer, it helped a lot to resolve $2000 issue.

Just solved issue with funds, which were sent in main Ethereum network to address of smart contract, deployed to test Ethereum network. We used same wallet to deploy different smart contract in main Ethereum network several times until transaction field nonce achieved the same value 13, as were used to deploy on test network. We called special method of freshly deployed smart contract to reclaim funds. So smart contract was deployed after it was really funded: https://etherscan.io/address/0x9c86825280b1d6c7dB043D4CC86E1549990149f9

Just finished an article about this issue: https://medium.com/@k06a/how-we-sent-eth-to-the-wrong-address-and-successfully-recovered-them-2fc18e09d8f6

enter image description here

4
  • Thanks.. but what if the mainnet contract owner has current nonce higher than the one was used to create contract in testnet. I have same situation as your.. but only probelm is that my main net owner wallet has latest nonce 236 and testnet contract was created at 13 nonce.. is there any way to override and deploy contract having previous nonce? Mar 15, 2019 at 10:52
  • 1
    At current gas fees, you would pay a fortune to deploy the contract 12 times, before you got to 13. Why did you not set the nonce to 13 right away?
    – Qwerty
    Dec 20, 2021 at 18:16
  • @Qwerty you can set a nonce yourself for deployment?
    – Sky
    Feb 1, 2022 at 9:51
  • @Sky Yes, in metamask when confirming the transaction. I just tried it with REMIX. If you don't see it in Metamask, enable advanced options.
    – Qwerty
    Feb 2, 2022 at 16:03
13

Here's a node.js script that deterministically computes an Ethereum contract address given the contract creator's public address and nonce value.

Let me know if anyone has questions about inputs, etc.

// node version: v9.10.0
// module versions:
// [email protected]
// [email protected]

const rlp = require("rlp");
const keccak = require("keccak");

var nonce = 0x00; //The nonce must be a hex literal!
var sender = "0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0"; //Requires a hex string as input!

var input_arr = [sender, nonce];
var rlp_encoded = rlp.encode(input_arr);

var contract_address_long = keccak("keccak256")
  .update(rlp_encoded)
  .digest("hex");

var contract_address = contract_address_long.substring(24); //Trim the first 24 characters.
console.log("contract_address: " + contract_address);

Note that the nonce can be incremented normally, just remember that it's a hex value.

Output (nonce = 0x00):

contract_address: cd234a471b72ba2f1ccf0a70fcaba648a5eecd8d

Output (nonce = 0x01):

contract_address: 343c43a37d37dff08ae8c4a11544c718abb4fcf8
2
6

Here is updated Python version for modern Ethereum libraries (eth-utils):

import rlp
from eth_utils import keccak, to_checksum_address, to_bytes


def mk_contract_address(sender: str, nonce: int) -> str:
    """Create a contract address using eth-utils.

    # https://ethereum.stackexchange.com/a/761/620
    """
    sender_bytes = to_bytes(hexstr=sender)
    raw = rlp.encode([sender_bytes, nonce])
    h = keccak(raw)
    address_bytes = h[12:]
    return to_checksum_address(address_bytes)


print(to_checksum_address(mk_contract_address(to_checksum_address("0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0"), 1)))
print("0x343c43a37d37dff08ae8c4a11544c718abb4fcf8")
assert mk_contract_address(to_checksum_address("0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0"), 1) == \
    to_checksum_address("0x343c43a37d37dff08ae8c4a11544c718abb4fcf8")
4

RLP done in solidity (did not test this though, beware! just for understanding):

    function addressFrom(address _origin, uint _nonce) public pure returns (address) {
        if(_nonce == 0x00)     return address(keccak256(byte(0xd6), byte(0x94), _origin, byte(0x80)));
        if(_nonce <= 0x7f)     return address(keccak256(byte(0xd6), byte(0x94), _origin, byte(_nonce)));
        if(_nonce <= 0xff)     return address(keccak256(byte(0xd7), byte(0x94), _origin, byte(0x81), uint8(_nonce)));
        if(_nonce <= 0xffff)   return address(keccak256(byte(0xd8), byte(0x94), _origin, byte(0x82), uint16(_nonce)));
        if(_nonce <= 0xffffff) return address(keccak256(byte(0xd9), byte(0x94), _origin, byte(0x83), uint24(_nonce)));
        return address(keccak256(byte(0xda), byte(0x94), _origin, byte(0x84), uint32(_nonce))); // more than 2^32 nonces not realistic
    }
4
  • 1
    thanks for sharing, wonder where did you get those magic numbers: 0x7f, 0xd6, 0x94
    – DiveInto
    Jul 28, 2018 at 13:44
  • 1
  • The nonce can never be 0, so that first test can be removed. Nov 15, 2018 at 9:48
  • Nonce starts with zero, see transactions on etherscan.
    – Alex
    Nov 19, 2018 at 10:09
1

Here is a pure ethers.js implementation in TypeScript, returning a checksummed address. nonce is expected to be a regular number.

(ethers.js does have a function called getContractAddress too, but it cannot be used for any nonce)

import { ethers } from 'hardhat';

static getContractAddress(address: string, nonce: number): string {
    const rlp_encoded = ethers.utils.RLP.encode(
        [address, ethers.BigNumber.from(nonce.toString()).toHexString()]
    );
    const contract_address_long = ethers.utils.keccak256(rlp_encoded);
    const contract_address = '0x'.concat(contract_address_long.substring(26));
    return ethers.utils.getAddress(contract_address);
}

2
  • This implementation works in case the nonce is greater than 0. For nonce = 0 the result is not correct (see example and compare with result of the top answer). A simple one-liner that works correctly in ethers.js is const contractAddress = ethers.utils.getContractAddress({from, nonce});
    – GongFu
    Jan 4, 2022 at 21:48
  • @GongFu yes, better to use the in-built function. At the time I believe I was using an outdated version of Ethers that did not have this function.
    – riordant
    Jan 7, 2022 at 2:10
1

The contract address is typically a hash of the sender's address and sender's wallet nonce. The actual contract code doesn't make any difference - the hash is the same regardless of the code.

Above I said typically because there are other ways of deploying contracts. If an existing contract deploys a contract with a special opcode CREATE2 the contract address is calculated a bit differently.

You can check details for example here: https://medium.com/coinmonks/smart-contract-address-creation-method-difference-between-smart-contract-address-and-wallet-97b421506455

3
  • Upvoted but merging with earlier question to gather answers together.
    – eth
    Oct 14, 2022 at 1:33
  • I already started wondering did I accidentally answer a question with valid previous answers already. Oct 14, 2022 at 6:53
  • No problem! Sometimes helpful to merge, sometimes not. Thanks for all your work. (I've upvoted many, but many others do not seem to vote much.)
    – eth
    Oct 15, 2022 at 5:38

Not the answer you're looking for? Browse other questions tagged or ask your own question.