Within an Ethereum transaction, the zero-account is just a special case used to indicate that a new contract is being deployed. It is literally '0x0' set to the to field in the raw transaction.

Every Ethereum transaction, whether it's a transfer between two external accounts, a request to execute contract code, or a request to deploy a new contract, are encoded in the same way. A raw transaction object will look something like this:

transaction = {
  nonce: '0x0', 
  gasLimit: '0x6acfc0', // 7000000
  gasPrice: '0x4a817c800', // 20000000000
  to: '0x0',
  value: '0x0',
  data: '0xfffff'
};

If to is set to something other than '0x0', this request will result in transferring ether to the address (if value is non-zero), and execute the function encoded in the data field. Remember, the address can either be a contract or an external account.

When the to address is the zero-address, a new contract will be created by executing the code in data (this is what is meant by "code that returns the code"). The address of the newly created contract is technically known beforehand as it's based on the address of the sender and it's current nonce. That address becomes the official address of the contract after mining.

For a pretty good read on Ethereum transactions, check out this blog post.

Note: There is also the actual Solidity code statement address(0) which is the initial value of a variable of type address. The documentation you posted, however, is referring to specifically when the to account address in a transaction is set to '0x0'.

Answer from Adam Kipnis on Stack Overflow
Top answer
1 of 4
51

Within an Ethereum transaction, the zero-account is just a special case used to indicate that a new contract is being deployed. It is literally '0x0' set to the to field in the raw transaction.

Every Ethereum transaction, whether it's a transfer between two external accounts, a request to execute contract code, or a request to deploy a new contract, are encoded in the same way. A raw transaction object will look something like this:

transaction = {
  nonce: '0x0', 
  gasLimit: '0x6acfc0', // 7000000
  gasPrice: '0x4a817c800', // 20000000000
  to: '0x0',
  value: '0x0',
  data: '0xfffff'
};

If to is set to something other than '0x0', this request will result in transferring ether to the address (if value is non-zero), and execute the function encoded in the data field. Remember, the address can either be a contract or an external account.

When the to address is the zero-address, a new contract will be created by executing the code in data (this is what is meant by "code that returns the code"). The address of the newly created contract is technically known beforehand as it's based on the address of the sender and it's current nonce. That address becomes the official address of the contract after mining.

For a pretty good read on Ethereum transactions, check out this blog post.

Note: There is also the actual Solidity code statement address(0) which is the initial value of a variable of type address. The documentation you posted, however, is referring to specifically when the to account address in a transaction is set to '0x0'.

2 of 4
14

It's not actually true that a contract creation transaction has a "to" field set to the zero address (meaning 0x00...000). This is an easy mistake to make (and I've made it too) as it is described that way in many resources.

The passage you cite from the Solidity docs were updated to state this:

If the target account is not set (the transaction does not have a recipient or the recipient is set to null), the transaction creates a new contract. As already mentioned, the address of that contract is not the zero address but an address derived from the sender and its number of transactions sent (the “nonce”).

So you can see they realized at some point that the recipient field should be empty. I've actually looked at serialized creation transactions and found 0x80 there instead of an RLP-ed zero address.

In fact, 0x80 is the RLP encoding of an empty byte array, which is what the Yellow Paper states is the recipient for a contract creation:

The address hash is slightly different: it is either a 20-byte address hash or, in the case of being a contract-creation transaction (and thus formally equal to ∅), it is the RLP empty byte sequence and thus the member of

As I said, this is a common source of confusion. In that vein, this GitHub PR rolling back a mistakenly "fixed" test is amusing. It has the comment:

RLP encoding of 0 is encoding of empty byte array, so 0x80 is correct.

0x00 is encoding of byte array of length 1 containing one byte 0, not encoding of integer 0.

