diff --git a/docs/addresses/interoperable-address-explainer.md b/docs/addresses/interoperable-address-explainer.md
index a44f196..94be5d4 100644
--- a/docs/addresses/interoperable-address-explainer.md
+++ b/docs/addresses/interoperable-address-explainer.md
@@ -1,54 +1,123 @@
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 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.
-For a normal user, they look like this:
+They contain the following information:
-
-
- 3::vitalik.eth@eth#5966be0f
-
-
+```solidity
+ struct InteroperableAddress {
+ bytes targetChainId;
+ bytes targetAddress;
+ bytes resolverChainId;
+ bytes resolverAddress;
+ }
+```
-- 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:
----
+
+InteroperableAddress addy = InteroperableAddress({
+ targetChainId: hex'000001',
+ targetAddress: hex'D8DA6BF26964AF9D7EED9E03E53415D37AA96045',
+ resolverChainId: hex'000001',
+ resolverAddress: 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
-
-
+
+ vitalik.eth@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
+000001000000000000000000000000000000000000000000000000000000000C
+D8DA6BF26964AF9D7EED9E03E53415D37AA96045000000000000000000000028
+000001000000000000000000000000000000000000000000000000000000000C
+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
+
+
+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
+8000618AD0D10000000000000000000000000000000000000000000000000000
+^^^^-------------------------------------------------------------- 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)
+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).
diff --git a/specs/addresses/cross-chain-interoperable-addresses-spec.md b/specs/addresses/cross-chain-interoperable-addresses-spec.md
index 3828beb..21024b3 100644
--- a/specs/addresses/cross-chain-interoperable-addresses-spec.md
+++ b/specs/addresses/cross-chain-interoperable-addresses-spec.md
@@ -1,197 +1,421 @@
# 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.
+# 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
-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)
+# 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 registries document](../docs/chain-registries.md)
-## Definitions
-Account id
-: A string which unambiguously corresponds to an address on a specific chain (EVM or not).
+# Definitions
+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 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.
+Target address
+: The (address, chainid) pair a particular Interoperable Address points to.
-## Machine address format definition
+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.
-### Syntax
+# 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.
+# Binary Format definition
+Word 0 Is the only word which will be common to all versions, and is defined as follows:
+```
+MSB LSB
+0x0000000000000000000000000000000000000000000000000000000000000000
+ ^^^^------------------------ 255-240 Interoperable Address version
+ ^^^^^^^^ --------------- 239-208 Checksum
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ \------------- 207-0 Reserved
+```
+
+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 (ABI representation would not be significantly cheaper though).
+
+# Human-readable name format definition
+
+## Syntax
```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.
-
-## Human-readable name format definition
-
-### Syntax
-```bnf
- ::= =
- ::= [0-9]{1,4}
- ::= [@-.%a-zA-Z0-9]*
+ ::= @#
+ ::= [-:_%a-zA-Z0-9]*
+ ::= [-:_a-zA-Z0-9]*
+ ::= [0-9A-F]{8}
```
## 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.
+- 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.
-## Resolver version definitions
+# 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.
+## `0x8000`: Standard Long Format: arbitrary length addresses, CAIP-10 display format
-#### Examples:
-Machine address
-: `0:::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#6164da10`
+### Machine-address format
-Human-readable name
-: `0:::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#6164da10`
+#### First word
+Does not make use of reserved bits
+```
+MSB LSB
+0x8000XXXXXXXX0000000000000000000000000000000000000000000000000000
+ ^^^^------------------------ 255-240 Interoperable Address version
+ ^^^^^^^^ --------------- 239-208 Checksum
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ \--------------- 207-0 Reserved
+```
-### `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.
+#### Second field
+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
-#### Examples:
-Machine address
-: `1:::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#b50c58f9`
+#### Third field
+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
-: `1::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045`
+### Human-readable name resolution
+The CAIP-2 namespace is to be rendered alongside the CAIP-10 formatted address and the checksum:
-### `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
+```
+@#
+```
-#### Human-readable name format
+### Examples
-```bnf
- ::= 2:::
+Human-readable name:
+`0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#6164DA10@eip155:1#618ad0d1`:
+
+First word:
+```
+MSB LSB
+0x80006164DA100000000000000000000000000000000000000000000000000000
+ ^^^^------------------------ 255-240 Interoperable Address version
+ ^^^^^^^^ --------------- 239-208 Checksum
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ \--------------- 207-0 Not used
```
-Since wallet software can always validate the checksum, it MUST be removed.
-EIP-55 or applicable scheme is used for canonicalization only.
+Second word (second field):
+```
+MSB LSB
+0x0100000000000000000000000000000000000000000000000000000000000002
+ ^^----------------------------------------------------------------- 255-249 bytes array payload
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- 9-249 padding
+ ^^ -- 0-8 2*1 (payload length)
+```
-#### Examples:
+Third word (third field):
+```
+MSB LSB
+0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045000000000000000000000028
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------------- 255-97 bytes array payload
+ ^^^^^^^^^^^^^^^^^^^^^^ ---- 9-96 padding
+ ^^ -- 0-8 2*20 (payload length)
+```
-Machine address
-: `2:::eip155:1:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#bc797def`
+TODO: example with multi-word fields
-Human-readable name
-: `2::eth:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045`
+## `0xC000`: Standard Long Format With Resolver Info: arbitrary length addresses, arbitrary length name-resolving contract specification
-### `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.
+### Machine-address format
-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.
+#### 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 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.
-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.
+#### Second field
+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).
-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.
+#### Third field
+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).
-#### Human-readable name format
+#### 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).
-```bnf
- ::= 3::@#
- ::= |
+#### 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, and used to display the address. 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
```
-#### Machine-address format
+Second word (second field): target address' chainid
+```
+MSB LSB
+0x0100000000000000000000000000000000000000000000000000000000000002
+ ^^----------------------------------------------------------------- 255-249 bytes array payload
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- 9-249 padding
+ ^^ -- 0-8 2*1 (payload length)
+```
-```bnf
- ::= 3:::#
-```
-
-#### `machine address -> human-readable name` resolution
-1. Extract CAIP-2 `chainId` and raw address from ``.
- - 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 ``.
-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 `` with the resolver used in the step above.
-8. Construct `` 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
-
-#### 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.
-
-#### Examples:
+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
+- 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
-: `3:eip155:1:0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e::eip155:10xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#5966be0f`
+:
+```
+MSB LSB
+0x0000618ad0d1000000000001D8DA6BF26964AF9D7EED9E03E53415D37AA96045
+ ^^^^------------------------ 255-240 Interoperable Address version
+ ^^^^^^^^ --------------- 239-208 Checksum
+ ^^^^^^^^^^^^
+ \------------- 207-160 Chainid
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ \- 159-0 Address
+```
Human-readable name
-: `3::vitalik.eth@eth`
+: `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045#6164da10@eip155:1#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
+## `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
-## 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
- - 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.
+### Supported chains
+Chain must be listed on ethereum-lists/chains on top of the restrictions of `0x0000`.
-## Recommendations for rollups
-TODO: probably coupled to ERC-7785, currently out of scope
+### Machine-address format
+Same as `0x0000`, with `0x0001` version
-## 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
+### 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
-## 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.
+
+## 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)
-### W3C DID
+### 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
TODO
-## Security considerations
+# 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 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
+
+`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`. (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 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:
+
+```solidity
+ function getChecksum(bytes2 caip2Namespace, bytes memory chainid, bytes memory address_)
+ internal
+ view
+ 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);
+ }
+```
+TODO: describe this in a way which is not potentially coupled to solidity (or even a specific version of it)