From c7c1209b53e9f3386fea14576e1b44bf8d1fc316 Mon Sep 17 00:00:00 2001 From: teddy Date: Wed, 12 Mar 2025 15:08:39 -0300 Subject: [PATCH 01/12] feat: rewrite as binary address POC --- ...ross-chain-interoperable-addresses-spec.md | 227 ++++++++++++++---- 1 file changed, 183 insertions(+), 44 deletions(-) diff --git a/specs/addresses/cross-chain-interoperable-addresses-spec.md b/specs/addresses/cross-chain-interoperable-addresses-spec.md index 3828beb..1860e90 100644 --- a/specs/addresses/cross-chain-interoperable-addresses-spec.md +++ b/specs/addresses/cross-chain-interoperable-addresses-spec.md @@ -1,7 +1,7 @@ # Cross-chain interoperable addresses specification This document, in its current state, aims to be the starting point for a future address format called 'Interoperable Address' whose aims & properties are fully described in [a separate document](../PROPERTIES.md) -Requires: CAIP-10 +Requires: RFC-4648, ENSIP-11, CAIP-2 ## Abstract An extensible way to describe an address specific to one chain which includes the information to securely condense it into a human-readable name. @@ -10,37 +10,122 @@ An extensible way to describe an address specific to one chain which includes th Similarly to CAIP-10, this specification is not concerned with the mapping from a chain id to a network name, which might not be surjective (eg: the case where if there are multiple EIP-155 chains with chain id 8453, which one should we call Base?), regarding that resolution a social-layer problem until a future ERC decides to tackle it. Efforts in that front are tracked in [the chain registires document](../docs/chain-registries.md) ## Definitions -Account id -: A string which unambiguously corresponds to an address on a specific chain (EVM or not). +Interoperable address +: A binary payload which includes both the information to unambiguosly point to a specific address on a specific chain and a _resolver specification_ which, together with this (and potentially future) ERCs, allows conversion to a human-readable name in a way that requires no further trust assumptions than those the wallet software executing said conversion already operates under. Human-readable name -: A shorter representation of an account id +: A string representation of an interoperable address, condensed into something that is to be consumed by humans. -Interoperable address -: A string which includes both an account id and a _resolver specification_ which, together with this (and potentially future) ERCs, allows conversion to a human-readable name in a way that requires no further trust assumptions than those the wallet software executing said conversion already operates under. +## Machine address format definition #1: easiest-calldata -## Machine address format definition +In order to maximize ease of use with most existing infrastructure, the format is deliberately solidity-ABI-compatible. For environments where solidity-ABI is not a native encoding, userspace parsers could be easily written. -### Syntax +This standard defines the format at the binary level, but for better readability, solidity structs with solidity types will be used throughout this document. -```bnf - ::= ::# - ::= : - ::= [0-9]{1,4} - ::= [-.%a-zA-Z0-9]* // same as CAIP-10 account address format - ::= [0-9a-f]{8} -``` - -### Semantics -- Similarly to CAIP-10, the resolver payload has `%` as a valid character to enable URL-escaping of arbitrary characters - - The rules for wether to parse URL escaping in a resolver payload are specific to the resolver version - - The rules for wether to parse URL escaping in a CAIP-10 account address are specific to its CAIP-2 chain namespace -- To maintain the bijectivity of account ids and therefore interoperable addresses to on-chain addresses: - - In CAIP-2 namespaces where there is a canonicalization scheme (such as EIP-55 in EIP-155 chains) it SHOULD be used. - - In CAIP-2 namespaces where addresses have an *optional* checksum field, it MUST be omitted and the checksum defined in the standard be used without redundancy - - In CAIP-2 namespaces where addresses are raw hexadecimal data without an EIP-55-equivalent capitalization scheme, the lowercase `a-f` characters MUST be used instead of uppercase ones. - - In the case of EIP-155 chains, EIP-55 canonicalization MUST be used -- The checksum MUST be the hexadecimal representation first four bytes of the keccak-256 hash of UTF-8 representation of the interoperable address from it's beginning up to and including the hash `#` character separating the checksum from the rest of the address. +The foundation for the Interoperable Address format is the following struct: + +```solidity +struct InteroperableAddress { + bytes32 version_checksum_reserved; + bytes chainId; + bytes address_; +} +``` + +where: + +`version` +: Defines the Interoperable Address version, which will be useful to know if to expect any extra fields at runtime. `uint16` stored in the most significant bits (240-255) of the `version_checksum_reserved` + +`checksum` +: A 4-byte value computed over the entirety of the Interoperable Address payload (details below). `bytes4` stored in bits (239-208) of `version_checksum_reserved` + +`reserved` +: Bytes that ABI-encoding would otherwise pad to zero, which can have specific uses in future versions of the standard. + +`chainid` +: Binary representation of the CAIP-2 blockchain id. See [Appendix A](#Appendix-A) + +`address_` +: Raw binary representation of the address in the chain. For `eip155` chains, this is trivial. Other chains can have different types of addresses which include more than just a public key, and those will be serialized as described in [Appendix B](#Appendix-B). + +## Machine address format definition #2: compact +The alternative above wastes a lot of space in order to be compliant with ABI spec. Another alternative is to define an address format with packing more similar to what is used for Solidity contract's storage layout. Addresses will be more compact in transit, but turning their components into Solidity types will not be trivial, requiring a library. + +### Word-by-word definition of the format + +#### Word 0: +``` +MSB LSB +0x0000000000000000000000000000000000000000000000000000000000000000 + ^^^^------------------------ 255-240 Interoperable Address version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \------------- 207-0 Reserved +``` + +#### Word 1: +Binary-encoded CAIP-2 blockchain id (following [Appendix A](#Appendix-A)) inside a short-packed bytes array, as described in [Appendix C](#Appendix-C). + +#### Word 2: +Binary-encoded address (following [Appendix B](#Appendix-B)) inside a short-packed bytes array, as described in [Appendix C](#Appendix-C). + +#### Word 3+: +Optionally used by the fields defined above, in the case chain ids or addresses are long enough to merit it. +Further words may be used by future versions of the standard + +## Checksum definition & validation +The high-level description of how to compute the checksum is: +- Set checksum to zero. +- Serialize the machine address. +- Compute the `keccak256` hash of the serialized address. +- Insert the first four bytes of the hash where the checksum is supposed to be +- Serialize the machine address again + +TODO: should the checksum go over the entire address, including the instructions on how to display it, or only the fields required for version zero? I'm specifying the former but leaning for the latter + +### Example +Assuming machine address format #1, CAIP-2 eip155 namespace has binary id `0x0001`, network is eth mainnet, and address in that network `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045`: + +``` +InteroperableAddress memory addy = InteroperableAddress({ + version_checksum_reserved: bytes32(uint256(uint16(2))) << 240, + chainId: hex'000101', + address_: hex'd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' +}); +``` +Serlialization with checksum set to zero: +``` +0x +0000000000000000000000000000000000000000000000000000000000000020 +0002000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000060 +00000000000000000000000000000000000000000000000000000000000000a0 +0000000000000000000000000000000000000000000000000000000000000003 +0001010000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000014 +d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000 +``` +keccak256 of the above: +``` +0xeb43550c612da0271a1f59bf6e9e4f3572139769ba88e9d05337d31fa1c2d2c2 +``` +Inserting the checksum into the address: +``` +addy.version_checksum_reserved |= bytes6(keccak256(abi.encode(addy))) >> 16; +``` +Serialized address including checksum: +``` +0x +0000000000000000000000000000000000000000000000000000000000000020 +0002eb43550c0000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000060 +00000000000000000000000000000000000000000000000000000000000000a0 +0000000000000000000000000000000000000000000000000000000000000003 +0001010000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000014 +d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000 +``` ## Human-readable name format definition @@ -53,16 +138,20 @@ Interoperable address ## Rationale - In order to guarantee future resolvers don't share prefixes with existing resolvers in an ambiguous way, and therefore human-readable names are always mappable to a single machine address, this standard defines the human-readable names to start with the resolver version. (TODO: ideally we should be smarter about this and resolve it in a way that doesn't expose this implementation quirk to users) -- Similarly to CAIP-10, arbitrary characters can be url-encoded. -## Resolver version definitions +## Encoding considerations +- on-chain actors, such as smart contracts, MUST always receive and return the machine addresses as byte array +- off-chain actors, such as wallets, MAY use the blockchain-native byte array representation, or, where practical MAY alternatively use base64 as defined in RFC-4648 to encode the former. +- users SHOULD NOT be shown the base64 or binary representations, instead, they should be shown the intended human-readable name or, in cases where that is not possible, falling back to interpreting it as Interoperable Address version zero. + +## Interoperable Address version definitions ### `0` : No resolution This is used to indicate no resolution, with the human-readable name being equal to the machine address. The machine address MUST be shown in full. #### Examples: Machine address -: `0:::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#6164da10` +: TODO Human-readable name : `0:::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#6164da10` @@ -72,7 +161,7 @@ This is used to indicate no resolution, but removing all redundant information t #### Examples: Machine address -: `1:::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#b50c58f9` +: TODO Human-readable name : `1::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045` @@ -92,7 +181,7 @@ EIP-55 or applicable scheme is used for canonicalization only. #### Examples: Machine address -: `2:::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#bc797def` +: TODO Human-readable name : `2::eth:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045` @@ -107,24 +196,20 @@ The chain/contract on which the ENSIP-11 contract used to resolve the human-read Also, wallets MAY have a default registry they use for converting human-readable names into machine addresses. This means different wallets could potentially resolve the same human-readable name to different machine addresses which potentially also map to different raw addresses. This should be mitigated by wallets' choices of valid and default registries. #### Human-readable name format - ```bnf ::= 3::@# ::= | ``` #### Machine-address format - -```bnf - ::= 3:::# -``` +TODO #### `machine address -> human-readable name` resolution -1. Extract CAIP-2 `chainId` and raw address from ``. +1. Extract CAIP-2 `chainId` and raw address from TODO - Failure mode: wallet can't call the contract (eg: does not have access to an rpc of that chain) - Failure mode: `chainId` is not an EVM address 2. Look up in wallet's 'trusted registry' set (which MAY be locally updated by the user) and see if the contract is contained in it. If it is not, issue a warning to the user. -3. Extract `chainId` and raw address from ``. +3. Extract `chainId` and raw address from `TODO`. 4. Convert `chainId` from step above into ENSIP-11 `coinType` 5. Compute the namehash for the ENSIP-19 reverse resolution from the results of step 3 and 4 - TODO: check if ambiguities or other edge cases are possible when converting from CAIP-10 into the raw form required by ENSIP-11 @@ -143,10 +228,9 @@ Also, wallets MAY have a default registry they use for converting human-readable 6. Call `addr(namehash, coinType)` on the wallet's default resolver, with the values from steps 5 and 2 respectively. - If it returns the zero address, prompt the user to pick another trusted resolver where the name is defined. - Failure mode: name cant be resolved with trusted resolvers. -7. Construct `` with the resolver used in the step above. -8. Construct `` with the address returned in step 6 and the destination chain from step 1. +7. Construct `TODO` with the resolver used in the step above. +8. Construct `TODO` with the address returned in step 6 and the destination chain from step 1. 9. The user should obviously not be prompted for the checksum, but it MUST be displayed somewhere in the wallet UI for the user to optionally validate with the receiver that they are using the same resolver. -10. Wallets MAY choose to display the full machine address as well. #### Pre-validations - The CAIP-2 `chain_id` included within both CAIP-10 account ids can be mapped to a valid ENSIP-11 `coinType` which extends both ENSIP-9 and SLIP44 @@ -164,7 +248,7 @@ Since it's possible for users' wallets to use different name registries by defau #### Examples: Machine address -: `3:eip155:1:0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e::eip155:10xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#5966be0f` +: TODO Human-readable name : `3::vitalik.eth@eth` @@ -174,7 +258,6 @@ Human-readable name - If the resolver lives in L1 or a name-specific rollup, then presumably it's feasible to run a light client of said network as part of the infrastructure trusted by the wallet ## Requirements for wallet software -- When parsing the CAIP-10 `account_address` for a CAIP-2 chain namespace where URL-escaping or the `%` character is not part of valid addresses, finding URL-encoded data MUST be treated as an error. - Wallet software MUST perform all relevant pre-validations, including verifying the checksum, and report any errors to the user, for every defined resolver. Wallets MAY reject an interoperable address solely on the basis of these checks failing. - TODO: what to do when a machine address' resolver version is not supported by the wallet - option 1: show it as is -> easiest @@ -184,9 +267,9 @@ Human-readable name TODO: probably coupled to ERC-7785, currently out of scope ## Rationale -- URL-escaping of characters might be necessary for future resolvers - Checksum algorithm is independent of used resolution method to allow wallets to validate an interoperable address' checksum despite not being able to generate its human-readable name - Ideally we'd want the resolution method to be fully abstracted away from the user, but that might not be achievable in every case. The next best thing is to prefix every human-readable name with a string denoting which method to use, which prevents the user ever being prompted to choose different addresses based on the resolution method used for each, which would be a more confusing and riskier UX +- Base64 was chosen since it is a more widely implemented standard than base58, and since machine addresses are not to be directly displayed to the user, the collision-avoidance reasons in favor of base58 do not apply ## Compatibility with other public-key sharing standards @@ -195,3 +278,59 @@ TODO ## Security considerations +## Appendix A: Binary encoding of CAIP-2 blockchain id +First two bytes are the binary representation of CAIP-2 namespace (see table below), rest are the CAIP-2 reference. +In the special case of eip155 chains, the bare `chainid` encoded as a `uint` of the necessary amount of bytes will be used [^1]. This allows for the existing EVM chainids fit inside one EVM word. +Reference will be the ASCII-encoded value from CAIP-2 (from, and not including, the colon, up to the end of the string) in all other cases. + +[^1]: This makes it possible to represent some chains using the full word as their chainid, which CAIP-2 does not support since the maximum value representable with 32 `a-zA-Z0-9` characters is less than `type(uint256).max`. This is done in an effort to support chains whose id is the output of `keccak256`, as proposed in ERC-7785. + +### CAIP-2 namespaces' binary representation table +TODO + +### Examples +TODO + +## Appendix B: Binary encoding of addresses +TODO, will be similar to ENSIP-9 and/or CAIP-50 + +### Examples +TODO + +## Appendix C: Short-encoding of byte arrays +This is a mix between [how bytes and strings are saved into storage](https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html#bytes-and-string) and how ABI encoding works + +This arises out of: +- The need to have the shortest possible representation for EVM addresses. +- Not having a canonical place to delimit the _start_ of the data (in the case of storage strings, it's the keccak256 hash of the storage slot index). + +If the data is at most 31 bytes long, the elements are stored in the higher-order bytes (left aligned) and the lowest-order byte stores the value `length * 2`. + +If the data is 32 bytes or longer, the current word stores `length * 2 + 1`, and data follows in the next words, left-aligned and zero-padded. + +This means access to + +### Examples + +`0x1234`: `0x1234000000000000000000000000000000000000000000000000000000000005` + +`0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1234`: `0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12343E` + +`0x00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF`: +``` +0x +0000000000000000000000000000000000000000000000000000000000000041 +00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF +``` + +`0x00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF0011`: +``` +0x +0000000000000000000000000000000000000000000000000000000000000045 +00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF +0011000000000000000000000000000000000000000000000000000000000000 +``` + + +TODO: +- Consider tradeoffs of following a head-tail encoding scheme a la ABI, instead of packing the data right after. It would be possible to pack the (relative to current position? absolute to start of payload?) offset into 16 bytes, and use the remaining 16 bytes for `length * 2 + 1`. From 47bd95e3b4a4c02490a6d23c806837937dbc9664 Mon Sep 17 00:00:00 2001 From: teddy Date: Wed, 12 Mar 2025 15:12:56 -0300 Subject: [PATCH 02/12] fix: cant index compact format over words --- .../cross-chain-interoperable-addresses-spec.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/specs/addresses/cross-chain-interoperable-addresses-spec.md b/specs/addresses/cross-chain-interoperable-addresses-spec.md index 1860e90..8afdb6b 100644 --- a/specs/addresses/cross-chain-interoperable-addresses-spec.md +++ b/specs/addresses/cross-chain-interoperable-addresses-spec.md @@ -64,15 +64,15 @@ MSB LSB \------------- 207-0 Reserved ``` -#### Word 1: -Binary-encoded CAIP-2 blockchain id (following [Appendix A](#Appendix-A)) inside a short-packed bytes array, as described in [Appendix C](#Appendix-C). +#### Field 1: +Binary-encoded CAIP-2 blockchain id (following [Appendix A](#Appendix-A)) inside a short-packed bytes array, as described in [Appendix C](#Appendix-C), taking 1 or more 32-byte words. -#### Word 2: -Binary-encoded address (following [Appendix B](#Appendix-B)) inside a short-packed bytes array, as described in [Appendix C](#Appendix-C). +#### Field 2: +Binary-encoded address (following [Appendix B](#Appendix-B)) inside a short-packed bytes array, as described in [Appendix C](#Appendix-C), taking 1 or more 32-byte words. -#### Word 3+: +#### Field 3+: Optionally used by the fields defined above, in the case chain ids or addresses are long enough to merit it. -Further words may be used by future versions of the standard +Further fields may be used by future versions of the standard ## Checksum definition & validation The high-level description of how to compute the checksum is: From 4289e33ecd187257185902cf6371cbeed3e865a7 Mon Sep 17 00:00:00 2001 From: teddy Date: Fri, 14 Mar 2025 12:00:55 -0300 Subject: [PATCH 03/12] feat: go for shortest representation --- ...ross-chain-interoperable-addresses-spec.md | 292 ++++++------------ 1 file changed, 96 insertions(+), 196 deletions(-) diff --git a/specs/addresses/cross-chain-interoperable-addresses-spec.md b/specs/addresses/cross-chain-interoperable-addresses-spec.md index 8afdb6b..a3d9aba 100644 --- a/specs/addresses/cross-chain-interoperable-addresses-spec.md +++ b/specs/addresses/cross-chain-interoperable-addresses-spec.md @@ -16,45 +16,11 @@ Interoperable address Human-readable name : A string representation of an interoperable address, condensed into something that is to be consumed by humans. -## Machine address format definition #1: easiest-calldata - -In order to maximize ease of use with most existing infrastructure, the format is deliberately solidity-ABI-compatible. For environments where solidity-ABI is not a native encoding, userspace parsers could be easily written. - -This standard defines the format at the binary level, but for better readability, solidity structs with solidity types will be used throughout this document. - -The foundation for the Interoperable Address format is the following struct: - -```solidity -struct InteroperableAddress { - bytes32 version_checksum_reserved; - bytes chainId; - bytes address_; -} -``` - -where: - -`version` -: Defines the Interoperable Address version, which will be useful to know if to expect any extra fields at runtime. `uint16` stored in the most significant bits (240-255) of the `version_checksum_reserved` - -`checksum` -: A 4-byte value computed over the entirety of the Interoperable Address payload (details below). `bytes4` stored in bits (239-208) of `version_checksum_reserved` - -`reserved` -: Bytes that ABI-encoding would otherwise pad to zero, which can have specific uses in future versions of the standard. - -`chainid` -: Binary representation of the CAIP-2 blockchain id. See [Appendix A](#Appendix-A) - -`address_` -: Raw binary representation of the address in the chain. For `eip155` chains, this is trivial. Other chains can have different types of addresses which include more than just a public key, and those will be serialized as described in [Appendix B](#Appendix-B). - -## Machine address format definition #2: compact +## Machine address format definition The alternative above wastes a lot of space in order to be compliant with ABI spec. Another alternative is to define an address format with packing more similar to what is used for Solidity contract's storage layout. Addresses will be more compact in transit, but turning their components into Solidity types will not be trivial, requiring a library. -### Word-by-word definition of the format - -#### Word 0: +### Format definition +Word 0 Is the only word which will be common to all versions, and is defined as follows: ``` MSB LSB 0x0000000000000000000000000000000000000000000000000000000000000000 @@ -64,198 +30,111 @@ MSB LSB \------------- 207-0 Reserved ``` -#### Field 1: -Binary-encoded CAIP-2 blockchain id (following [Appendix A](#Appendix-A)) inside a short-packed bytes array, as described in [Appendix C](#Appendix-C), taking 1 or more 32-byte words. - -#### Field 2: -Binary-encoded address (following [Appendix B](#Appendix-B)) inside a short-packed bytes array, as described in [Appendix C](#Appendix-C), taking 1 or more 32-byte words. +No length restriction is placed on how many more words can an Interoperable Address span. Different versions of the standard can define uses for extra words and the 208 reserved bits. -#### Field 3+: -Optionally used by the fields defined above, in the case chain ids or addresses are long enough to merit it. -Further fields may be used by future versions of the standard - -## Checksum definition & validation -The high-level description of how to compute the checksum is: -- Set checksum to zero. -- Serialize the machine address. -- Compute the `keccak256` hash of the serialized address. -- Insert the first four bytes of the hash where the checksum is supposed to be -- Serialize the machine address again - -TODO: should the checksum go over the entire address, including the instructions on how to display it, or only the fields required for version zero? I'm specifying the former but leaning for the latter - -### Example -Assuming machine address format #1, CAIP-2 eip155 namespace has binary id `0x0001`, network is eth mainnet, and address in that network `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045`: - -``` -InteroperableAddress memory addy = InteroperableAddress({ - version_checksum_reserved: bytes32(uint256(uint16(2))) << 240, - chainId: hex'000101', - address_: hex'd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' -}); -``` -Serlialization with checksum set to zero: -``` -0x -0000000000000000000000000000000000000000000000000000000000000020 -0002000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000060 -00000000000000000000000000000000000000000000000000000000000000a0 -0000000000000000000000000000000000000000000000000000000000000003 -0001010000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000014 -d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000 -``` -keccak256 of the above: -``` -0xeb43550c612da0271a1f59bf6e9e4f3572139769ba88e9d05337d31fa1c2d2c2 -``` -Inserting the checksum into the address: -``` -addy.version_checksum_reserved |= bytes6(keccak256(abi.encode(addy))) >> 16; -``` -Serialized address including checksum: -``` -0x -0000000000000000000000000000000000000000000000000000000000000020 -0002eb43550c0000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000060 -00000000000000000000000000000000000000000000000000000000000000a0 -0000000000000000000000000000000000000000000000000000000000000003 -0001010000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000014 -d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000 -``` +### Restrictions for future versions +- The Interoperable Address MUST include an address on a particular chain and MUST also specify on which chain said address exists. +- Interoperable Address versions MAY only be able to represent a subset of the CAIP-2 namespaces +- Interoperable Address versions MAY define extra fields containing information on how to display the addresses. ## Human-readable name format definition ### Syntax ```bnf - ::= = - ::= [0-9]{1,4} - ::= [@-.%a-zA-Z0-9]* + ::= @ + ::= TODO + ::= TODO ``` -## Rationale -- In order to guarantee future resolvers don't share prefixes with existing resolvers in an ambiguous way, and therefore human-readable names are always mappable to a single machine address, this standard defines the human-readable names to start with the resolver version. (TODO: ideally we should be smarter about this and resolve it in a way that doesn't expose this implementation quirk to users) - ## Encoding considerations -- on-chain actors, such as smart contracts, MUST always receive and return the machine addresses as byte array -- off-chain actors, such as wallets, MAY use the blockchain-native byte array representation, or, where practical MAY alternatively use base64 as defined in RFC-4648 to encode the former. -- users SHOULD NOT be shown the base64 or binary representations, instead, they should be shown the intended human-readable name or, in cases where that is not possible, falling back to interpreting it as Interoperable Address version zero. +- On-chain actors, such as smart contracts, MUST always receive and return the machine addresses as byte array +- Off-chain actors, such as wallets, MAY use the blockchain-native byte array representation, or, where practical MAY alternatively use base64 as defined in RFC-4648 to encode the former. +- Users SHOULD NOT be shown the base64 or binary representations, instead, they should be shown the intended human-readable name or, in cases where that is not possible, falling back to interpreting it as Interoperable Address version TODO. ## Interoperable Address version definitions -### `0` : No resolution -This is used to indicate no resolution, with the human-readable name being equal to the machine address. The machine address MUST be shown in full. +### `0x0000` : single-word 48-bit EVM chainids, no human-readable name resolution +This encoding is meant to be the shortest possible way to encode most EVM addresses -#### Examples: -Machine address -: TODO +#### Supported chains +EVM chains with a chainid shorter than 48 bits (which potentially rules out chainids chosen to comply with ERC-7785) -Human-readable name -: `0:::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#6164da10` +#### Machine-address format -### `1` : No resolution, compact format -This is used to indicate no resolution, but removing all redundant information that can be verified by the wallet. It is equivalent to the CAIP-10 account id, with the canonicalization caveat described above. +``` +MSB LSB +0x0000000000000000000000000000000000000000000000000000000000000000 + ^^^^------------------------ 255-240 Interoperable Address version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^ + \------------- 207-160 Chainid + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \- 159-0 Address +``` -#### Examples: -Machine address -: TODO +`Interoperable Address version` +: Always `0x0000` -Human-readable name -: `1::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045` +`Checksum` +: Computed as described in [Appendix D](#Appendix-D) -### `2` : ERC-3770 chain name resolution only -The human-readable name in this approach is consistent with the address format defined in ERC-3770, and similarly depends on the EF's mapping of chain ids to names maintained in github at: https://github.com/ethereum-lists/chains +`Chainid` +: `uint48` containing the chainId for the target chain -#### Human-readable name format +`Address` +: Native EVM address -```bnf - ::= 2::: -``` -Since wallet software can always validate the checksum, it MUST be removed. +#### Human-readable name resolution +The CAIP-2 namespace is to be rendered alongside the `0x`-prefixed EIP-55 address and the checksum -EIP-55 or applicable scheme is used for canonicalization only. +``` +
@# +``` #### Examples: - Machine address -: TODO +: +``` +MSB LSB +0x0000618ad0d1000000000001D8DA6BF26964AF9D7EED9E03E53415D37AA96045 + ^^^^------------------------ 255-240 Interoperable Address version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^ + \------------- 207-160 Chainid + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \- 159-0 Address +``` Human-readable name -: `2::eth:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045` +: `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#6164da10@eip155:1#618ad0d1` -### `3` : ENSIP-11 + ENSIP-19 for raw address resolution + ethereum-lists chain name resolution -This resolver relies on the centralized [SLIP44](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) list for ENS standards compliance and on the one used by ERC-3770 to define the short chain names. +### `0x0001` : Compact format, ENSIP-11+ERC-3770 name resolution +The binary representation is identical to the format above, with the exception that the version number is different, indicating the intent for the chain to be displayed using the ERC-3770 shortname and the address to be displayed following mainnet's ENS deployment and ENSIP-11 -The machine address, in turn, specifies what will the source of truth be for the `raw address -> ens-like name` mapping, expecting it to conform to ENSIP-11. - -The chain/contract on which the ENSIP-11 contract used to resolve the human-readable name resides is abstracted away from the user, but implementing wallets MUST maintain a list of those considered trustworthy and warn the user or choose to display the machine address in full when the contract it instructs to use is outside the set. - -Also, wallets MAY have a default registry they use for converting human-readable names into machine addresses. This means different wallets could potentially resolve the same human-readable name to different machine addresses which potentially also map to different raw addresses. This should be mitigated by wallets' choices of valid and default registries. - -#### Human-readable name format -```bnf - ::= 3::@# - ::= | -``` +#### Supported chains +Chain must be listed on ethereum-lists/chains on top of the restrictions as `0x0000`. #### Machine-address format -TODO - -#### `machine address -> human-readable name` resolution -1. Extract CAIP-2 `chainId` and raw address from TODO - - Failure mode: wallet can't call the contract (eg: does not have access to an rpc of that chain) - - Failure mode: `chainId` is not an EVM address -2. Look up in wallet's 'trusted registry' set (which MAY be locally updated by the user) and see if the contract is contained in it. If it is not, issue a warning to the user. -3. Extract `chainId` and raw address from `TODO`. -4. Convert `chainId` from step above into ENSIP-11 `coinType` -5. Compute the namehash for the ENSIP-19 reverse resolution from the results of step 3 and 4 - - TODO: check if ambiguities or other edge cases are possible when converting from CAIP-10 into the raw form required by ENSIP-11 -6. Call `resolver(bytes32 node)`on the contract obtained in step 1, using the value from the step above for `node`. -7. Call `name(bytes32 node)` on the contract returned by the step above. Save the response as the ``. -8. Check direct resolution of name obtained in the step above, and fail the resolution if it does not match, as described in ENSIP-19 -9. For the ``, extract the CAIP-2 chain id from ``. If said chain has an entry in ethereum-lists, display its shortname. Otherwise, display the raw CAIP-2 chain id. -10. Append the checksum from the machine address. - -#### `human-readable name -> machine address ` resolution -1. Let the user input a destination chain name, and convert it to a CAIP-2 chainId. -2. Convert the result from step 1 into an ENSIP-11 `coinType`. -3. Let the user input a unicode string instead of the punycode-encoded name. -4. Convert the string from step 3 into a punycode-encoded name. -5. Compute the punycode-encoded name's namehash. -6. Call `addr(namehash, coinType)` on the wallet's default resolver, with the values from steps 5 and 2 respectively. - - If it returns the zero address, prompt the user to pick another trusted resolver where the name is defined. - - Failure mode: name cant be resolved with trusted resolvers. -7. Construct `TODO` with the resolver used in the step above. -8. Construct `TODO` with the address returned in step 6 and the destination chain from step 1. -9. The user should obviously not be prompted for the checksum, but it MUST be displayed somewhere in the wallet UI for the user to optionally validate with the receiver that they are using the same resolver. - -#### Pre-validations -- The CAIP-2 `chain_id` included within both CAIP-10 account ids can be mapped to a valid ENSIP-11 `coinType` which extends both ENSIP-9 and SLIP44 - -#### Semantics -- ENS uses [punycode](https://www.unicode.org/reports/tr46/) to encode non-ascii characters, which SHOULD be rendered by wallets. In cases where the wallet could infer the presence of non-ascii characters to be unlikely (eg: depending on locale), a warning MAY also be issued to the user. -- `` is to be the fully qualified name, including the TLD. -- For chains listed in `ethereum-lists/chains`, the short name MUST be used, taking precedence over the CAIP-2 chain id. - -#### Rationale -This is proposed as a way to have functional human readable names with existing tooling and infrastructure, while being flexible in not enshrining a particular contract to allow for future changes on where & how names are resolved. Future developments in chain configs and name registries should improve upon it's decentralization characteristics and render it obsolete in the long-term. - -Since it's possible for users' wallets to use different name registries by default when computing a machine address from a human-readable name, the checksum for the machine address is provided as a layer of defense against losing funds either by mis-configuration or deliberate attacks taking advantage of the differences between the data contained in different naming registries. +Same as `0x0000`, with `0x0001` version #### Examples: - Machine address -: TODO +: +``` +MSB LSB +0x0001618ad0d1000000000001D8DA6BF26964AF9D7EED9E03E53415D37AA96045 + ^^^^------------------------ 255-240 Interoperable Address version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^ + \------------- 207-160 Chainid + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \- 159-0 Address +``` Human-readable name -: `3::vitalik.eth@eth` +: `vitalik.eth@eth#618ad0d1` -#### Security considerations -- If the resolver lives in the destination/source chains, then securing a trustworthy RPC is already in scope of the wallet's responsibilities to operate safely -- If the resolver lives in L1 or a name-specific rollup, then presumably it's feasible to run a light client of said network as part of the infrastructure trusted by the wallet +TODO: example on another chain ## Requirements for wallet software - Wallet software MUST perform all relevant pre-validations, including verifying the checksum, and report any errors to the user, for every defined resolver. Wallets MAY reject an interoperable address solely on the basis of these checks failing. @@ -308,7 +187,7 @@ If the data is at most 31 bytes long, the elements are stored in the higher-orde If the data is 32 bytes or longer, the current word stores `length * 2 + 1`, and data follows in the next words, left-aligned and zero-padded. -This means access to +This means access to an arbitrary field in the structure requires a worst-case linear amount of reads. Future encodings using it should take it into consideration to put less-frequently-accessed members last. ### Examples @@ -331,6 +210,27 @@ This means access to 0011000000000000000000000000000000000000000000000000000000000000 ``` - TODO: -- Consider tradeoffs of following a head-tail encoding scheme a la ABI, instead of packing the data right after. It would be possible to pack the (relative to current position? absolute to start of payload?) offset into 16 bytes, and use the remaining 16 bytes for `length * 2 + 1`. +- Consider tradeoffs of following a head-tail encoding scheme a la ABI, instead of packing the data right after. It would be possible to pack the (relative to current position? absolute to start of payload?) offset into 16 bytes, and use the remaining 16 bytes for `length * 2 + 1`. (pro of this approach: not possible to add extra data between fields which is invisible to parsers like is possible with abi encoding) + +## Appendix D: checksum computation +With the intent of: +- Maximizing the difficulty of mining checksum collisions +- Maximize the safety a user gets from knowing the checksum matches +- Allow maximum flexibility for human-readable names, leveraging the above to make collisions permissible + +We propose a way to serialize the 'abstract' components of an address, ignoring the information on how it should be displayed, to achieve the above: + +```solidity + function getChecksum(bytes2 caip2Namespace, bytes memory chainid, bytes memory address_) + internal + view + returns (bytes4 checksum) + { + bytes memory fullChainid = bytes.concat(caip2Namespace, chainid); + bytes memory serialized = abi.encode(fullChainid, address_); + bytes32 hashed = keccak256(serialized); + checksum = bytes4(hashed); + } +``` +TODO: describe this in a way which is not potentially coupled to solidity (or even a specific version of it) From b8f7a687b3bdab1181029bb582c858c364ea6e38 Mon Sep 17 00:00:00 2001 From: teddy Date: Mon, 17 Mar 2025 12:20:45 -0300 Subject: [PATCH 04/12] feat: Standard Long Format --- ...ross-chain-interoperable-addresses-spec.md | 204 ++++++++++++------ 1 file changed, 144 insertions(+), 60 deletions(-) diff --git a/specs/addresses/cross-chain-interoperable-addresses-spec.md b/specs/addresses/cross-chain-interoperable-addresses-spec.md index a3d9aba..1c5b9f7 100644 --- a/specs/addresses/cross-chain-interoperable-addresses-spec.md +++ b/specs/addresses/cross-chain-interoperable-addresses-spec.md @@ -3,23 +3,49 @@ This document, in its current state, aims to be the starting point for a future Requires: RFC-4648, ENSIP-11, CAIP-2 -## Abstract -An extensible way to describe an address specific to one chain which includes the information to securely condense it into a human-readable name. +# Abstract +An extensible way to describe an address specific to one chain which also includes the information to securely condense it into a human-readable name. -## Out of scope concerns +# Out of scope concerns Similarly to CAIP-10, this specification is not concerned with the mapping from a chain id to a network name, which might not be surjective (eg: the case where if there are multiple EIP-155 chains with chain id 8453, which one should we call Base?), regarding that resolution a social-layer problem until a future ERC decides to tackle it. Efforts in that front are tracked in [the chain registires document](../docs/chain-registries.md) -## Definitions +# Definitions Interoperable address -: A binary payload which includes both the information to unambiguosly point to a specific address on a specific chain and a _resolver specification_ which, together with this (and potentially future) ERCs, allows conversion to a human-readable name in a way that requires no further trust assumptions than those the wallet software executing said conversion already operates under. +: A binary payload which includes both the information to unambiguously point to a specific address on a specific chain and a _resolver specification_ which, together with this (and potentially future) ERCs, allows conversion to a human-readable name in a way that requires no further trust assumptions than those the wallet software executing said conversion already operates under. Human-readable name : A string representation of an interoperable address, condensed into something that is to be consumed by humans. -## Machine address format definition +# Restrictions for future versions +- The Interoperable Address MUST include an address on a particular chain and MUST also specify on which chain said address exists. +- Interoperable Address versions MAY only be able to represent a subset of the CAIP-2 namespaces. +- Interoperable Address versions MAY define extra fields containing information on how to display the addresses. +- The most significant version bit is reserved to mean an address complies with the Interoperable Long Format, described in Interoperable Address version `0x8000`. + +# Requirements for wallet software +- Wallet software MUST perform all relevant pre-validations, including verifying the checksum, and report any errors to the user, for every defined resolver. Wallets MAY reject an interoperable address solely on the basis of these checks failing. + +# Rationale +- Checksum algorithm is independent of used resolution method to allow wallets to validate an interoperable address' checksum despite not being able to generate its human-readable name +- Base64 was chosen since it is a more widely implemented standard than base58, and since machine addresses are not to be directly displayed to the user, the collision-avoidance reasons in favor of base58 do not apply + +# Encoding considerations +- On-chain actors, such as smart contracts, MUST always receive and return the machine addresses as byte array +- Off-chain actors, such as wallets, MAY use the blockchain-native byte array representation, or, where practical MAY alternatively use base64 as defined in RFC-4648 to encode the former. +- Users SHOULD NOT be shown the base64 or binary representations, instead, they should be shown the intended human-readable name or, in cases where that is not possible, falling back to interpreting it as Interoperable Address version `0x8000`. + +# Compatibility with other public-key sharing standards + +## W3C DID +TODO + +# Security considerations +TODO + +# Machine address format definition The alternative above wastes a lot of space in order to be compliant with ABI spec. Another alternative is to define an address format with packing more similar to what is used for Solidity contract's storage layout. Addresses will be more compact in transit, but turning their components into Solidity types will not be trivial, requiring a library. -### Format definition +## Format definition Word 0 Is the only word which will be common to all versions, and is defined as follows: ``` MSB LSB @@ -32,34 +58,31 @@ MSB LSB No length restriction is placed on how many more words can an Interoperable Address span. Different versions of the standard can define uses for extra words and the 208 reserved bits. -### Restrictions for future versions -- The Interoperable Address MUST include an address on a particular chain and MUST also specify on which chain said address exists. -- Interoperable Address versions MAY only be able to represent a subset of the CAIP-2 namespaces -- Interoperable Address versions MAY define extra fields containing information on how to display the addresses. +TODO: consider making this format 31 bytes and define standard ways to pad it so it can be saved in a `bytes` array taking only one word. -## Human-readable name format definition +# Human-readable name format definition -### Syntax +## Syntax ```bnf - ::= @ - ::= TODO - ::= TODO + ::= @# + ::= [-:_%a-zA-Z0-9]* + ::= [-:_a-zA-Z0-9]* + ::= [0-9A-F]{8} ``` -## Encoding considerations -- On-chain actors, such as smart contracts, MUST always receive and return the machine addresses as byte array -- Off-chain actors, such as wallets, MAY use the blockchain-native byte array representation, or, where practical MAY alternatively use base64 as defined in RFC-4648 to encode the former. -- Users SHOULD NOT be shown the base64 or binary representations, instead, they should be shown the intended human-readable name or, in cases where that is not possible, falling back to interpreting it as Interoperable Address version TODO. +## Rationale +- Chain and account fields' syntax is deliberately chosen to be able to express CAIP-2 namespaces 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 account field includes `%` as a valid character to allow for url-encoding of any other characters. -## Interoperable Address version definitions +# Interoperable Address version definitions -### `0x0000` : single-word 48-bit EVM chainids, no human-readable name resolution +## `0x0000` : single-word 48-bit EVM chainids, no human-readable name resolution This encoding is meant to be the shortest possible way to encode most EVM addresses -#### Supported chains +### Supported chains EVM chains with a chainid shorter than 48 bits (which potentially rules out chainids chosen to comply with ERC-7785) -#### Machine-address format +### Machine-address format ``` MSB LSB @@ -84,14 +107,14 @@ MSB LSB `Address` : Native EVM address -#### Human-readable name resolution +### Human-readable name resolution The CAIP-2 namespace is to be rendered alongside the `0x`-prefixed EIP-55 address and the checksum ```
@# ``` -#### Examples: +### Examples: Machine address : ``` @@ -108,16 +131,16 @@ MSB LSB Human-readable name : `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#6164da10@eip155:1#618ad0d1` -### `0x0001` : Compact format, ENSIP-11+ERC-3770 name resolution +## `0x0001` : Compact format, ENSIP-11+ERC-3770 name resolution The binary representation is identical to the format above, with the exception that the version number is different, indicating the intent for the chain to be displayed using the ERC-3770 shortname and the address to be displayed following mainnet's ENS deployment and ENSIP-11 -#### Supported chains +### Supported chains Chain must be listed on ethereum-lists/chains on top of the restrictions as `0x0000`. -#### Machine-address format +### Machine-address format Same as `0x0000`, with `0x0001` version -#### Examples: +### Examples: Machine address : ``` @@ -136,47 +159,103 @@ Human-readable name TODO: example on another chain -## Requirements for wallet software -- Wallet software MUST perform all relevant pre-validations, including verifying the checksum, and report any errors to the user, for every defined resolver. Wallets MAY reject an interoperable address solely on the basis of these checks failing. -- TODO: what to do when a machine address' resolver version is not supported by the wallet - - option 1: show it as is -> easiest - - option 2: convert it to resolver `1` -> guarantees not-that-bad-to-read address is shown to the user, might impose extra constraints on existing resolvers. +## `0x8000`: Standard Long Format: arbitrary length addresses, CAIP-10 display format -## Recommendations for rollups -TODO: probably coupled to ERC-7785, currently out of scope +### Machine-address format -## Rationale -- Checksum algorithm is independent of used resolution method to allow wallets to validate an interoperable address' checksum despite not being able to generate its human-readable name -- Ideally we'd want the resolution method to be fully abstracted away from the user, but that might not be achievable in every case. The next best thing is to prefix every human-readable name with a string denoting which method to use, which prevents the user ever being prompted to choose different addresses based on the resolution method used for each, which would be a more confusing and riskier UX -- Base64 was chosen since it is a more widely implemented standard than base58, and since machine addresses are not to be directly displayed to the user, the collision-avoidance reasons in favor of base58 do not apply +#### First word +Does not make use of reserved bits +``` +MSB LSB +0x8000XXXXXXXX0000000000000000000000000000000000000000000000000000 + ^^^^------------------------ 255-240 Interoperable Address version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \--------------- 207-0 Reserved +``` -## Compatibility with other public-key sharing standards +#### Second field +Serializes the chainid described in [Appendix A](#Appendix-A) and encodes it into a byte array as described in [Appendix C](#Appendix-C). It is a _field_ and not a _word_, since it may take up more than one word -### W3C DID -TODO +#### Third field +Serializes the address described in [Appendix A](#Appendix-A) and encodes it into a byte array as described in [Appendix C](#Appendix-C). It is a _field_ and not a _word_, since it may take up more than one word, and may not start at the third word boundary if the second field takes up more than one word. -## Security considerations +### Human-readable name resolution +The CAIP-2 namespace is to be rendered alongside the CAIP-10 formatted address and the checksum: -## Appendix A: Binary encoding of CAIP-2 blockchain id -First two bytes are the binary representation of CAIP-2 namespace (see table below), rest are the CAIP-2 reference. -In the special case of eip155 chains, the bare `chainid` encoded as a `uint` of the necessary amount of bytes will be used [^1]. This allows for the existing EVM chainids fit inside one EVM word. -Reference will be the ASCII-encoded value from CAIP-2 (from, and not including, the colon, up to the end of the string) in all other cases. +``` +@# +``` -[^1]: This makes it possible to represent some chains using the full word as their chainid, which CAIP-2 does not support since the maximum value representable with 32 `a-zA-Z0-9` characters is less than `type(uint256).max`. This is done in an effort to support chains whose id is the output of `keccak256`, as proposed in ERC-7785. +### Examples -### CAIP-2 namespaces' binary representation table -TODO +Human-readable name: +`0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#6164DA10@eip155:1#618ad0d1`: -### Examples -TODO +First word: +``` +MSB LSB +0x80006164DA100000000000000000000000000000000000000000000000000000 + ^^^^------------------------ 255-240 Interoperable Address version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \--------------- 207-0 Not used +``` + +Second word (second field): +``` +MSB LSB +0x0100000000000000000000000000000000000000000000000000000000000002 + ^^----------------------------------------------------------------- 255-249 bytes array payload + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- 9-249 padding + ^^ -- 0-8 2*1 (payload length) +``` -## Appendix B: Binary encoding of addresses +Third word (third field): +``` +MSB LSB +0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045000000000000000000000028 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------------- 255-97 bytes array payload + ^^^^^^^^^^^^^^^^^^^^^^ ---- 9-96 padding + ^^ -- 0-8 2*20 (payload length) +``` + +# Appendix A: Binary encoding of CAIP-2 blockchain id +First two bytes are the binary representation of CAIP-2 namespace (see table below), rest are the CAIP-2 reference, whose encoding is namespace-specific and defined below. + +## CAIP-2 namespaces' binary representation table + +| Namespace | binary key | +| --- | --- | +| eip155 | `0x0000` | +| bip122 | `0x0001` | + +### eip155 +The bare `chainid` encoded as a `uint` of the necessary amount of bytes will be used [^1]. This allows for most of existing EVM chainids to fit inside one EVM word. + +[^1]: This makes it possible to represent some chains using the full word as their chainid, which CAIP-2 does not support since the set of values representable with 32 `a-zA-Z0-9` characters has less than `type(uint256).max` elements. This is done in an effort to support chains whose id is the output of `keccak256`, as proposed in ERC-7785. + +#### Examples +Ethereum Mainnet: `0x000001` (1, encoded as uint8) +Optimism Mainnet: `0x00000A` (10, encoded as uint8) +Ethereum Sepolia: `0x0000aa36a7` (11155111, encoded as uint24) + +### bip122 +The genesis/fork blockhash is to be stored raw, without encoding/decoding from/to base58btc, and without removing any leading zeroes: + +Note: CAIP-2 has a 32 character limit on chain references which means converting to them will require truncating the reference, and converting _from_ CAIP-2 to this standard is potentially ambiguous (but converting from actual bip122 to this standard will never be) + +#### Examples +Bitcoin Mainnet: `0x0001000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f` +Litecoin: `0x000112a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2` + +# Appendix B: Binary encoding of addresses TODO, will be similar to ENSIP-9 and/or CAIP-50 -### Examples +## Examples TODO -## Appendix C: Short-encoding of byte arrays +# Appendix C: Short-encoding of byte arrays This is a mix between [how bytes and strings are saved into storage](https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html#bytes-and-string) and how ABI encoding works This arises out of: @@ -189,7 +268,7 @@ If the data is 32 bytes or longer, the current word stores `length * 2 + 1`, and This means access to an arbitrary field in the structure requires a worst-case linear amount of reads. Future encodings using it should take it into consideration to put less-frequently-accessed members last. -### Examples +## Examples `0x1234`: `0x1234000000000000000000000000000000000000000000000000000000000005` @@ -213,11 +292,15 @@ This means access to an arbitrary field in the structure requires a worst-case l TODO: - Consider tradeoffs of following a head-tail encoding scheme a la ABI, instead of packing the data right after. It would be possible to pack the (relative to current position? absolute to start of payload?) offset into 16 bytes, and use the remaining 16 bytes for `length * 2 + 1`. (pro of this approach: not possible to add extra data between fields which is invisible to parsers like is possible with abi encoding) -## Appendix D: checksum computation +# Appendix D: checksum computation With the intent of: - Maximizing the difficulty of mining checksum collisions - Maximize the safety a user gets from knowing the checksum matches -- Allow maximum flexibility for human-readable names, leveraging the above to make collisions permissible +- Allow maximum flexibility for human-readable names, leveraging the above to make human-readable name collisions permissible + +And considering: +- Binary payloads will often have their own error-correction mechanisms when in transit (eg: if encoded into a QR code, said QR code will have information redundancy & its own checksum ensuring only valid data can be decoded), so that can safely be deemed out of scope. +TODO: Considering the above, does it make sense to store the checksum inside the address? We propose a way to serialize the 'abstract' components of an address, ignoring the information on how it should be displayed, to achieve the above: @@ -228,6 +311,7 @@ We propose a way to serialize the 'abstract' components of an address, ignoring returns (bytes4 checksum) { bytes memory fullChainid = bytes.concat(caip2Namespace, chainid); + // Deliberately abi-encode instead of encode-packed to avoid preimage collisions bytes memory serialized = abi.encode(fullChainid, address_); bytes32 hashed = keccak256(serialized); checksum = bytes4(hashed); From 79237e5660dcbbba3ad6fac4017ce3cee436a826 Mon Sep 17 00:00:00 2001 From: teddy Date: Mon, 17 Mar 2025 17:51:40 -0300 Subject: [PATCH 05/12] fix: small clarifications --- ...ross-chain-interoperable-addresses-spec.md | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/specs/addresses/cross-chain-interoperable-addresses-spec.md b/specs/addresses/cross-chain-interoperable-addresses-spec.md index 1c5b9f7..f7ad852 100644 --- a/specs/addresses/cross-chain-interoperable-addresses-spec.md +++ b/specs/addresses/cross-chain-interoperable-addresses-spec.md @@ -10,17 +10,20 @@ An extensible way to describe an address specific to one chain which also includ Similarly to CAIP-10, this specification is not concerned with the mapping from a chain id to a network name, which might not be surjective (eg: the case where if there are multiple EIP-155 chains with chain id 8453, which one should we call Base?), regarding that resolution a social-layer problem until a future ERC decides to tackle it. Efforts in that front are tracked in [the chain registires document](../docs/chain-registries.md) # Definitions -Interoperable address +Interoperable Address : A binary payload which includes both the information to unambiguously point to a specific address on a specific chain and a _resolver specification_ which, together with this (and potentially future) ERCs, allows conversion to a human-readable name in a way that requires no further trust assumptions than those the wallet software executing said conversion already operates under. Human-readable name : A string representation of an interoperable address, condensed into something that is to be consumed by humans. # Restrictions for future versions -- The Interoperable Address MUST include an address on a particular chain and MUST also specify on which chain said address exists. +- The Interoperable Address MUST include an address on a particular chain and MUST also specify on which chain said address exists. A version requiring an indirection layer between data contained in the payload and the two fields described above would be in infringement of this restriction. - Interoperable Address versions MAY only be able to represent a subset of the CAIP-2 namespaces. - Interoperable Address versions MAY define extra fields containing information on how to display the addresses. - The most significant version bit is reserved to mean an address complies with the Interoperable Long Format, described in Interoperable Address version `0x8000`. +- The second-most significant version bit is reserved to mean the payload includes information on how to display the address to users, but is not normative about how that information is to be encoded. An example of this is provided in Interoperable Address version `0xC000`. + +In short, the above means any Interoperable Address should be trivially convertible to Interoperable Long Format, `0x8000`, making all other versions second-class citizens to it. # Requirements for wallet software - Wallet software MUST perform all relevant pre-validations, including verifying the checksum, and report any errors to the user, for every defined resolver. Wallets MAY reject an interoperable address solely on the basis of these checks failing. @@ -42,10 +45,7 @@ TODO # Security considerations TODO -# Machine address format definition -The alternative above wastes a lot of space in order to be compliant with ABI spec. Another alternative is to define an address format with packing more similar to what is used for Solidity contract's storage layout. Addresses will be more compact in transit, but turning their components into Solidity types will not be trivial, requiring a library. - -## Format definition +# Binary Format definition Word 0 Is the only word which will be common to all versions, and is defined as follows: ``` MSB LSB @@ -58,7 +58,7 @@ MSB LSB No length restriction is placed on how many more words can an Interoperable Address span. Different versions of the standard can define uses for extra words and the 208 reserved bits. -TODO: consider making this format 31 bytes and define standard ways to pad it so it can be saved in a `bytes` array taking only one word. +TODO: consider making this format 31 bytes and define standard ways to pad it so it can be _saved_ in a `bytes` array taking only one word (ABI representation would not be significantly cheaper though). # Human-readable name format definition @@ -135,7 +135,7 @@ Human-readable name The binary representation is identical to the format above, with the exception that the version number is different, indicating the intent for the chain to be displayed using the ERC-3770 shortname and the address to be displayed following mainnet's ENS deployment and ENSIP-11 ### Supported chains -Chain must be listed on ethereum-lists/chains on top of the restrictions as `0x0000`. +Chain must be listed on ethereum-lists/chains on top of the restrictions of `0x0000`. ### Machine-address format Same as `0x0000`, with `0x0001` version @@ -155,7 +155,7 @@ MSB LSB ``` Human-readable name -: `vitalik.eth@eth#618ad0d1` +: `vitalik.eth@eth#618AD0D1` TODO: example on another chain @@ -220,6 +220,8 @@ MSB LSB ^^ -- 0-8 2*20 (payload length) ``` +TODO: example with multi-word fields + # Appendix A: Binary encoding of CAIP-2 blockchain id First two bytes are the binary representation of CAIP-2 namespace (see table below), rest are the CAIP-2 reference, whose encoding is namespace-specific and defined below. From d506076b0f15490db523bf473474279ed9f8cfc0 Mon Sep 17 00:00:00 2001 From: teddy Date: Mon, 17 Mar 2025 18:20:49 -0300 Subject: [PATCH 06/12] chore: fix links --- .../cross-chain-interoperable-addresses-spec.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/specs/addresses/cross-chain-interoperable-addresses-spec.md b/specs/addresses/cross-chain-interoperable-addresses-spec.md index f7ad852..57217f6 100644 --- a/specs/addresses/cross-chain-interoperable-addresses-spec.md +++ b/specs/addresses/cross-chain-interoperable-addresses-spec.md @@ -7,7 +7,7 @@ Requires: RFC-4648, ENSIP-11, CAIP-2 An extensible way to describe an address specific to one chain which also includes the information to securely condense it into a human-readable name. # Out of scope concerns -Similarly to CAIP-10, this specification is not concerned with the mapping from a chain id to a network name, which might not be surjective (eg: the case where if there are multiple EIP-155 chains with chain id 8453, which one should we call Base?), regarding that resolution a social-layer problem until a future ERC decides to tackle it. Efforts in that front are tracked in [the chain registires document](../docs/chain-registries.md) +Similarly to CAIP-10, this specification is not concerned with the mapping from a chain id to a network name, which might not be surjective (eg: the case where if there are multiple EIP-155 chains with chain id 8453, which one should we call Base?), regarding that resolution a social-layer problem until a future ERC decides to tackle it. Efforts in that front are tracked in [the chain registries document](../docs/chain-registries.md) # Definitions Interoperable Address @@ -99,7 +99,8 @@ MSB LSB : Always `0x0000` `Checksum` -: Computed as described in [Appendix D](#Appendix-D) +: Computed as described in [Appendix D](#appendix-d-checksum-computation) + `Chainid` : `uint48` containing the chainId for the target chain @@ -175,10 +176,10 @@ MSB LSB ``` #### Second field -Serializes the chainid described in [Appendix A](#Appendix-A) and encodes it into a byte array as described in [Appendix C](#Appendix-C). It is a _field_ and not a _word_, since it may take up more than one word +Serializes the chainid described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). It is a _field_ and not a _word_, since it may take up more than one word #### Third field -Serializes the address described in [Appendix A](#Appendix-A) and encodes it into a byte array as described in [Appendix C](#Appendix-C). It is a _field_ and not a _word_, since it may take up more than one word, and may not start at the third word boundary if the second field takes up more than one word. +Serializes the address described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). It is a _field_ and not a _word_, since it may take up more than one word, and may not start at the third word boundary if the second field takes up more than one word. ### Human-readable name resolution The CAIP-2 namespace is to be rendered alongside the CAIP-10 formatted address and the checksum: From 9f2b11b872703e8fe27db466e9de4a61165a3391 Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 18 Mar 2025 11:23:33 -0300 Subject: [PATCH 07/12] feat: 0xC000 address version --- ...ross-chain-interoperable-addresses-spec.md | 100 +++++++++++++++++- 1 file changed, 96 insertions(+), 4 deletions(-) diff --git a/specs/addresses/cross-chain-interoperable-addresses-spec.md b/specs/addresses/cross-chain-interoperable-addresses-spec.md index 57217f6..c1cfa28 100644 --- a/specs/addresses/cross-chain-interoperable-addresses-spec.md +++ b/specs/addresses/cross-chain-interoperable-addresses-spec.md @@ -42,9 +42,6 @@ In short, the above means any Interoperable Address should be trivially converti ## W3C DID TODO -# Security considerations -TODO - # Binary Format definition Word 0 Is the only word which will be common to all versions, and is defined as follows: ``` @@ -101,7 +98,6 @@ MSB LSB `Checksum` : Computed as described in [Appendix D](#appendix-d-checksum-computation) - `Chainid` : `uint48` containing the chainId for the target chain @@ -223,6 +219,102 @@ MSB LSB TODO: example with multi-word fields +## `0xC000`: Standard Long Format With Resolver Info: arbitrary length addresses, arbitrary length resolver specification + +### Machine-address format + +#### First word +Uses reserved bits as a registry of interfaces the provided resolver conforms to. +``` +MSB LSB +0xC000XXXXXXXX0000000000000000000000000000000000000000000000000000 + ^^^^------------------------ 255-240 Interoperable Address version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \--------------- 207-0 Resolver Interface Key +``` +The Resolver Interface Key defines how wallets should interact with the smart contract responsible for assigning names to addresses. +Said contract MAY be responsible for naming the chain on which the target address resides as well as providing a human-readable name for the address. + +#### Second field +Serializes the chainid where the target account is located as described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). + +#### Third field +Serializes the address of the target account as described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). + +#### Fourth field +Serializes the chainid where the name-resolving contract is located as described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). + +#### Fifth field +Serializes the address of the name-resolving contract as described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). + +### Human-readable name resolution +Specific to every Resolver Interface Key + +### Resolver Interface Keys + +#### `0x0000000000000000000000000000000000000000000000000000` +Responsibility over discovering the interface of the naming smart contract is delegated to the contract itself, via mechanisms comparable to `ERC165`, out of scope for this definition. + +#### `0x0000000000000000000000000000000000000000000000000001` +Naming contract is expected to conform to ENSIP-11. ENSIP-11 does not name chains, so the CAIP-2 name should be used instead. + +### Examples + +Human-readable name: +`vitalik.eth@eip155:1#618AD0D1`: + +First word: metadata +``` +MSB LSB +0xC0006164DA100000000000000000000000000000000000000000000000000001 + ^^^^------------------------ 255-240 Interoperable Address version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \--------------- 207-0 Resolver Interface Key +``` + +Second word (second field): target address' chainid +``` +MSB LSB +0x0100000000000000000000000000000000000000000000000000000000000002 + ^^----------------------------------------------------------------- 255-249 bytes array payload + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- 9-249 padding + ^^ -- 0-8 2*1 (payload length) +``` + +Third word (third field): target address +``` +MSB LSB +0XD8DA6BF26964AF9D7EED9E03E53415D37AA96045000000000000000000000028 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------------- 255-97 bytes array payload + ^^^^^^^^^^^^^^^^^^^^^^ ---- 9-96 padding + ^^ -- 0-8 2*20 (payload length) +``` + +Fourth word (fourth field): name resolving contract's chainid +``` +MSB LSB +0x0100000000000000000000000000000000000000000000000000000000000002 + ^^----------------------------------------------------------------- 255-249 bytes array payload + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- 9-249 padding + ^^ -- 0-8 2*1 (payload length) +``` + +Fifth word (fifth field): name resolving contract's address +``` +MSB LSB +0X00000000000C2E074EC69A0DFB2997BA6C7D2E1E000000000000000000000028 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------------- 255-97 bytes array payload + ^^^^^^^^^^^^^^^^^^^^^^ ---- 9-96 padding + ^^ -- 0-8 2*20 (payload length) +``` + +TODO: example with other ENSIP-11 contract + +### Security considerations +TODO + # Appendix A: Binary encoding of CAIP-2 blockchain id First two bytes are the binary representation of CAIP-2 namespace (see table below), rest are the CAIP-2 reference, whose encoding is namespace-specific and defined below. From cef0fac7ef280f5f56bde31ac2d7b207ffe35852 Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 18 Mar 2025 14:09:09 -0300 Subject: [PATCH 08/12] fix: wording and definitions --- ...ross-chain-interoperable-addresses-spec.md | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/specs/addresses/cross-chain-interoperable-addresses-spec.md b/specs/addresses/cross-chain-interoperable-addresses-spec.md index c1cfa28..b9f560a 100644 --- a/specs/addresses/cross-chain-interoperable-addresses-spec.md +++ b/specs/addresses/cross-chain-interoperable-addresses-spec.md @@ -16,27 +16,33 @@ Interoperable Address Human-readable name : A string representation of an interoperable address, condensed into something that is to be consumed by humans. +Target address +: The (address, chainid) pair a particular Interoperable Address points to. + +Name-resolving contract +: A contract where responsibility over converting addresses and/or chainids in a format meant for machine consumption over to parts of a human-readable name. + # Restrictions for future versions -- The Interoperable Address MUST include an address on a particular chain and MUST also specify on which chain said address exists. A version requiring an indirection layer between data contained in the payload and the two fields described above would be in infringement of this restriction. +- The Interoperable Address MUST include an address on a particular chain and MUST also specify on which chain said address exists, fully defining a target address. A version requiring an indirection layer between data contained in the payload and the two fields described above would be in infringement of this restriction. - Interoperable Address versions MAY only be able to represent a subset of the CAIP-2 namespaces. - Interoperable Address versions MAY define extra fields containing information on how to display the addresses. - The most significant version bit is reserved to mean an address complies with the Interoperable Long Format, described in Interoperable Address version `0x8000`. - The second-most significant version bit is reserved to mean the payload includes information on how to display the address to users, but is not normative about how that information is to be encoded. An example of this is provided in Interoperable Address version `0xC000`. -In short, the above means any Interoperable Address should be trivially convertible to Interoperable Long Format, `0x8000`, making all other versions second-class citizens to it. +# Guarantees provided by the standard +- Any Interoperable Address is trivially convertible to Interoperable Long Format, `0x8000`, making it a canonical representation for users who need to treat them opaquely. +- Checksums are short enough to be compared by humans, and effectively identify a _target address_ independently of any extra data the address may contain. # Requirements for wallet software -- Wallet software MUST perform all relevant pre-validations, including verifying the checksum, and report any errors to the user, for every defined resolver. Wallets MAY reject an interoperable address solely on the basis of these checks failing. - -# Rationale -- Checksum algorithm is independent of used resolution method to allow wallets to validate an interoperable address' checksum despite not being able to generate its human-readable name -- Base64 was chosen since it is a more widely implemented standard than base58, and since machine addresses are not to be directly displayed to the user, the collision-avoidance reasons in favor of base58 do not apply +- Wallet software MUST perform all relevant pre-validations, including verifying the checksum, and report any errors to the user. Wallets MAY reject an interoperable address solely on the basis of these checks failing. # Encoding considerations -- On-chain actors, such as smart contracts, MUST always receive and return the machine addresses as byte array -- Off-chain actors, such as wallets, MAY use the blockchain-native byte array representation, or, where practical MAY alternatively use base64 as defined in RFC-4648 to encode the former. +- On-chain actors, such as smart contracts, MUST always receive and return the machine addresses as byte array. +- Off-chain actors, such as wallets, MAY use the blockchain-native byte array representation, or, where practical MAY alternatively use base64 [^2] as defined in RFC-4648 to encode the former. - Users SHOULD NOT be shown the base64 or binary representations, instead, they should be shown the intended human-readable name or, in cases where that is not possible, falling back to interpreting it as Interoperable Address version `0x8000`. +[^2]: Base64 was chosen since it is a more widely implemented standard than base58, and since machine addresses are not to be directly displayed to the user, the collision-avoidance reasons in favor of base58 do not apply + # Compatibility with other public-key sharing standards ## W3C DID @@ -172,10 +178,10 @@ MSB LSB ``` #### Second field -Serializes the chainid described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). It is a _field_ and not a _word_, since it may take up more than one word +Serializes the chainid as described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). It is a _field_ and not a _word_, since it may take up more than one word #### Third field -Serializes the address described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). It is a _field_ and not a _word_, since it may take up more than one word, and may not start at the third word boundary if the second field takes up more than one word. +Serializes the address as described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). It is a _field_ and not a _word_, since it may take up more than one word, and may not start at the third word boundary if the second field takes up more than one word. ### Human-readable name resolution The CAIP-2 namespace is to be rendered alongside the CAIP-10 formatted address and the checksum: @@ -219,7 +225,7 @@ MSB LSB TODO: example with multi-word fields -## `0xC000`: Standard Long Format With Resolver Info: arbitrary length addresses, arbitrary length resolver specification +## `0xC000`: Standard Long Format With Resolver Info: arbitrary length addresses, arbitrary length name-resolving contract specification ### Machine-address format @@ -234,13 +240,13 @@ MSB LSB \--------------- 207-0 Resolver Interface Key ``` The Resolver Interface Key defines how wallets should interact with the smart contract responsible for assigning names to addresses. -Said contract MAY be responsible for naming the chain on which the target address resides as well as providing a human-readable name for the address. +Said contract MAY also be responsible for naming the chain on which the target address resides as well as providing a human-readable name for the address, when ERC-7785 or similar standards reach production. #### Second field -Serializes the chainid where the target account is located as described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). +Serializes the chainid of the target address as described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). #### Third field -Serializes the address of the target account as described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). +Serializes the address of the target address as described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). #### Fourth field Serializes the chainid where the name-resolving contract is located as described in [Appendix A](#appendix-a-binary-encoding-of-caip-2-blockchain-id) and encodes it into a byte array as described in [Appendix C](#appendix-c-short-encoding-of-byte-arrays). @@ -257,7 +263,7 @@ Specific to every Resolver Interface Key Responsibility over discovering the interface of the naming smart contract is delegated to the contract itself, via mechanisms comparable to `ERC165`, out of scope for this definition. #### `0x0000000000000000000000000000000000000000000000000001` -Naming contract is expected to conform to ENSIP-11. ENSIP-11 does not name chains, so the CAIP-2 name should be used instead. +Naming contract is expected to conform to ENSIP-11, and used to display the address. ENSIP-11 does not name chains, so the CAIP-2 name should be used instead. ### Examples @@ -313,7 +319,7 @@ MSB LSB TODO: example with other ENSIP-11 contract ### Security considerations -TODO +- Wallets will have to maintain a list of Resolver Interface Keys they support, and which name-resolving contracts they consider trustworthy, and display addresses as described in `0x8000` when the provided name-resolving contract is not contained in the list. Said list MAY be updateable by the user. # Appendix A: Binary encoding of CAIP-2 blockchain id First two bytes are the binary representation of CAIP-2 namespace (see table below), rest are the CAIP-2 reference, whose encoding is namespace-specific and defined below. From 25749c41bc059c52ec651e61604b7c9793963620 Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 18 Mar 2025 14:20:40 -0300 Subject: [PATCH 09/12] chore: ordering --- ...ross-chain-interoperable-addresses-spec.md | 210 +++++++++--------- 1 file changed, 105 insertions(+), 105 deletions(-) diff --git a/specs/addresses/cross-chain-interoperable-addresses-spec.md b/specs/addresses/cross-chain-interoperable-addresses-spec.md index b9f560a..21024b3 100644 --- a/specs/addresses/cross-chain-interoperable-addresses-spec.md +++ b/specs/addresses/cross-chain-interoperable-addresses-spec.md @@ -22,32 +22,10 @@ Target address Name-resolving contract : A contract where responsibility over converting addresses and/or chainids in a format meant for machine consumption over to parts of a human-readable name. -# Restrictions for future versions -- The Interoperable Address MUST include an address on a particular chain and MUST also specify on which chain said address exists, fully defining a target address. A version requiring an indirection layer between data contained in the payload and the two fields described above would be in infringement of this restriction. -- Interoperable Address versions MAY only be able to represent a subset of the CAIP-2 namespaces. -- Interoperable Address versions MAY define extra fields containing information on how to display the addresses. -- The most significant version bit is reserved to mean an address complies with the Interoperable Long Format, described in Interoperable Address version `0x8000`. -- The second-most significant version bit is reserved to mean the payload includes information on how to display the address to users, but is not normative about how that information is to be encoded. An example of this is provided in Interoperable Address version `0xC000`. - # Guarantees provided by the standard - Any Interoperable Address is trivially convertible to Interoperable Long Format, `0x8000`, making it a canonical representation for users who need to treat them opaquely. - Checksums are short enough to be compared by humans, and effectively identify a _target address_ independently of any extra data the address may contain. -# Requirements for wallet software -- Wallet software MUST perform all relevant pre-validations, including verifying the checksum, and report any errors to the user. Wallets MAY reject an interoperable address solely on the basis of these checks failing. - -# Encoding considerations -- On-chain actors, such as smart contracts, MUST always receive and return the machine addresses as byte array. -- Off-chain actors, such as wallets, MAY use the blockchain-native byte array representation, or, where practical MAY alternatively use base64 [^2] as defined in RFC-4648 to encode the former. -- Users SHOULD NOT be shown the base64 or binary representations, instead, they should be shown the intended human-readable name or, in cases where that is not possible, falling back to interpreting it as Interoperable Address version `0x8000`. - -[^2]: Base64 was chosen since it is a more widely implemented standard than base58, and since machine addresses are not to be directly displayed to the user, the collision-avoidance reasons in favor of base58 do not apply - -# Compatibility with other public-key sharing standards - -## W3C DID -TODO - # Binary Format definition Word 0 Is the only word which will be common to all versions, and is defined as follows: ``` @@ -79,89 +57,6 @@ TODO: consider making this format 31 bytes and define standard ways to pad it so # Interoperable Address version definitions -## `0x0000` : single-word 48-bit EVM chainids, no human-readable name resolution -This encoding is meant to be the shortest possible way to encode most EVM addresses - -### Supported chains -EVM chains with a chainid shorter than 48 bits (which potentially rules out chainids chosen to comply with ERC-7785) - -### Machine-address format - -``` -MSB LSB -0x0000000000000000000000000000000000000000000000000000000000000000 - ^^^^------------------------ 255-240 Interoperable Address version - ^^^^^^^^ --------------- 239-208 Checksum - ^^^^^^^^^^^^ - \------------- 207-160 Chainid - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - \- 159-0 Address -``` - -`Interoperable Address version` -: Always `0x0000` - -`Checksum` -: Computed as described in [Appendix D](#appendix-d-checksum-computation) - -`Chainid` -: `uint48` containing the chainId for the target chain - -`Address` -: Native EVM address - -### Human-readable name resolution -The CAIP-2 namespace is to be rendered alongside the `0x`-prefixed EIP-55 address and the checksum - -``` -
@# -``` - -### Examples: -Machine address -: -``` -MSB LSB -0x0000618ad0d1000000000001D8DA6BF26964AF9D7EED9E03E53415D37AA96045 - ^^^^------------------------ 255-240 Interoperable Address version - ^^^^^^^^ --------------- 239-208 Checksum - ^^^^^^^^^^^^ - \------------- 207-160 Chainid - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - \- 159-0 Address -``` - -Human-readable name -: `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#6164da10@eip155:1#618ad0d1` - -## `0x0001` : Compact format, ENSIP-11+ERC-3770 name resolution -The binary representation is identical to the format above, with the exception that the version number is different, indicating the intent for the chain to be displayed using the ERC-3770 shortname and the address to be displayed following mainnet's ENS deployment and ENSIP-11 - -### Supported chains -Chain must be listed on ethereum-lists/chains on top of the restrictions of `0x0000`. - -### Machine-address format -Same as `0x0000`, with `0x0001` version - -### Examples: -Machine address -: -``` -MSB LSB -0x0001618ad0d1000000000001D8DA6BF26964AF9D7EED9E03E53415D37AA96045 - ^^^^------------------------ 255-240 Interoperable Address version - ^^^^^^^^ --------------- 239-208 Checksum - ^^^^^^^^^^^^ - \------------- 207-160 Chainid - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - \- 159-0 Address -``` - -Human-readable name -: `vitalik.eth@eth#618AD0D1` - -TODO: example on another chain - ## `0x8000`: Standard Long Format: arbitrary length addresses, CAIP-10 display format ### Machine-address format @@ -321,6 +216,111 @@ TODO: example with other ENSIP-11 contract ### Security considerations - Wallets will have to maintain a list of Resolver Interface Keys they support, and which name-resolving contracts they consider trustworthy, and display addresses as described in `0x8000` when the provided name-resolving contract is not contained in the list. Said list MAY be updateable by the user. +## `0x0000` : single-word 48-bit EVM chainids, no human-readable name resolution +This encoding is meant to be the shortest possible way to encode most EVM addresses + +### Supported chains +EVM chains with a chainid shorter than 48 bits (which potentially rules out chainids chosen to comply with ERC-7785) + +### Machine-address format + +``` +MSB LSB +0x0000000000000000000000000000000000000000000000000000000000000000 + ^^^^------------------------ 255-240 Interoperable Address version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^ + \------------- 207-160 Chainid + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \- 159-0 Address +``` + +`Interoperable Address version` +: Always `0x0000` + +`Checksum` +: Computed as described in [Appendix D](#appendix-d-checksum-computation) + +`Chainid` +: `uint48` containing the chainId for the target chain + +`Address` +: Native EVM address + +### Human-readable name resolution +The CAIP-2 namespace is to be rendered alongside the `0x`-prefixed EIP-55 address and the checksum + +``` +
@# +``` + +### Examples: +Machine address +: +``` +MSB LSB +0x0000618ad0d1000000000001D8DA6BF26964AF9D7EED9E03E53415D37AA96045 + ^^^^------------------------ 255-240 Interoperable Address version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^ + \------------- 207-160 Chainid + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \- 159-0 Address +``` + +Human-readable name +: `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#6164da10@eip155:1#618ad0d1` + +## `0x0001` : Compact format, ENSIP-11+ERC-3770 name resolution +The binary representation is identical to the format above, with the exception that the version number is different, indicating the intent for the chain to be displayed using the ERC-3770 shortname and the address to be displayed following mainnet's ENS deployment and ENSIP-11 + +### Supported chains +Chain must be listed on ethereum-lists/chains on top of the restrictions of `0x0000`. + +### Machine-address format +Same as `0x0000`, with `0x0001` version + +### Examples: +Machine address +: +``` +MSB LSB +0x0001618ad0d1000000000001D8DA6BF26964AF9D7EED9E03E53415D37AA96045 + ^^^^------------------------ 255-240 Interoperable Address version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^ + \------------- 207-160 Chainid + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \- 159-0 Address +``` + +Human-readable name +: `vitalik.eth@eth#618AD0D1` + +TODO: example on another chain + +# Restrictions for future versions +- The Interoperable Address MUST include an address on a particular chain and MUST also specify on which chain said address exists, fully defining a target address. A version requiring an indirection layer between data contained in the payload and the two fields described above would be in infringement of this restriction. +- Interoperable Address versions MAY only be able to represent a subset of the CAIP-2 namespaces. +- Interoperable Address versions MAY define extra fields containing information on how to display the addresses. +- The most significant version bit is reserved to mean an address complies with the Interoperable Long Format, described in Interoperable Address version `0x8000`. +- The second-most significant version bit is reserved to mean the payload includes information on how to display the address to users, but is not normative about how that information is to be encoded. An example of this is provided in Interoperable Address version `0xC000`. + +# Requirements for wallet software +- Wallet software MUST perform all relevant pre-validations, including verifying the checksum, and report any errors to the user. Wallets MAY reject an interoperable address solely on the basis of these checks failing. + +# Encoding considerations +- On-chain actors, such as smart contracts, MUST always receive and return the machine addresses as byte array. +- Off-chain actors, such as wallets, MAY use the blockchain-native byte array representation, or, where practical MAY alternatively use base64 [^2] as defined in RFC-4648 to encode the former. +- Users SHOULD NOT be shown the base64 or binary representations, instead, they should be shown the intended human-readable name or, in cases where that is not possible, falling back to interpreting it as Interoperable Address version `0x8000`. + +[^2]: Base64 was chosen since it is a more widely implemented standard than base58, and since machine addresses are not to be directly displayed to the user, the collision-avoidance reasons in favor of base58 do not apply + +# Compatibility with other public-key sharing standards + +## W3C DID +TODO + # Appendix A: Binary encoding of CAIP-2 blockchain id First two bytes are the binary representation of CAIP-2 namespace (see table below), rest are the CAIP-2 reference, whose encoding is namespace-specific and defined below. From d9121a31977b89facf5b1c5e6d3019be4dcbdad0 Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 18 Mar 2025 23:47:55 -0300 Subject: [PATCH 10/12] docs: update explainer for binary addresses --- .../interoperable-address-explainer.md | 136 +++++++++++++----- 1 file changed, 101 insertions(+), 35 deletions(-) diff --git a/docs/addresses/interoperable-address-explainer.md b/docs/addresses/interoperable-address-explainer.md index a44f196..e0575ec 100644 --- a/docs/addresses/interoperable-address-explainer.md +++ b/docs/addresses/interoperable-address-explainer.md @@ -1,54 +1,120 @@ Introducing: Interoperable Addresses ==== -*Specs in the formal format are written [here](/specs/addresses/cross-chain-interoperable-addresses-spec.md)*. +*Specs in the formal, normative format are written [here](/specs/addresses/cross-chain-interoperable-addresses-spec.md)*. Interoperable Addresses is a standard defining address formats for a multi-chain world. -For a normal user, they look like this: +They contain the following information: -