🌐
Etherscan
etherscan.io › address › 0x0000000000000000000000000000000000000000
Null: 0x000...000 | Address: 0x00000000...000000000 | Etherscan
Get 177% Deposit Bonus and 25 Jackpot Spins. Fast crypto withdrawals. ... This address is not owned by any user, is often associated with token burn & mint/genesis events and used as a generic null address
🌐
Ethers
docs.ethers.org › v5 › api › utils › constants
Constants
ethers.constants.AddressZero ⇒ string< Address > ... The Address Zero, which is 20 bytes (40 nibbles) of zero.
🌐
GitHub
github.com › ethereum-optimism › contracts › issues › 329
Use ethers.constants.ZeroAddress instead of ZERO_ADDRESS · Issue #329 · ethereum-optimism/contracts
March 16, 2021 - export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' Ethers also has this constant at ethers.constants.ZeroAddress. We want to replace all instances of ZERO_ADDRESS with ethers.constants.ZeroAddress. You can see an example of this change in this PR: https://github.com/ethereum-optimism/contracts/pull/327/files.
Author   ethereum-optimism
🌐
Medium
medium.com › @ajaotosinserah › mastering-addresses-in-ethereum-5411ba6c3b0f
Mastering Addresses In Ethereum
June 1, 2023 - The zero address is a special address that should not be used for any purpose other than those listed above. If you send Ether to the zero address or attempt to create a contract or interact with a contract at the zero address, you will lose ...
🌐
GitHub
github.com › ethers-io › ethers.js › discussions › 4510
The namehash of an empty string should be the zero address · ethers-io/ethers.js · Discussion #4510
Strictly speaking according to the spec (https://eips.ethereum.org/EIPS/eip-137#namehash-algorithm) the namehash/node for a zero length string should be the zero address.
Author   ethers-io
🌐
Jesserc Articles
jesserc.hashnode.dev › solidity-attack-vectors-8-no-address-zero-check
Solidity Attack Vectors: #8 No Address Zero Check
January 4, 2023 - The Zero Address is an address usually used for the burning of tokens and Ether. Anything sent to the Zero Address is lost and lost forever because there is no corresponding private key for it and no one has the private key.
Top answer
1 of 2
5

So, for now, transferring to what we call a long-zero address (an address obtained by converting an accountId to its solidity expression 0.0.536603 -> 0x0000000000000000000000000000000000536603) via a JSON-RPC transaction will fail.

However, transferring to an EVM address using a JSON-RPC transaction will work, see example below:

    console.log("Transfer to EVM address");
    let tx = {
        to: `0xb8482dc06049cdff56a6b747330f06de3cc1efc0`,
        value: ethers.parseEther('3', 'wei')
    };
    let transaction = await signer.sendTransaction(tx);

The EVM address for an account only exists if the account was first created by sending hbar or tokens to this address. An account created with the SDK will only have a long-zero EVM address.

Alternatively, you can use the SDK to transfer to any of the three address types:

    import {
        AccountId,
        Client, Hbar,
        PrivateKey, TransferTransaction
    } from "@hashgraph/sdk";
    import dotenv from "dotenv";

    dotenv.config();
    
    async function main() {

        let client = Client.forName(process.env.HEDERA_NETWORK).setOperator(
            AccountId.fromString(process.env.OPERATOR_ID),
            PrivateKey.fromString(process.env.OPERATOR_KEY)
        );
        console.log("Transfer to accountId");
        response = await new TransferTransaction()
            .addHbarTransfer(client.operatorAccountId, new Hbar(1).negated())
            .addHbarTransfer(AccountId.fromString("0.0.5465603"), new Hbar(1))
            .execute(client);
        await response.getReceipt(client);

        console.log("Transfer to solidity address");
        response = await new TransferTransaction()
            .addHbarTransfer(client.operatorAccountId, new Hbar(1).negated())
            .addHbarTransfer("0x0000000000000000000000000000000000536603", new Hbar(1))
            .execute(client);
        await response.getReceipt(client);

        console.log("Transfer to EVM address");
        let response = await new TransferTransaction()
            .addHbarTransfer(client.operatorAccountId, new Hbar(1).negated())
            .addHbarTransfer("0xb8482dc06049cdff56a6b747330f06de3cc1efc0", new Hbar(1))
            .execute(client);
        await response.getReceipt(client);
        
        client.close();
    }

    void main();
2 of 2
1

It turns out to be a little more nuanced than the above, you can indeed send to a long-zero address, however...

If the account has an EVM address, you have to use the EVM address.

For example: account 0.0.5465603 was created by sending hbar to 0xb8482dc06049cdff56a6b747330f06de3cc1efc0, as a result, only this address can be used with ethers.js.

If the account was created via the SDK and doesn't have an EVM address, but a long-zero address, you can use ethers.js to send to the long zero address.

For example: account 0.0.220237 was created with the SDK and has a long zero address: 0x0000000000000000000000000000000000219b07 which can be used by ethers.js

Also tried through a contract

pragma solidity ^0.8.26;
contract SendTest {
    function send(address payable to) public payable {
        to.transfer(msg.value);
    }
 }

deployed here on testnet: 0x000000000000000000000000000000000053da1a

Sending to the long zero address of an account (0.0.536603) created by sending hbar to an evm address fails

const testContract = new ethers.Contract(`0x${contractAddress}`, abi, signer)
const options = {
    value: 20000000000, // 2 tinybar
    gasLimit: 100000
}

await testContract.send("0x0000000000000000000000000000000000536603", options);

Sending to the EVM address of that account (0.0.536603) works

const testContract = new ethers.Contract(`0x${contractAddress}`, abi, signer)
const options = {
    value: 20000000000, // 2 tinybar
    gasLimit: 100000
}

await testContract.send("0xb8482dc06049cdff56a6b747330f06de3cc1efc0", options);

Sending to the long zero address of an account created with the SDK (0.0.2202375) works

const testContract = new ethers.Contract(`0x${contractAddress}`, abi, signer)
const options = {
    value: 20000000000, // 2 tinybar
    gasLimit: 100000
}

await testContract.send("0x0000000000000000000000000000000000219b07", options);
Find elsewhere
🌐
GitHub
github.com › ethers-io › ethers.js › issues › 658
Override type checking in contract call · Issue #658 · ethers-io/ethers.js
November 20, 2019 - To check a user's ETH balance, the contract makes a special case for the address 0x0 (note that this is not intended to be the null/0-address) when encountered in the tokens array. ethers, however, treats 0x0 as the invalid address it is.
Author   ethers-io
🌐
Medium
medium.com › @joichiro.sai › solidity-attack-vectors-11-no-address-zero-check-7dd337bd9587
Solidity Attack Vectors #11 — No Address Zero Check | by 0xjoi | Medium
February 1, 2025 - Default Address Issue: Solidity assigns default values to uninitialized variables. Since the default value for an address type is 0x0000000000000000000000000000000000000000, calling payUser on an uninitialized array index will also send funds to the Zero Address.
🌐
Ethers
docs.ethers.org › v5 › api › utils › address
Addresses
Due to the way IBAN encodes address, only addresses that fit into 30 base-36 characters are actually compatible, so the format was adapted to support 31 base-36 characters which is large enough for a full Ethereum address, however the preferred method was to select a private key whose address has a 0 as the first byte, which allows the address to be formatted as a fully compatibly standard IBAN address with 30 base-36 characters.
🌐
Snyk
snyk.io › advisor › ethers › functions › ethers.ethers.constants
How to use the ethers.ethers.constants function in ethers | Snyk
ethers.constants.AddressZero : token.address; } const taskId = await makeTask({ colonyNetwork, colony, dueDate, domainId, skillId, manager }); const task = await colony.getTask(taskId); const managerPayoutBN = new BN(managerPayout); const evaluatorPayoutBN = new BN(evaluatorPayout); const workerPayoutBN = new BN(workerPayout); const totalPayouts = managerPayoutBN.add(workerPayoutBN).add(evaluatorPayoutBN); const childSkillIndex = await getChildSkillIndex(colonyNetwork, colony, 1, task.domainId); await colony.setFundingRole(1, 0, manager, 1, true); await colony.moveFundsBetweenPots(1, 0, childSkillIndex, 1, task.fundingPotId, totalPayouts, tokenAddress, { from: manager }); await colony.setAllTaskPayouts(taskId, tokenAddress, managerPayout, evaluatorPayout, workerPayout, { from: manager }); await assignRoles({ colony, taskId, manager, evaluator, worker }); return taskId;
🌐
Ethers
docs.ethers.org › v6 › api › constants
Documentation
A constant for the number of wei in a single ether. ... A constant for the zero address.
🌐
Metaschool
metaschool.so › home › answers › what is address(0) in solidity
What is Address(0) in Solidity -
March 29, 2024 - This address holds a distinctive status within the Ethereum ecosystem, signifying a null address with all its bytes set to zero.
🌐
Panda Academy
academy.pandatool.org › en_US › eth › 489
Zero Address vs. Dead Address: Key Differences in Ethereum | Panda Academy
In the Ethereum ecosystem, “black hole addresses” refer to addresses whose private keys are permanently lost, making any assets sent to them irrecoverable. These addresses are primarily used to burn tokens, reducing the circulating supply.
🌐
Fellowship of Ethereum Magicians
ethereum-magicians.org › ercs
ERC: Short Representation for Leading Zeros in Address - ERCs - Fellowship of Ethereum Magicians
December 20, 2023 - Hi, as I presented in previous AllWalletDevs about a proposal to represent leading zeros in address which reduces chance of phishing, I am thinking of starting an ERC. Motivation reduce phishing Specification The format will be 0{N}xAA..BBBB, where N is the number of leading zeros in decimal form AA is the two hex digits of two digits since first non-zero hex digit BBBB is the last four hex digits Rationale We choose 0{N}x format so it can be easily differentiate from 0x We choose 2 digit...