/ EIPS / eip-55.md
eip-55.md
  1  ---
  2  eip: 55
  3  title: Mixed-case checksum address encoding
  4  author: Vitalik Buterin <vitalik.buterin@ethereum.org>, Alex Van de Sande <avsa@ethereum.org>
  5  type: Standards Track
  6  category: ERC
  7  status: Final
  8  created: 2016-01-14
  9  ---
 10  
 11  # Specification
 12  
 13  Code:
 14  
 15  ``` python
 16  from ethereum import utils
 17  
 18  def checksum_encode(addr): # Takes a 20-byte binary address as input
 19      o = ''
 20      v = utils.big_endian_to_int(utils.sha3(addr.hex()))
 21      for i, c in enumerate(addr.hex()):
 22          if c in '0123456789':
 23              o += c
 24          else:
 25              o += c.upper() if (v & (2**(255 - 4*i))) else c.lower()
 26      return '0x'+o
 27  
 28  def test(addrstr):
 29      assert(addrstr == checksum_encode(bytes.fromhex(addrstr[2:])))
 30  
 31  test('0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed')
 32  test('0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359')
 33  test('0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB')
 34  test('0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb')
 35  
 36  ```
 37  
 38  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.
 39  
 40  # Rationale
 41  
 42  Benefits:
 43  - Backwards compatible with many hex parsers that accept mixed case, allowing it to be easily introduced over time
 44  - Keeps the length at 40 characters
 45  - 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.
 46  
 47  # Implementation
 48  
 49  In javascript:
 50  
 51  ```js
 52  const createKeccakHash = require('keccak')
 53  
 54  function toChecksumAddress (address) {
 55    address = address.toLowerCase().replace('0x', '')
 56    var hash = createKeccakHash('keccak256').update(address).digest('hex')
 57    var ret = '0x'
 58  
 59    for (var i = 0; i < address.length; i++) {
 60      if (parseInt(hash[i], 16) >= 8) {
 61        ret += address[i].toUpperCase()
 62      } else {
 63        ret += address[i]
 64      }
 65    }
 66  
 67    return ret
 68  }
 69  ```
 70  
 71  ```
 72  > toChecksumAddress('0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359')
 73  '0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359'
 74  ```
 75  
 76  Note that the input to the Keccak256 hash is the lowercase hexadecimal string (i.e. the hex address encoded as ASCII):
 77  
 78  ```
 79      var hash = createKeccakHash('keccak256').update(Buffer.from(address.toLowerCase(), 'ascii')).digest()
 80  ```
 81  
 82  # Test Cases
 83  
 84  ```
 85  # All caps
 86  0x52908400098527886E0F7030069857D2E4169EE7
 87  0x8617E340B3D01FA5F11F306F4090FD50E238070D
 88  # All Lower
 89  0xde709f2102306220921060314715629080e2fb77
 90  0x27b1fdb04752bbc536007a920d24acb045561c26
 91  # Normal
 92  0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed
 93  0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359
 94  0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB
 95  0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb
 96  ```
 97  
 98  # Adoption
 99  
100  | Wallet                   | displays checksummed addresses | rejects invalid mixed-case | rejects too short | rejects too long |
101  |--------------------------|--------------------------------|----------------------------|-------------------|------------------|
102  | Etherwall 2.0.1          | Yes                            | Yes                        | Yes               | Yes              |
103  | Jaxx 1.2.17              | No                             | Yes                        | Yes               | Yes              |
104  | MetaMask 3.7.8           | Yes                            | Yes                        | Yes               | Yes              |
105  | Mist 0.8.10              | Yes                            | Yes                        | Yes               | Yes              |
106  | MyEtherWallet v3.9.4     | Yes                            | Yes                        | Yes               | Yes              |
107  | Parity 1.6.6-beta (UI)   | Yes                            | Yes                        | Yes               | Yes              |
108  | Jaxx Liberty 2.0.0       | Yes                            | Yes                        | Yes               | Yes              |
109  | Coinomi 1.10             | Yes                            | Yes                        | Yes               | Yes              |
110  | Trust Wallet             | Yes                            | Yes                        | Yes               | Yes              |
111  
112  ### Exchange support for mixed-case address checksums, as of 2017-05-27:
113  
114  | Exchange     | displays checksummed deposit addresses | rejects invalid mixed-case | rejects too short | rejects too long |
115  |--------------|----------------------------------------|----------------------------|-------------------|------------------|
116  | Bitfinex     | No                                     | Yes                        | Yes               | Yes              |
117  | Coinbase     | Yes                                    | No                         | Yes               | Yes              |
118  | GDAX         | Yes                                    | Yes                        | Yes               | Yes              |
119  | Kraken       | No                                     | No                         | Yes               | Yes              |
120  | Poloniex     | No                                     | No                         | Yes               | Yes              |
121  | Shapeshift   | No                                     | No                         | Yes               | Yes              |
122  
123  # References
124  
125  1. EIP 55 issue and discussion https://github.com/ethereum/eips/issues/55
126  2. Python example by @Recmo https://github.com/ethereum/eips/issues/55#issuecomment-261521584
127  3. Python implementation in [`ethereum-utils`](https://github.com/pipermerriam/ethereum-utils#to_checksum_addressvalue---text)
128  4. Ethereumjs-util implementation https://github.com/ethereumjs/ethereumjs-util/blob/75f529458bc7dc84f85fd0446d0fac92d991c262/index.js#L452-L466
129  5. Swift implementation in [`EthereumKit`](https://github.com/yuzushioh/EthereumKit/blob/master/EthereumKit/Helper/EIP55.swift)
130  6. Kotlin implementation in [`KEthereum`](https://github.com/walleth/kethereum/tree/master/erc55)