2018-03-20 15:10:58 +00:00
---
2018-03-21 12:51:05 +00:00
eip: 55
title: Mixed-case checksum address encoding
2019-03-08 18:22:02 +00:00
author: Vitalik Buterin < vitalik.buterin @ ethereum . org > , Alex Van de Sande < avsa @ ethereum . org >
2018-03-21 15:55:18 +00:00
type: Standards Track
2018-03-21 12:51:05 +00:00
category: ERC
2018-04-20 13:30:12 +00:00
status: Final
2018-03-21 12:51:05 +00:00
created: 2016-01-14
2018-03-20 15:10:58 +00:00
---
2017-06-24 10:16:06 +00:00
# Specification
2017-06-24 10:13:19 +00:00
Code:
``` python
2017-06-24 10:44:46 +00:00
from ethereum import utils
2017-06-24 10:13:19 +00:00
def checksum_encode(addr): # Takes a 20-byte binary address as input
o = ''
2017-06-24 10:44:46 +00:00
v = utils.big_endian_to_int(utils.sha3(addr.hex()))
for i, c in enumerate(addr.hex()):
2017-06-24 10:13:19 +00:00
if c in '0123456789':
o += c
else:
2017-06-24 10:44:46 +00:00
o += c.upper() if (v & (2**(255 - 4*i))) else c.lower()
2017-06-24 10:13:19 +00:00
return '0x'+o
2017-06-24 10:44:46 +00:00
def test(addrstr):
2017-10-21 16:29:39 +00:00
assert(addrstr == checksum_encode(bytes.fromhex(addrstr[2:])))
2017-06-24 10:44:46 +00:00
test('0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed')
test('0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359')
test('0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB')
test('0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb')
2017-06-24 10:13:19 +00:00
```
2017-06-29 20:39:10 +00:00
In English, convert the address to hex, but if the `i` th digit is a letter (ie. it's one of `abcdef` ) print it in uppercase if the `4*i` th bit of the hash of the lowercase hexadecimal address is 1 otherwise print it in lowercase.
2017-06-24 10:13:19 +00:00
2017-12-02 20:08:26 +00:00
# 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.
2017-06-24 11:06:16 +00:00
# Implementation
In javascript:
```js
const createKeccakHash = require('keccak')
function toChecksumAddress (address) {
2017-12-08 02:59:12 +00:00
address = address.toLowerCase().replace('0x', '')
2017-06-24 11:06:16 +00:00
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()
```
2017-12-02 20:08:26 +00:00
# Test Cases
2017-06-24 11:06:16 +00:00
2017-12-02 20:08:26 +00:00
```
# All caps
0x52908400098527886E0F7030069857D2E4169EE7
0x8617E340B3D01FA5F11F306F4090FD50E238070D
# All Lower
0xde709f2102306220921060314715629080e2fb77
0x27b1fdb04752bbc536007a920d24acb045561c26
# Normal
0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed
0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359
0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB
0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb
```
2017-06-24 10:13:19 +00:00
2017-06-24 11:09:51 +00:00
# Adoption
| Wallet | displays checksummed addresses | rejects invalid mixed-case | rejects too short | rejects too long |
|--------------------------|--------------------------------|----------------------------|-------------------|------------------|
2017-07-04 21:06:52 +00:00
| Etherwall 2.0.1 | Yes | Yes | Yes | Yes |
2017-06-24 11:09:51 +00:00
| Jaxx 1.2.17 | No | Yes | Yes | Yes |
| MetaMask 3.7.8 | Yes | Yes | Yes | Yes |
| Mist 0.8.10 | Yes | Yes | Yes | Yes |
| MyEtherWallet v3.9.4 | Yes | Yes | Yes | Yes |
| Parity 1.6.6-beta (UI) | Yes | Yes | Yes | Yes |
2018-10-15 11:38:27 +00:00
| Jaxx Liberty 2.0.0 | Yes | Yes | Yes | Yes |
2018-10-17 13:06:14 +00:00
| Coinomi 1.10 | Yes | Yes | Yes | Yes |
2018-11-13 05:37:50 +00:00
| Trust Wallet | Yes | Yes | Yes | Yes |
2017-06-24 11:09:51 +00:00
### Exchange support for mixed-case address checksums, as of 2017-05-27:
| Exchange | displays checksummed deposit addresses | rejects invalid mixed-case | rejects too short | rejects too long |
|--------------|----------------------------------------|----------------------------|-------------------|------------------|
| Bitfinex | No | Yes | Yes | Yes |
| Coinbase | Yes | No | Yes | Yes |
| GDAX | Yes | Yes | Yes | Yes |
| Kraken | No | No | Yes | Yes |
| Poloniex | No | No | Yes | Yes |
| Shapeshift | No | No | Yes | Yes |
2017-06-24 10:44:46 +00:00
# References
2017-06-24 10:13:19 +00:00
2017-06-24 10:44:46 +00:00
1. EIP 55 issue and discussion https://github.com/ethereum/eips/issues/55
2. Python example by @Recmo https://github.com/ethereum/eips/issues/55#issuecomment-261521584
2017-06-27 22:53:43 +00:00
3. Python implementation in [`ethereum-utils` ](https://github.com/pipermerriam/ethereum-utils#to_checksum_addressvalue---text )
4. Ethereumjs-util implementation https://github.com/ethereumjs/ethereumjs-util/blob/75f529458bc7dc84f85fd0446d0fac92d991c262/index.js#L452-L466
2018-03-27 16:24:00 +00:00
5. Swift implementation in [`EthereumKit` ](https://github.com/yuzushioh/EthereumKit/blob/master/EthereumKit/Helper/EIP55.swift )
2019-01-25 21:37:23 +00:00
6. Kotlin implementation in [`KEthereum` ](https://github.com/walleth/kethereum/tree/master/erc55 )