- - 3::vitalik.eth@eth#5966be0f - -

+```solidity + struct InteroperableAddress { + bytes chainId; + bytes address_; + bytes nameContractChain; + bytes nameContractAddress; + } +``` -- 3::: the Interoperable Address Resolver version, which your wallet may very well omit. -- vitalik.eth: A human-readable name, specific to a chain. Supported by (anything looking like) ENS. -- eth: A human-readable chain name, defined by either https://github.com/ethereum-lists/chains if available (same registry for ERC-3770) or CAIP-2 in all other cases. -- 5966be0f: A checksum so you can at a glance validate what you see matches what you expect to be under the hood. +Let's take an example: ---- +
+InteroperableAddres addy = InteroperableAddress({
+    chainId: hex'000001',
+    address_: hex'D8DA6BF26964AF9D7EED9E03E53415D37AA96045',
+    nameContractChain: hex'000001',
+    nameContractAddress: hex'00000000000C2E074EC69A0DFB2997BA6C7D2E1E'
+})
+
-For nerds and computers, however, they look like this: +Would be seen by users like this: -

- - 3:eip155:1:0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#5966be0f - -

+
+    0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@eip:155:1#618AD0D1
+
-- 3:: Interoperable Address version. -- eip155:1: CAIP-2 id of chain where the naming registry is located -- 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e: Address where to find the naming registry -- eip155:1: CAIP-2 id of chain we are referring to -- 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045: Chain-specific address we are targeting in that chain -- 5966be0f: Checksum of all previous fields, to make sure nothing got lost in transit +...and in memory, it would actually be laid out like this: ---- +
+C000618AD0D10000000000000000000000000000000000000000000000000001
+0000010000000000000000000000000000000000000000000000000000000006
+D8DA6BF26964AF9D7EED9E03E53415D37AA96045000000000000000000000028
+0000010000000000000000000000000000000000000000000000000000000006
+00000000000C2E074EC69A0DFB2997BA6C7D2E1E000000000000000000000028
+
-The Interoperable Address is a format for strings to: -- Fully specify an address on a particular chain (using CAIP-10), supporting any EVM-ecosystem chain and any chain on SLIP-044. -- Also include the information to display it to a human in a readable way, as displayed above. +It includes: +- A full specification of what (address,chain) pair we're referring to +- A full specification of on which (address,chain) pair the contract responsible for resolving addresses to names lives +- ... and a full 32-byte word before any of that? -Some of its features are: -- Uses mature technologies such as CAIP-10 and ENS. -- Is extensible for future resolving mechanisms (eg: ERC-7785, when/if it reaches production). -- Resolution of Interoperable Addresses to human readable names is fully deterministic. +Said word is what enables us to make this standard extensible, let's take a closer look: + +
+MSB                                                          LSB
+C0006164DA100000000000000000000000000000000000000000000000000001
+^^^^------------------------ 255-240 Interoperable Address Version
+    ^^^^^^^^ --------------- 239-208 Checksum
+            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+            \--------------- 207-0   Resolver Interface Key
+
+ +- Interoperable Address Version: First two bytes of the payload allows us to discern how we should interpret it, more on this later +- Checksum: Covers only the (address,chain) we are referring to -> is independent of the method used to display the address, or how it is serialized -> makes naming collisions evident +- Resolver Interface Key: in addresses version `0xC000`, instructs us on what to expect from `nameContractAddress` and `nameContractChain`. In particular, this value means to expect an ENSIP-11 contract. + +But wait! I actually want... +- A canonical representation: use Interoperable Address Version `0x8000` +- To be as space-efficient as possible for EVM chains: use Interoperable Address Version `0x0000` or `0x0001` +- To display human-readable chain names to users, but not rely on centralized lists: define a new 'Resolver Interface Key' as soon as ERC-7785 reaches production + +What some other resolvers look like: + +`0x0000`: +``` +MSB LSB +0x0000618ad0d1000000000001D8DA6BF26964AF9D7EED9E03E53415D37AA96045 + ^^^^------------------------ 255-240 Interoperable Address version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^ + \------------- 207-160 Chainid + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \- 159-0 Address +``` +Is represented as: +`0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@eip155:1#618AD0D1` + +`0x8000`: +``` +MSB LSB +0000618AD0D10000000000000000000000000000000000000000000000000000 +^^^^------------------------ 255-240 Interoperable Address Version + ^^^^^^^^ --------------- 239-208 Checksum + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + \------------- 207-0 not used, always zero +MSB LSB +0100000000000000000000000000000000000000000000000000000000000002 +^^----------------------------------------------------------------- 255-249 bytes array payload + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- 9-249 padding + ^^ -- 0-8 2*1 (payload length) +MSB LSB +D8DA6BF26964AF9D7EED9E03E53415D37AA96045000000000000000000000028 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------------- 255-97 bytes array payload + ^^^^^^^^^^^^^^^^^^^^^^ ---- 9-96 padding + ^^ -- 0-8 2*20 (payload length) +``` +Is represented as: +`0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@eip155:1#618AD0D1` + +Some properties of this system: +- Interoperable addresses of any version can always be converted to format `0x8000` -> forwards-compatibility and graceful degradation of interfaces. +- Interoperable addresses of any version can always be casted to a valid CAIP-10. +- Addresses of any length in chains of any supported CAIP-2 namespace can be represented +- Future-proofing for developments on future resolving mechanisms. +- Implementable right now with current tools & standards. - Edge cases are securely abstractable to a library/SDK for wallets. -- Does not enshrine a particular ENS contract, making it flexible for a future naming-only rollup, instances on other rollups or even an ENS fork. +- Does not enshrine a particular naming contract, making it flexible for a future naming-only rollup, instances on other rollups or even an ENS competitor. -And, in all honesty, it has some drawbacks as well: -- Exposes a version number to users (although that can be mitigated by wallet UX) +And, in all honesty, some drawbacks as well: - Supporting different name resolution contracts mean human-readable name -> machine address resolution can produce different results (which is mitigated by the checksum) - Wallets will have to maintain a set of name resolving contracts considered trustworthy, with a trust model similar to RPC urls (can be taken care of by a library/SDK, but user overrides should be supported). From 8ef71315d672073f39bdd7a99c7ddfafb2b70cb6 Mon Sep 17 00:00:00 2001 From: teddy Date: Thu, 20 Mar 2025 16:47:17 -0300 Subject: [PATCH 11/12] fix: fixes for show&tell working group presentation --- .../interoperable-address-explainer.md | 59 +++++++++++-------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/docs/addresses/interoperable-address-explainer.md b/docs/addresses/interoperable-address-explainer.md index e0575ec..45c14e9 100644 --- a/docs/addresses/interoperable-address-explainer.md +++ b/docs/addresses/interoperable-address-explainer.md @@ -1,7 +1,7 @@ Introducing: Interoperable Addresses ==== -*Specs in the formal, normative format are written [here](/specs/addresses/cross-chain-interoperable-addresses-spec.md)*. +*Specs in the formal, normative format can be found [here](/specs/addresses/cross-chain-interoperable-addresses-spec.md)*. Interoperable Addresses is a standard defining address formats for a multi-chain world. @@ -9,37 +9,37 @@ They contain the following information: ```solidity struct InteroperableAddress { - bytes chainId; - bytes address_; - bytes nameContractChain; - bytes nameContractAddress; + bytes targetChainId; + bytes targetAddress; + bytes resolverChainId; + bytes resolverAddress; } ``` Let's take an example:
-InteroperableAddres addy = InteroperableAddress({
-    chainId: hex'000001',
-    address_: hex'D8DA6BF26964AF9D7EED9E03E53415D37AA96045',
-    nameContractChain: hex'000001',
-    nameContractAddress: hex'00000000000C2E074EC69A0DFB2997BA6C7D2E1E'
+InteroperableAddress addy = InteroperableAddress({
+    targetChainId: hex'000001',
+    targetAddress: hex'D8DA6BF26964AF9D7EED9E03E53415D37AA96045',
+    resolverChainId: hex'000001',
+    resolverAddress: hex'00000000000C2E074EC69A0DFB2997BA6C7D2E1E'
 })
 
Would be seen by users like this:
-    0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@eip:155:1#618AD0D1
+    vitalik.eth@eip:155:1#618AD0D1
 
...and in memory, it would actually be laid out like this:
 C000618AD0D10000000000000000000000000000000000000000000000000001
-0000010000000000000000000000000000000000000000000000000000000006
+000001000000000000000000000000000000000000000000000000000000000C
 D8DA6BF26964AF9D7EED9E03E53415D37AA96045000000000000000000000028
-0000010000000000000000000000000000000000000000000000000000000006
+000001000000000000000000000000000000000000000000000000000000000C
 00000000000C2E074EC69A0DFB2997BA6C7D2E1E000000000000000000000028
 
@@ -71,32 +71,39 @@ But wait! I actually want... What some other resolvers look like: `0x0000`: -``` +
 MSB                                                            LSB
-0x0000618ad0d1000000000001D8DA6BF26964AF9D7EED9E03E53415D37AA96045
-  ^^^^------------------------ 255-240 Interoperable Address version
-      ^^^^^^^^ --------------- 239-208 Checksum
+0x0000618ad0d1000000000001D8DA6BF26964AF9D7EED9E03E53415D37AA96045
+  ^^^^------------------------ 255-240 Interoperable Address version
+      ^^^^^^^^ --------------- 239-208 Checksum
               ^^^^^^^^^^^^
-                \------------- 207-160 Chainid
+                \------------- 207-160 Chainid
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-                            \- 159-0   Address
-```
+                            \- 159-0   Address
+
Is represented as: -`0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@eip155:1#618AD0D1` +
+0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@eip155:1#618AD0D1
+
+ +To fit in a single word, it sacrifices: +* Ability to refer to CAIP-2 namespaces other than eip155 (it's implied by the version number) +* Ability to represent addresses longer than 20 bytes +* Ability to refer to chains with chainids longer than 48 bits (rules out ERC-7785) `0x8000`: ``` MSB LSB -0000618AD0D10000000000000000000000000000000000000000000000000000 +8000618AD0D10000000000000000000000000000000000000000000000000000 ^^^^------------------------ 255-240 Interoperable Address Version ^^^^^^^^ --------------- 239-208 Checksum ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \------------- 207-0 not used, always zero MSB LSB -0100000000000000000000000000000000000000000000000000000000000002 -^^----------------------------------------------------------------- 255-249 bytes array payload - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- 9-249 padding - ^^ -- 0-8 2*1 (payload length) +00000100000000000000000000000000000000000000000000000000000000C0 +^^^^^^------------------------------------------------------------- 255-208 bytes array payload + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- 9-207 padding + ^^ -- 0-8 2*6 (payload length) MSB LSB D8DA6BF26964AF9D7EED9E03E53415D37AA96045000000000000000000000028 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------------- 255-97 bytes array payload From 8d5b7be7ae003b4a22c24d0b98dddda1bd8824f5 Mon Sep 17 00:00:00 2001 From: teddy Date: Fri, 21 Mar 2025 18:34:14 -0300 Subject: [PATCH 12/12] feat: formatting suggestion by shaito --- .../interoperable-address-explainer.md | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/docs/addresses/interoperable-address-explainer.md b/docs/addresses/interoperable-address-explainer.md index 45c14e9..94be5d4 100644 --- a/docs/addresses/interoperable-address-explainer.md +++ b/docs/addresses/interoperable-address-explainer.md @@ -53,10 +53,9 @@ Said word is what enables us to make this standard extensible, let's take a clos
 MSB                                                          LSB
 C0006164DA100000000000000000000000000000000000000000000000000001
-^^^^------------------------ 255-240 Interoperable Address Version
-    ^^^^^^^^ --------------- 239-208 Checksum
-            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-            \--------------- 207-0   Resolver Interface Key
+^^^^-------------------------------------------------------------- 255-240 Interoperable Address Version
+    ^^^^^^^^ ----------------------------------------------------- 239-208 Checksum
+            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 207-0   Resolver Interface Key
 
- Interoperable Address Version: First two bytes of the payload allows us to discern how we should interpret it, more on this later @@ -74,12 +73,10 @@ What some other resolvers look like:
 MSB                                                            LSB
 0x0000618ad0d1000000000001D8DA6BF26964AF9D7EED9E03E53415D37AA96045
-  ^^^^------------------------ 255-240 Interoperable Address version
-      ^^^^^^^^ --------------- 239-208 Checksum
-              ^^^^^^^^^^^^
-                \------------- 207-160 Chainid
-                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-                            \- 159-0   Address
+  ^^^^------------------------------------------------------------- 255-240 Interoperable Address version
+      ^^^^^^^^----------------------------------------------------- 239-208 Checksum
+              ^^^^^^^^^^^^----------------------------------------- 207-160 Chainid
+                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- 159-0   Address
 
Is represented as:
@@ -95,20 +92,19 @@ To fit in a single word, it sacrifices:
 ```
 MSB                                                          LSB
 8000618AD0D10000000000000000000000000000000000000000000000000000
-^^^^------------------------ 255-240 Interoperable Address Version
-    ^^^^^^^^ --------------- 239-208 Checksum
-            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-              \------------- 207-0   not used, always zero
+^^^^-------------------------------------------------------------- 255-240 Interoperable Address Version
+    ^^^^^^^^ ----------------------------------------------------- 239-208 Checksum
+            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 207-0   not used, always zero
 MSB                                                          LSB
 00000100000000000000000000000000000000000000000000000000000000C0
-^^^^^^------------------------------------------------------------- 255-208 bytes array payload
-      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- 9-207   padding
-                                                              ^^ -- 0-8    2*6 (payload length)
+^^^^^^------------------------------------------------------------ 255-208 bytes array payload
+      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- 9-207   padding
+                                                              ^^ - 0-8    2*6 (payload length)
 MSB                                                          LSB
 D8DA6BF26964AF9D7EED9E03E53415D37AA96045000000000000000000000028
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ------------------------- 255-97 bytes array payload
-                                        ^^^^^^^^^^^^^^^^^^^^^^ ---- 9-96   padding
-                                                              ^^ -- 0-8    2*20 (payload length)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ------------------------ 255-97 bytes array payload
+                                        ^^^^^^^^^^^^^^^^^^^^^^ --- 9-96   padding
+                                                              ^^ - 0-8    2*20 (payload length)
 ```
 Is represented as:
 `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@eip155:1#618AD0D1`