Mixed-case checksum address encoding

FinalStandards Track: ERC
Created: 2016-01-14
Vitalik Buterin <vitalik.buterin@ethereum.org>, Alex Van de Sande <avsa@ethereum.org>
DiscussionsOriginal linkEdit
1 min read

The ERC-55 standard is a proposal for a new method of encoding Ethereum addresses that includes a checksum to reduce the risk of errors when sending transactions. The standard was introduced in January 2016 by Vitalik Buterin and Alex Van de Sande as part of the Ethereum Improvement Proposals (EIPs).

The standard works by taking a 20-byte binary address and converting it to a hexadecimal string. This string is then hashed using the keccak256 algorithm, which produces a 256-bit hash value. The hash value is then used to generate a new string that includes both upper and lower case letters. The checksum is calculated by comparing each character in the original address to the corresponding character in the new string. If the character is a letter, it is converted to upper case if the corresponding character in the hash value is greater than or equal to 8, and left as lower case otherwise. If the character is a number, it is left unchanged.

The significance of the ERC-55 standard is that it provides a more reliable way of verifying Ethereum addresses. Previously, users had to rely on manually checking the address for errors, which was prone to mistakes. With the checksum, it is much less likely that a user will accidentally send funds to the wrong address. This is particularly important given the irreversible nature of Ethereum transactions.

The standard has been widely adopted by the Ethereum community and is now the recommended method for encoding addresses. It has also been implemented in many Ethereum wallets and other software tools. Overall, the ERC-55 standard has helped to improve the security and reliability of the Ethereum network, making it a more trustworthy platform for decentralized applications and transactions.

Anyone may contribute to propose contents.
Go propose



import eth_utils def checksum_encode(addr): # Takes a 20-byte binary address as input hex_addr = addr.hex() checksummed_buffer = "" # Treat the hex address as ascii/utf-8 for keccak256 hashing hashed_address = eth_utils.keccak(text=hex_addr).hex() # Iterate over each character in the hex address for nibble_index, character in enumerate(hex_addr): if character in "0123456789": # We can't upper-case the decimal digits checksummed_buffer += character elif character in "abcdef": # Check if the corresponding hex digit (nibble) in the hash is 8 or higher hashed_address_nibble = int(hashed_address[nibble_index], 16) if hashed_address_nibble > 7: checksummed_buffer += character.upper() else: checksummed_buffer += character else: raise eth_utils.ValidationError( f"Unrecognized hex character {character!r} at position {nibble_index}" ) return "0x" + checksummed_buffer def test(addr_str): addr_bytes = eth_utils.to_bytes(hexstr=addr_str) checksum_encoded = checksum_encode(addr_bytes) assert checksum_encoded == addr_str, f"{checksum_encoded} != expected {addr_str}" test("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed") test("0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359") test("0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB") test("0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb")

In English, convert the address to hex, but if the ith digit is a letter (ie. it's one of abcdef) print it in uppercase if the 4*ith bit of the hash of the lowercase hexadecimal address is 1 otherwise print it in lowercase.



  • Backwards compatible with many hex parsers that accept mixed case, allowing it to be easily introduced over time
  • Keeps the length at 40 characters
  • On average there will be 15 check bits per address, and the net probability that a randomly generated address if mistyped will accidentally pass a check is 0.0247%. This is a ~50x improvement over ICAP, but not as good as a 4-byte check code.


In javascript:

const createKeccakHash = require('keccak') function toChecksumAddress (address) { address = address.toLowerCase().replace('0x', '') var hash = createKeccakHash('keccak256').update(address).digest('hex') var ret = '0x' for (var i = 0; i < address.length; i++) { if (parseInt(hash[i], 16) >= 8) { ret += address[i].toUpperCase() } else { ret += address[i] } } return ret }
> toChecksumAddress('0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359')

Note that the input to the Keccak256 hash is the lowercase hexadecimal string (i.e. the hex address encoded as ASCII):

    var hash = createKeccakHash('keccak256').update(Buffer.from(address.toLowerCase(), 'ascii')).digest()

Test Cases

# All caps
# All Lower
# Normal
Further reading
Anyone may contribute to propose contents.
Go propose
Adopted by projects
Anyone may contribute to propose contents.
Go propose

Not miss a beat of EIPs' update?

Subscribe EIPs Fun to receive the latest updates of EIPs Good for Buidlers to follow up.

View all
Serve Ethereum Builders, Scale the Community.
Supported by