ERC-7930 - Interoperable Addresses

Created 2025-02-02
Status Draft
Category ERC
Type Standards Track
Authors

Abstract

Interoperable Addresses is a binary format to describe an address specific to one chain with a companion 'Interoperable Names' specification for human-readable display.

This is achieved through a versioned, length-prefixed binary envelope that supports arbitrary-length data. The interpretation and serialization rules for the data within this envelope are defined by companion standards, which provide profiles for each chain type.

Motivation

Current Ethereum addresses (ERC-55) lack chain specificity and have optional checksums, creating several challenges:

Interoperable Addresses build on insights from , CAIP-10 and CAIP-50, offering a unified format which combines: - Binding chain specificity (via explicit chain identifiers) to the raw address. - Compact & canonical binary format for use on cross-chain message passing and intent declaration. - Checksums for name collision mitigation & user error prevention.

Furthermore, this proposal adds a few features to make addresses interoperable with infrastructure at the edges of and beyond the ethereum ecosystem, by supporting the representation of addresses of non-evm chains as well, for the benefit of cross-chain liquidity movements and cross-chain message passing.

Guarantees this standard aims to provide

Comparisons with other standards

CAIP-10

CAIP-10 proposes a standard text format to represent what in this document is defined as target addresses. Since it's a text-only standard, it does not concern itself with the serialization/deserialization of the various chains' address formats, simply using the text representation of addresses already defined by the respective chains. This means it is trivial to add support for chains to CAIP-10, while doing so with this standard involves defining a serialization scheme.

The above has the drawback of not being able to guarantee canonicity. That is, there could be multiple valid CAIP-10 addresses pointing to the same target address.

Also, the text format is of little use for smart contracts involved with cross-chain liquidity transfers and message passing due to its reduced data efficiency and lack of canonicity.

Interoperable Names are convertible to CAIP-10 without even going through the binary representation, so backwards-compatibility with actors expecting CAIP-10 identifiers should not be an issue.

The interop roadmap is better served by having a standardized binary format for addresses first, which allows the message passing and intents verticals to move forward on a common interface, with a good-enough text representation which is familiar to users and useful for developers, and as a next step develop a chain & address name resolving standard on top of it, leveraging its uniformity and extensibility.

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Concepts

Interoperable Address : A binary payload which unambiguously identifies a target address and allows conversion to a human-readable name.

Interoperable Name : A string representation of an interoperable address, meant to be used by humans.

Target address : The (address, chain ID) pair a particular Interoperable Address points to.

Interoperable Address V1 binary format definition

In binary format, addresses MUST have the following encoding:

┌─────────┬───────────┬──────────────────────┬────────────────┬───────────────┬─────────┐
│ Version │ ChainType │ ChainReferenceLength │ ChainReference │ AddressLength │ Address │
└─────────┴───────────┴──────────────────────┴────────────────┴───────────────┴─────────┘

Where:

Version : A 2-byte version identifier. For version 1, this must be 0x0001 (big-endian). Future versions SHOULD be standardized in separate ERCs.

ChainType : A 2-byte value as defined in CAIP-350, corresponding to a CAIP-2 namespace, which allows users to know how to interpret & display the other two fields.

ChainReferenceLength : A 1-byte integer encoding the length of ChainReference in bytes. Note that it MAY be zero, in which the Interoperable Address will not include a chain reference.

ChainReference : Variable length, binary representation of CAIP-2 chain namespace & reference serialized as explained in the CAIP-350 profile for the chain type, encoding the chain ID.

AddressLength : 1-byte integer encoding the length of Address in bytes. Note that it MAY be zero, in which the Interoperable Address will not include an address. It MUST NOT be zero if ChainReferenceLength is also zero.

Address : Variable length field containing the binary format of the address component. For serialization details of different types of addresses see the CAIP-350 profile for the chain type.

Version Compatibility

These rules ensure that future versions of Interoperable Addresses maintain backwards compatibility and consistent behavior across implementations:

Interoperable Name format definition

Syntax

<human readable name> ::= <address> @ <chain> # <checksum>
<address>             ::= [.-:_%a-zA-Z0-9]*
<chain>               ::= [.-:_a-zA-Z0-9]*
<checksum>            ::= [0-9A-F]{8}

Where:

Chain : String representation of CAIP-2 blockchain identifier, recovered from the binary representation described in the CAIP-350 profile for the chain type. In the case where ChainReferenceLength is zero, it should be the CAIP namespace alone, and no trailing colon. Note that it's not possible to specify a reference without a namespace.

Address : Chain namespace specific text representation of the address from the binary representation. Mapping between the two described in the CAIP-350 profile for the chain type. In the case where AddressLength is zero, it should be the empty string.

