How is the address of an Ethereum contract computed? What use cases are there for knowing a contract's address in advance?
7 Answers
EDIT April 2019: CREATE2
information added.
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 ++ senderAddress ++ salt ++ keccak256(init_code))[12:]
More information will be added here and for the meantime see EIP-1014.
-
5For the usecase part, you could mention something about prefunding contracts Jan 30, 2016 at 2:11
-
4What 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
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
-
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
-
1At 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?– QwertyDec 20, 2021 at 18:16
-
-
@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.– QwertyFeb 2, 2022 at 16:03
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:
// rlp@2.0.0
// keccak@1.4.0
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
-
-
1Here is a good explanation: ethereum.stackexchange.com/questions/19092/… Jun 10, 2018 at 1:30
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")
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
}
-
1thanks for sharing, wonder where did you get those magic numbers: 0x7f, 0xd6, 0x94– DiveIntoJul 28, 2018 at 13:44
-
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);
}
-
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});
– GongFuJan 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.– riordantJan 7, 2022 at 2:10
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
-
-
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