HomeEIPsNewsletter
EIPsERC-55
ERC-55

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>
Discussions ForumOriginal Proposal 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.

Video
Anyone may contribute to propose contents.
Go propose
Original

Specification

Code:

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.

Rationale

Benefits:

  • 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.

Implementation

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')
'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
0x52908400098527886E0F7030069857D2E4169EE7
0x8617E340B3D01FA5F11F306F4090FD50E238070D
# All Lower
0xde709f2102306220921060314715629080e2fb77
0x27b1fdb04752bbc536007a920d24acb045561c26
# Normal
0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed
0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359
0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB
0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb
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.
Resources
GitHub
Supported by