Checksum : 4-byte checksum calculated by computing the keccak256 hash of the concatenated ChainType, ChainReferenceLength, ChainReference, AddressLength and Address fields of the binary representation (that is, the v1 binary representation skipping the Version field), and truncating all but the first 4 bytes of the output. Represented as a base16 string as defined in RFC 4648.

Rationale

Test Cases

Example 1: Ethereum mainnet address

Chain: Ethereum Mainnet Address: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045

Interoperable Name: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@eip155:1#4CA88C9C

Interoperable Address:

0x00010000010114D8DA6BF26964AF9D7EED9E03E53415D37AA96045
  ^^^^-------------------------------------------------- Version:              decimal 1
      ^^^^---------------------------------------------- ChainType:            2 bytes of CAIP namespace
          ^^-------------------------------------------- ChainReferenceLength: decimal 1
            ^^------------------------------------------ ChainReference:       1 byte to store uint8(1)
              ^^---------------------------------------- AddressLength:        decimal 20
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Address:              20 bytes of ethereum address

keccak256 input for checksum: 0x0000010114D8DA6BF26964AF9D7EED9E03E53415D37AA96045 note the version field is removed before hashing

Example 2: Solana mainnet address

Chain: Solana Mainnet

Address: MJKqp326RZCHnAAbew9MDdui3iCKWco7fsK9sVuZTX2

Interoperable Name: MJKqp326RZCHnAAbew9MDdui3iCKWco7fsK9sVuZTX2@solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d#88835C11

Interoperable Address:

0x000100022045296998a6f8e2a784db5d9f95e18fc23f70441a1039446801089879b08c7ef02005333498d5aea4ae009585c43f7b8c30df8e70187d4a713d134f977fc8dfe0b5
  ^^^^---------------------------------------------------------------------------------------------------------------------------------------- Version:              decimal 1
      ^^^^------------------------------------------------------------------------------------------------------------------------------------ ChainType:            2 bytes of CAIP namespace
          ^^---------------------------------------------------------------------------------------------------------------------------------- ChainReferenceLength: decimal 32
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------------------------------------ ChainReference:       32 bytes of solana genesis block
                                                                            ^^---------------------------------------------------------------- AddressLength:        decimal 32
                                                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- Address:              32 bytes of solana address

keccak256 input for checksum: 0x00022045296998a6f8e2a784db5d9f95e18fc23f70441a1039446801089879b08c7ef02005333498d5aea4ae009585c43f7b8c30df8e70187d4a713d134f977fc8dfe0b5. Note the version field is removed before hashing.

Example 3: EVM address without chainid

Chain: eip155 namespace, chainid not specified. Address: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 Interoperable Name: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@eip155#B26DB7CB

Interoperable Address:

0x000100000014D8DA6BF26964AF9D7EED9E03E53415D37AA96045
  ^^^^------------------------------------------------ Version:              decimal 1
      ^^^^-------------------------------------------- ChainType:            2 bytes of CAIP namespace
          ^^------------------------------------------ ChainReferenceLength: zero, indicating no chainid
            ^^---------------------------------------- AddressLength:        decimal 20
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Address:              20 bytes of ethereum address

keccak256 input for checksum: 0x00000014D8DA6BF26964AF9D7EED9E03E53415D37AA96045 Note the version field is removed before hashing.

Example 4: Solana mainnet network, no address

Chain: Solana Mainnet.

Address: Not specified.

Interoperable Name: @solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d#2EB18670

Interoperable Address:

0x000100022045296998a6f8e2a784db5d9f95e18fc23f70441a1039446801089879b08c7ef000
  ^^^^------------------------------------------------------------------------ Version:              decimal 1
      ^^^^-------------------------------------------------------------------- ChainType:            2 bytes of CAIP namespace
          ^^------------------------------------------------------------------ ChainReferenceLength: decimal 32
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- ChainReference:       32 bytes of solana genesis block
                                                                            ^^ AddressLength:        zero, indicating no address

keccak256 input for checksum: 0x00022045296998a6f8e2a784db5d9f95e18fc23f70441a1039446801089879b08c7ef000. Note the version field is removed before hashing.

Security Considerations

While this standard aims to be a foundation to be able to canonically refer to addresses on different chains, that guarantee is going to be a leaky abstraction in the real world, given that e.g. a particular chain namespace might define a serialization scheme that can't guarantee canonicity of addresses, or a given network might have two valid CAIP-2 ids referring to it.

It is therefore advised for implementers requiring canonicity of addresses (e.g by using them as keys in smart contract mappings or other key-value stores), to thoroughly review the CAIP-350 profile of a chain namespace for the possibility of a lack of canonicity of addresses (which should be noted in the profile's 'Extra Considerations' section) as well as collisions with other already-supported namespaces.

Copyright

Copyright and related rights waived via CC0.