diff --git a/ERCS/erc-7930.md b/ERCS/erc-7930.md index 63e23f08b1f..b908aa79b07 100644 --- a/ERCS/erc-7930.md +++ b/ERCS/erc-7930.md @@ -2,68 +2,65 @@ eip: 7930 title: Interoperable Addresses description: An extensible binary format to refer to an address specific to one chain. -author: Teddy (@0xteddybear), Joxes (@0xJoxess), Nick Johnson (@Arachnid), Francisco Giordano (@frangio), Skeletor Spaceman (@skeletor-spaceman), Racu (@0xRacoon), TiTi (@0xtiti), Gori (@0xGorilla), Ardy (@0xArdy), Onizuka (@onizuka-wl), Sam Kaufman (@SampkaML), Marco Stronati (@paracetamolo), Yuliya Alexiev (@yuliyaalexiev), Jeff Lau (@jefflau), Sam Wilson (@samwilsn), Vitalik Buterin (@vbuterin) +author: Teddy (@0xteddybear), Joxes (@0xJoxess), Nick Johnson (@Arachnid), Francisco Giordano (@frangio), Skeletor Spaceman (@skeletor-spaceman), Racu (@0xRacoon), TiTi (@0xtiti), Gori (@0xGorilla), Ardy (@0xArdy), Onizuka (@onizuka-wl), Sam Kaufman (@SampkaML), Marco Stronati (@paracetamolo), Yuliya Alexiev (@yuliyaalexiev), Jeff Lau (@jefflau), Sam Wilson (@samwilsn), Vitalik Buterin (@vbuterin), Thomas Clowes (@clowestab), Mono (0xMonoAx) discussions-to: https://ethereum-magicians.org/t/erc-7930-interoperable-addresses/23365 -status: Draft +status: Review type: Standards Track category: ERC created: 2025-02-02 --- ## 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 proposal introduces a **binary format** to describe a chain specific address. Additionally, it defines a human-readable version of that identifier for improved user experience for user facing interactions. -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. +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 ([CAIP-350]), which provide profiles for each chain type. ## Motivation -Current Ethereum addresses ([ERC-55]) lack chain specificity and have optional checksums, creating several challenges: +The address format utilized on Ethereum mainnet is shared by a large number of other blockchains. The format does not include details of the chain on which an interaction should occur. This introduces risk if, for example, a transaction is mistakenly executed on a chain where the address is inaccesible. This risk is particularly pronounced for addresses that represent smart contracts or smart accounts. -- Optional checksum validation allows mistyped addresses to be accepted without user awareness. -- Addresses do not include any indication of the chain to which the address applies. This means chain information must be expressed out of band, and introduces the risk of an address being mistakenly used on a chain it is not valid for. This risk is particularly pronounced for addresses that represent smart contracts. -- The existing address format provides no mechanism for extension, meaning that there is no natural method to add these features to the existing address format. +([ERC-55]) outlines an **optional** checksum standard which means that mistyped addresses can be accepted by clients without the user being aware. -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. +This proposal builds on insights from [CAIP-10] and [CAIP-50]. It offers both a binary canonical _Interoperable Address_ format and a human readable _Interoperable Name_ format which: -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. +- Binds together chain identification and the raw address. +- Is compact for usage with cross-chain message passing and intent declaration. +- Includes short, easily verififiable checksums to protect users. +- Extends beyond EVM blockchains. -### Guarantees this standard aims to provide -- Any future Interoperable Address will be trivially convertible to Interoperable Address v1 (specified below), which, together with the point below, makes them a canonical representation for users who need to treat them opaquely. -- Two Interoperable Addresses, converted to this canonical version, will be bitwise-equal if and only if they represent the same _target address_. -- Checksums are short enough to be compared by humans, and allow for easy differentiation of _target addresses_ independently of any extra data the Interoperable Address may contain. +These features mitigate the risk of an address being incorrectly inputted or mistakenly used on a chain it is not intended for - a risk that is particularly pronounced for addresses that represent smart contracts. -### Comparisons with other standards +These features can not be added to existing standards as they are not easily extensible - this one is. -#### [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. +### Comparisons with other standards -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. +#### CAIP-10 -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. +[CAIP-10] proposes a standard text format to represent an address on a specific chain (referenced by its [CAIP-2] identifier). -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 standard **does not** concern itself with the serialization/deserialization of the chain specific address format. -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. +It is trivial to add support for chains to [CAIP-10], but the standard has its drawbacks: +- There is no canonical identifier for a specific address on a specific chain - there could be multiple valid [CAIP-10] addresses pointing to the same target address. +- The format is not optimized for usage within smart contracts as strings are an inefficient way to store data on-chain and [CAIP-10] identifiers lack canonicity. +- It depends on [CAIP-2], which limits the chain reference to 32 characters. ## 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. +### Terminology +**Target Address** +: The target address being represented. Serialized subject to the rules outlined in the [CAIP-350] profile for the namespace of the chain being targeted. -Interoperable Name -: A string representation of an interoperable address, meant to be used by humans. +**Interoperable Address** +: A binary payload which unambiguously identifies a target address on a target chain. -Target address -: The (address, chain ID) pair a particular Interoperable Address points to. +**Interoperable Name** +: A string representation of an _Interoperable Address_, meant to be used by humans. -### Interoperable Address V1 binary format definition -In binary format, addresses MUST have the following encoding: +### Binary Format Definition + +An _Interoperable Address_ as defined by this standard MUST have the following binary format: ``` ┌─────────┬───────────┬──────────────────────┬────────────────┬───────────────┬─────────┐ @@ -71,75 +68,80 @@ In binary format, addresses MUST have the following encoding: └─────────┴───────────┴──────────────────────┴────────────────┴───────────────┴─────────┘ ``` -Where: - -Version -: A 2-byte version identifier. For version 1, this must be `0x0001` (big-endian). Future versions SHOULD be standardized in separate ERCs. +The components outlined above have the following meanings: -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. +**Version** +: A 2-byte version identifier. For version 1 (this specification), this must be `0x0001` (big-endian). Future versions SHOULD be standardized in separate ERCs. -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. +**ChainType** +: A 2-byte value as defined in [CAIP-350], corresponding to a [CAIP-2] namespace, which allows users to know how to interpret and display the _ChainReference_ and the _Address_. -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. +**ChainReferenceLength** +: A 1-byte integer encoding the length of _ChainReference_ in bytes. Note that it MAY be zero, in which case the _Interoperable Address_ MUST NOT include a chain reference. -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. +**ChainReference** +: Variable length, binary representation of the [CAIP-2] chain ID. To discern how to serialize the _ChainReference_ for a specific chain type, implementors MUST reference the respective [CAIP-350] profile. Chain profiles are maintained by the Chain-Agnostic Standards Alliance (CASA). -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. +**AddressLength** +: 1-byte integer encoding the length of Address in bytes. Note that it MAY be zero, in which case the _Interoperable Address_ MUST NOT include an address. It MUST NOT be zero if the _ChainReferenceLength_ is also zero. -#### Version Compatibility +**Address** +: Variable length field containing the binary encoding of the address. The serialization for a specific _ChainType_ MUST follow the rules of its corresponding [CAIP-350] profile. -These rules ensure that future versions of Interoperable Addresses maintain backwards compatibility and consistent behavior across implementations: +### Interoperable Name Definition -- Future versions incompatible with v1 parsing MUST set the most significant bit of the version field to 1 -- All versions MUST support both address and chain specification simultaneously -- All versions MUST serialize to v1 format for checksum calculation, excluding the version field from the hash input -- Interoperable Address versions MAY only be able to represent a subset of the CAIP namespaces. -- Interoperable Address versions MAY assign extra syntactic restrictions on the associated Interoperable Name, coupled to novel semantic meaning (e.g. use of ENS or other naming registries) -- Interoperable Address versions MAY define extra fields for purposes such as storing information on how to display the addresses. +Recall that an _Interoperable Name_ is a human readable representation of an underlying _Interoperable Address_. -### Interoperable Name format definition +It's format is `
@ # ` where the components match the following regular expressions: #### Syntax ```bnf - ::=
@ #
::= [.-:_%a-zA-Z0-9]* ::= [.-:_a-zA-Z0-9]* ::= [0-9A-F]{8} ``` -Where: +These components have the following meanings: -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. +`
` is the text representation of an address for the chain namespace in question. -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. +`` is the string representation of a specific blockchain as defined in [CAIP-2]. For example `eip155:1` for Ethereum Mainnet. -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]. +If you are representing an address for a namespace more generally it MUST be set to the CAIP namespace with no trailing colon. For example `eip155`. -## Rationale -- Chain and address fields' syntax is deliberately chosen to be able to express [CAIP-2] namespaces (by using the `@` symbol for the separator, freeing up `:`) and [CAIP-10] account IDs, with the caveat that no length restriction is placed, so chains with longer address formats or full 256-bit EVM chainids can be represented. -- Similarly, the address field includes `%` as a valid character to allow for url-encoding of any other characters. -- While a fresh start on text-encoding schemes could e.g. make use of more characters with base58 or base64 to achieve greater information efficiency and/or abstract which chain the address exists on as an implementation detail, a more familiar approach was chosen since: - - It makes the Interoperable Address <-> raw address relationship evident to the user, which will make the cases where the former are not (yet) supported by a dapp or hardware wallet easier to reason with, as users will evidently see the address is the same, but it's the chain&checksum that is being trimmed. - - Its extra human-readability will make it more useful as a a stopgap solution until a standard focused on chain and address names is finalized. -- We chose to support zero-length addresses and chainids to be able to use just one standard to represent both potentially foreign _target addresses_ (e.g. the recipient of a cross-chain message) and also plain addresses or chainids (e.g. to specify the origin-chain hook address of a cross-chain message), for greater uniformity across implementations. +The 4-byte `` is the first 4 bytes of the hexadecimal ([RFC 4648]) string representation of a keccak256 hash. This hash is computed over the concatenation of the _Interoperable Address_'s binary fields: `ChainType`, `ChainReferenceLength`, `ChainReference`, `AddressLength`, and `Address`. The `Version` field MUST NOT be included in the hashed data. + +#### Checksums + +A 4-byte checksum MUST be computed and included when sharing an _Interoperable Name_. + +If a user-provided _Interoperable Name_ includes a checksum, clients MUST derive the underlying _Interoperable Address_, recalculate the checksum, and compare it to the provided value. In case of a mismatch, clients MUST warn the user and require explicit user input to continue with the operation. -## Test Cases +Clients MAY include the checksum when displaying an _Interoperable Name_ within their interface. +Clients MAY accept _Interoperable Name_ inputs without a checksum. -### Example 1: Ethereum mainnet address -Chain: Ethereum Mainnet -Address: `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045` +### Parsing and Serialization: -Interoperable Name: `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@eip155:1#4CA88C9C` +When parsing an _Interoperable Name_ to generate its binary _Interoperable Address_, clients MUST follow the normalization and serialization rules defined in the relevant [CAIP-350] profile for the given `` and `
`. This ensures that different valid text representations (e.g., case variations in an address) resolve to a single, canonical binary form, which is essential for consistent checksum calculation and data integrity. + +### Examples + +#### Example 1: Ethereum mainnet address + +| Key | Value | +| :--- | :--- | +| **Chain Name** | Ethereum Mainnet | +| **CAIP-2 Namespace** | `eip155` | +| **CAIP-2 Chain ID** | `1` | +| **Address** | `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045` | +| **Checksum Input** | `0x0000010114D8DA6BF26964AF9D7EED9E03E53415D37AA96045` | +| **Interoperable Name** | `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@eip155:1#4CA88C9C` | +| **Interoperable Address** | `0x00010000010114D8DA6BF26964AF9D7EED9E03E53415D37AA96045` | + +**Components** + +The components of the _Interoperable Address_ are: -Interoperable Address: ``` 0x00010000010114D8DA6BF26964AF9D7EED9E03E53415D37AA96045 ^^^^-------------------------------------------------- Version: decimal 1 @@ -149,17 +151,24 @@ Interoperable Address: ^^---------------------------------------- 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` +#### Example 2: Solana mainnet address + +| Key | Value | +| :--- | :--- | +| **Chain Name** | Solana Mainnet | +| **CAIP-2 Namespace** | `solana` | +| **CAIP-2 Chain ID** | `5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d` | +| **Address** | `MJKqp326RZCHnAAbew9MDdui3iCKWco7fsK9sVuZTX2` | +| **Checksum Input** | `0x00022045296998a6f8e2a784db5d9f95e18fc23f70441a1039446801089879b08c7ef02005333498d5aea4ae009585c43f7b8c30df8e70187d4a713d134f977fc8dfe0b5` | +| **Interoperable Name** | `MJKqp326RZCHnAAbew9MDdui3iCKWco7fsK9sVuZTX2@solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d#88835C11` | +| **Interoperable Address** | `0x000100022045296998a6f8e2a784db5d9f95e18fc23f70441a1039446801089879b08c7ef02005333498d5aea4ae009585c43f7b8c30df8e70187d4a713d134f977fc8dfe0b5` | -Interoperable Name: `MJKqp326RZCHnAAbew9MDdui3iCKWco7fsK9sVuZTX2@solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d#88835C11` +**Components** + +The components of the _Interoperable Address_ are: -Interoperable Address: ``` 0x000100022045296998a6f8e2a784db5d9f95e18fc23f70441a1039446801089879b08c7ef02005333498d5aea4ae009585c43f7b8c30df8e70187d4a713d134f977fc8dfe0b5 ^^^^---------------------------------------------------------------------------------------------------------------------------------------- Version: decimal 1 @@ -169,15 +178,23 @@ Interoperable Address: ^^---------------------------------------------------------------- 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` +#### Example 3: EVM address without chainid + +| Key | Value | +| :--- | :--- | +| **Chain Name** | Ethereum Mainnet | +| **CAIP-2 Namespace** | `eip155` | +| **CAIP-2 Chain ID** | N/A | +| **Address** | `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045` | +| **Checksum Input** | `0x00000014D8DA6BF26964AF9D7EED9E03E53415D37AA96045` | +| **Interoperable Name** | `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@eip155#B26DB7CB` | +| **Interoperable Address** | `0x000100000014D8DA6BF26964AF9D7EED9E03E53415D37AA96045` | + +**Components** + +The components of the _Interoperable Address_ are: -Interoperable Address: ``` 0x000100000014D8DA6BF26964AF9D7EED9E03E53415D37AA96045 ^^^^------------------------------------------------ Version: decimal 1 @@ -186,17 +203,24 @@ Interoperable Address: ^^---------------------------------------- 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. +#### Example 4: Solana mainnet network, no address + +| Key | Value | +| :--- | :--- | +| **Chain Name** | Solana Mainnet | +| **CAIP-2 Namespace** | `solana` | +| **CAIP-2 Chain ID** | `5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d` | +| **Address** | N/A | +| **Checksum Input** | `0x00022045296998a6f8e2a784db5d9f95e18fc23f70441a1039446801089879b08c7ef000` | +| **Interoperable Name** | `@solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d#2EB18670` | +| **Interoperable Address** | `0x000100022045296998a6f8e2a784db5d9f95e18fc23f70441a1039446801089879b08c7ef000` | + +**Components** -Interoperable Name: `@solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d#2EB18670` +The components of the _Interoperable Address_ are: -Interoperable Address: ``` 0x000100022045296998a6f8e2a784db5d9f95e18fc23f70441a1039446801089879b08c7ef000 ^^^^------------------------------------------------------------------------ Version: decimal 1 @@ -205,25 +229,38 @@ Interoperable Address: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- 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. +### Versioning -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. +These rules ensure that future standards that build upon this one maintain backwards compatibility. -## Copyright -Copyright and related rights waived via [CC0](../LICENSE.md). +Future versions: - +- The `@` symbol is used as a separator as it provides visual clarity to humans, is easy for software to parse, and avoids confusion with the colon (`:`) symbol utilized in [CAIP-2] identifiers. +- No length restriction is placed on addresses, allowing for chains with longer address formats to be represented. +- The address field includes `%` as a valid character to allow for URL-encoded address formats. +- We chose to support zero-length addresses and chain IDs to make this standard flexible and to allow developers to use a single, uniform standard for many different jobs. +- We chose **not** to utilize alternate encoding formats (`base58` or `base64` for example) to reduce the size of the _Interoperable Address_ and/or to abstract away namespace specific address serialization standards. We decided that using the chain specific address formats that users are used to provides a better user experience. + + +## Security Considerations +This standard aims to be a foundation to allow for canonical representations of chain specific addresses. In the real world it can not be guaranteed that there will only be one valid representation of a chain specific address. For example, 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 that implementers requiring canonicity of addresses (if for example you are using them as keys in smart contract mappings), to thoroughly review the [CAIP-350] profile of a chain namespace for the possibility of a lack of canonicity. These considerations should be noted in the profile's 'Extra Considerations' section. + +## Copyright +Copyright and related rights waived via [CC0](../LICENSE.md). [ERC-55]: ./eip-55.md -[ERC-7785]: ./eip-7785.md [CAIP-2]: https://github.com/ChainAgnostic/CAIPs/blob/2a7d42aebaffa42d1017c702974395ff5c1b3636/CAIPs/caip-2.md [CAIP-10]: https://github.com/ChainAgnostic/CAIPs/blob/2a7d42aebaffa42d1017c702974395ff5c1b3636/CAIPs/caip-10.md [CAIP-50]: https://github.com/ChainAgnostic/CAIPs/blob/2a7d42aebaffa42d1017c702974395ff5c1b3636/CAIPs/caip-50.md