importeth_utilsdefchecksum_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
fornibble_index,characterinenumerate(hex_addr):ifcharacterin"0123456789":# We can't upper-case the decimal digits
checksummed_buffer+=characterelifcharacterin"abcdef":# Check if the corresponding hex digit (nibble) in the hash is 8 or higher
hashed_address_nibble=int(hashed_address[nibble_index],16)ifhashed_address_nibble>7:checksummed_buffer+=character.upper()else:checksummed_buffer+=characterelse:raiseeth_utils.ValidationError(f"Unrecognized hex character {character!r} at position {nibble_index}")return"0x"+checksummed_bufferdeftest(addr_str):addr_bytes=eth_utils.to_bytes(hexstr=addr_str)checksum_encoded=checksum_encode(addr_bytes)assertchecksum_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.