ERC-1191 Adding a Chain ID to Checksummed Addresses (Add chain id to mixed-case checksum address encoding)
Last Call · Accounts & wallets · created 2018-03-18
Incorporates a network-distinguishing chain ID into the mixed-case checksum calculation of an address, so that software such as wallets can detect an attempt to send to an address generated on a different network.
Why it is needed
An Ethereum address is a hash of a public key, so the address itself carries no metadata indicating which network it's meant for. The existing standard, EIP-55, filters out typo'd addresses using a checksum that mixes uppercase and lowercase letters, but it cannot catch an address generated on a different Ethereum-based network, since such an address is fully valid in form. For example, if an address received on an Ethereum testnet is pasted into a mainnet wallet and sent to, the software gives no warning at all, and funds can be lost as a result. This standard optionally incorporates the chain ID defined in EIP-155 into the EIP-55 checksum calculation, making the case pattern differ by network, so that software can distinguish addresses belonging to different networks.
In depth
An optional variant extending EIP-55
EIP-55 is a mixed-case checksum standard created to prevent users from losing funds by sending to an invalid address. This proposal optionally adds the chain ID defined by EIP-155 to that hash calculation. The goal is to prevent losses from sending to an address that is valid but was obtained from a client on a different network. The original text gives an example in which, if this proposal is implemented, a wallet on the Ethereum mainnet can warn the user when attempting to send to an Ethereum testnet address.
Checksum calculation rule
The base algorithm is the same as EIP-55. However, if a registered chain ID is given, that value is added to the input of the hash function. If the supplied chain ID belongs to a network that has adopted this checksum variant, the chain ID and a 0x separator are prepended to the address before the hash is computed. The address is then written in hexadecimal, and for the i-th character, if it is a letter (one of abcdef), it is written uppercase when the 4*i-th bit of the computed hash is 1, and lowercase otherwise. The original Rationale section cites as an advantage that minimal code changes to existing libraries can prevent losses from mixing up addresses across different Ethereum-based networks.
Reference implementation (Python)
The original text's eth_checksum_encode(addr, chainid=1) function sets the list of adopting networks as adopted_eip1191 = [30, 31]; if the chain ID is in that list, it uses str(chainid) + addr.lower() as the input to the keccak_256 hash, and otherwise uses addr[2:].lower() as in the existing EIP-55. It then uppercases each character whose corresponding hash nibble value is 8 or greater. In other words, on networks that have not adopted it, such as the Ethereum mainnet (chain ID 1), the result is identical to existing EIP-55.
Adopting networks and test cases
According to the original text's Usage table, the networks supporting this checksum variant are RSK mainnet (chain ID 30) and RSK testnet (chain ID 31). The test cases show that the same address produces a different case pattern on Ethereum mainnet (1), RSK mainnet (30), and RSK testnet (31), and verify that each listed address is reproduced exactly when re-encoded with its corresponding chain ID.
List of projects that have implemented it
The original text's Implementation table lists MyCrypto, MyEtherWallet, Ledger, Trezor, Web3.js, EthereumJS-util, and ENS address-encoder as projects that have implemented this standard. The implementation languages vary, including JavaScript, TypeScript, Python, and C.
Document status
The original text's status is listed as Last Call, with a deadline of 2019-11-18. Since this is a stage before Final, its content may have changed since then.