From daba5fb277d9b6f4742e7de20a0951ebf823cbd3 Mon Sep 17 00:00:00 2001 From: Paperclip Minimizer Date: Fri, 22 May 2026 14:40:13 -0300 Subject: [PATCH 1/3] azip-15: aztec namespace --- AZIPs/azip-15.md | 411 +++++++++++++++++++++++++++++++++++++ assets/azip-15/caip-10.md | 108 ++++++++++ assets/azip-15/caip-2.md | 104 ++++++++++ assets/azip-15/caip-350.md | 101 +++++++++ assets/azip-15/checksum.py | 43 ++++ 5 files changed, 767 insertions(+) create mode 100644 AZIPs/azip-15.md create mode 100644 assets/azip-15/caip-10.md create mode 100644 assets/azip-15/caip-2.md create mode 100644 assets/azip-15/caip-350.md create mode 100644 assets/azip-15/checksum.py diff --git a/AZIPs/azip-15.md b/AZIPs/azip-15.md new file mode 100644 index 0000000..8f2da43 --- /dev/null +++ b/AZIPs/azip-15.md @@ -0,0 +1,411 @@ +# Aztec Improvement Proposal: Aztec Namespace + +## Preamble + +| `azip` | `title` | `description` | `author` | `discussions-to` | `status` | `category` | `created` | +| --- | --- | --- | --- | --- | --- | --- | --- | +| 15 | Aztec Namespace | Define a Chain Agnostic Namespace for Aztec | Paperclip Minimizer (@paperclip-minim) | TBD | Draft | Standard | 2026-05-22 | + +## Abstract + +We define a Chain Agnostic namespace and profiles for CAIP-2, CAIP-10, and CAIP-350. This results in an unambiguous definition of Aztec chain ID for every Aztec deployed version across all EVM blockchains, and an interoperable address that includes Aztec addresses along with a specific rollup version. + +## Impacted Stakeholders + +Every stakeholder that receives user input (bridges, wallets, dApps) as well as on-chain applications dealing with cross chain messages, may unequivocally identify Aztec address-blockchain pairs, including senders, recipients, and tokens. They'll also have routing information (settlement chain and rollup contract address) available. + +## Motivation + +Cross-chain messaging *requires* a definition of chain ID for every involved chain. E.g., an intents-based bridge requires representing the chain for the input assets, as well as each output's recipient, which may be any address at any supported chain. + +Separately, Aztec's address derivation is deterministic in the contract's constructor arguments, its function bytecode and verification keys, and the account's public keys. This scheme is not guaranteed to hold constant across different Aztec versions, which means the same address that a user controls in one rollup version may not be controllable by the user in a different version. Inadvertently sending funds to an address for a newer rollup version may result in loss of funds. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174 + +The chain-agnostic namespace `aztec` SHALL be reserved for the Aztec ecosystem. And the following ChainAgnostic profiles SHALL be pushed into Chain Agnostic's namespaces repo. + +- [CAIP-2](../assets/azip-x/caip-2.md): defines a blockchain ID +- [CAIP-10](../assets/azip-x/caip-10.md): defines a text representation for account addresses +- [CAIP-350](../assets/azip-x/caip-350.md): specifies text and binary representations of the chain ID and account address, plus a 2-byte chain type identifier. + +A brief description of those is included in the subsections below. + +### CAIP-2 + +This profile specifies a unique chain ID for every chain, restricted to match the regex `[-_a-zA-Z0-9]{1,32}`. Since Aztec rollup contracts compile to EVM bytecode, every live Aztec rollup chain has an associated EVM chain ID and rollup contract address. + +An Aztec chain's ID is defined as a hash of the settlement chain's ID and the rollup contract address. Optionally, a chain may also have a Governance-attributed human-readable name. + +Both of these leverage a Governance-owned registry, as described in the [chain registry](#chain-registry) section. An Aztec's CAIP-2 chain ID can be queried by calling the registry's `getTextChainId` method. + +Clients SHOULD resolve a chain's CAIP-2 chain ID by querying a node of that chain via a dedicated JSON-RPC method (e.g., `aztec_getChainId`). Nodes derive the chain ID by reading the alias from the on-chain registry if one is set, or otherwise computing the hash form locally from the known `evmChainId` and `rollupContractAddress`. + +#### Human-readable form + +For every existing chain, governance MAY choose to bind a human-readable name once and irreversibly, by calling the registry's `setAlias` method. Said form will be restricted to strings matching the regex `[_a-z]{1,31}`. + +#### Hash of the chain's details + +When a human-readable name has not been set, the chain ID is the base58btc encoding of `keccak256(abi.encodePacked(evmChainId, rollupContractAddress))[:23]`, left-padded with `'1'` characters (base58btc's zero) to exactly 32 characters. Where, going forwards in the document: +- `evmChainId` is a `uint256` holding the settlement chain's EVM chain ID. +- `rollupContractAddress` is the `address` of the rollup contract on the settlement chain. + +### CAIP-10 + +This profile specifies a text representation for Aztec addresses, restricted to match the regex `[-.%a-zA-Z0-9]{1,128}`. We'll define it as the 0-padded 64-character hexadecimal representation of the `AztecAddress`, with the mixed-case Aztec-chain-dependent checksum inspired by EIP-55 as described: + +Define +- `binary_chain_hash = keccak256(abi.encodePacked(evmChainId, rollupContractAddress))` +- `aztec_address` the lower-case 0-padded 64-character hexadecimal representation of the `AztecAddress`. + +Then, the checksummed CAIP-10 Aztec address is constructed by, for each `i` in `0..64`, upper-casing the `i`-th character of `aztec_address` if and only if the `i`-th bit of `binary_chain_hash` is `1`. Numeric characters are left unchanged. + +Consumers of this standard MUST validate the checksum. + +### CAIP-350 + +This profile specifies three representations for both the chain ID and the address: +- Customary representation: whatever the ecosystem uses. +- Text representation: this is like CAIP-2, but without a character limit. +- Binary representation: matching EIP-7930's binary format + +As well as a 2-byte binary key representing the chain type. + +The `aztec.on.eth` subdomain SHALL be registered, and when `on.eth` allows custom ownership of its subdomain, it SHALL be owned by the Governance contract. + +When an interoperable name omits the chain (e.g., `
@aztec`), the Aztec chain pointed to by `aztec.on.eth` is used to compute and validate the address's checksum. + +#### Chain type + +The chain type is a 2-byte value, uniquely associated to the namespace. + +This AZIP proposes `0xa27c`, which reads almost like "Aztec". + +#### Customary and text representation + +Both matching CAIP-2 and CAIP-10 + +#### Binary representation + +For the chain ID, this is `abi.encodePacked(evmChainId, rollupContractAddress)`. + +For the address, this is just the Ethereum `uint256` for the field number in the `AztecAddress`. + +### Chain registry + +A chain registry MUST be deployed, MUST inherit from OpenZeppelin's `Ownable`, and MUST be owned by the Governance contract. + +It MUST implement the following methods: + +```solidity +function getTextChainId(uint256 evmChainId, address rollupContractAddress) external view returns (string memory); +``` + +Returns the text representation of the chain ID for the Aztec chain represented by the arguments. It MUST return the human-readable form if available, and the hash form otherwise. Clients that need the binary form decode the result as base58btc (stripping leading `'1'` padding) when the length is 32, or look it up via `getChainDetails` otherwise. + +```solidity +function setAlias(uint256 evmChainId, address rollupContractAddress, string calldata alias) external onlyOwner; +``` + +Sets `alias` as the human-readable chain ID for the Aztec chain represented by the arguments. +MUST assert that: +- `alias` matches the regex `[_a-z]{1,31}` *or* is equal to the text chain ID deterministically derived from the chain's information, in which case it becomes non-aliasable. +- `alias` hasn't been assigned to another Aztec chain before. +- `setAlias` hasn't been successfully called for this Aztec chain before. +- At least one of the following holds: + - `evmChainId` is not `1` + - a static call to `rollupContractAddress`'s `owner()` method returns the registry owner's address + - `ensureAlias` has been successfully called before with `alias` matching the value passed here +MUST store the chain details for the deterministic chain ID as well. +MUST emit an `AliasSet` event. + +```solidity +function ensureAlias(address rollupContractAddress, string calldata alias) external; +``` + +Pins `alias` as the only human-readable form that governance is allowed to bind to the Aztec chain settling at address `rollupContractAddress` on Ethereum mainnet. +MUST assert that: +- `alias` matches the regex `[_a-z]{1,31}` *or* is equal to the text chain ID deterministically derived from the chain's information, in which case it becomes non-aliasable. +- `msg.sender` matches the one returned by a static call to `rollupContractAddress`'s `owner` method. +MUST NOT check that `alias` hasn't been assigned to another chain, and MUST allow later calls to overwrite the previous ensured alias. +MUST emit an `AliasBound` event. + +```solidity +function getChainDetails(string calldata textChainId) external view returns (uint256, address); +``` + +When it has been stored either via `setAlias` or `storeChainDetails`, returns the corresponding EVM chain ID and rollup contract address for the Aztec chain with text chain ID `textChainId`. + +```solidity +function storeChainDetails(uint256 evmChainId, address rollupContractAddress) external; +``` + +Store the EVM chain ID and rollup contract address (the *details*) for the chain ID corresponding to said chain. +MUST be permissionless. +MUST ensure the chain details haven't been stored before. +MUST emit a `ChainDetailsStored` event. + +```solidity +function getBinaryChainId(uint256 evmChainId, address rollupContractAddress) external pure returns (bytes memory); +``` + +Returns the binary representation of the chain ID, `abi.encodePacked(evmChainId, rollupContractAddress)`. Although callers can compute this locally, the registry exposes it as a normative reference so that consumers do not produce divergent encodings. + +It MUST define the following events: + +```solidity +event AliasSet(uint256 indexed evmChainId, address indexed rollupContractAddress, string alias); +``` + +Emitted by `setAlias` when governance binds a human-readable `alias` to the Aztec chain identified by `evmChainId` and `rollupContractAddress`. + +```solidity +event AliasBound(address indexed rollupContractAddress, string alias); +``` + +Emitted by `ensureAlias` when the chain owner pins `alias` as the only human-readable form acceptable for the Aztec chain settling at `rollupContractAddress` on Ethereum mainnet. + +```solidity +event ChainDetailsStored(uint256 indexed evmChainId, address indexed rollupContractAddress); +``` + +Emitted by `storeChainDetails` when the EVM chain ID and rollup contract address backing a chain ID are recorded in the registry, enabling text-to-binary lookups. + +#### Constructor + +The registry's constructor allows seeding aliases for mainnet-settling Aztec chains without the ownership restrictions enforced by `setAlias`. This MAY be used by governance to give human-readable names to mainnet-settling Aztec chains whose ownership has already been renounced on mainnet at deployment time. + +```solidity +constructor(address[] memory rollupContractAddresses, string[] memory aliases); +``` + +Each entry refers to the Aztec chain settling at `rollupContractAddresses[i]` on Ethereum mainnet (i.e., `evmChainId == 1`). + +MUST assert that: +- Both arrays have the same length. +- For each `i`, `aliases[i]` matches the regex `[_a-z]{1,31}` *or* is equal to the text chain ID deterministically derived from `(1, rollupContractAddresses[i])`, in which case that chain becomes non-aliasable. +- No `aliases[i]` is reused for another chain in the constructor call. + +MUST emit an `AliasSet` event for each `i`. + +After construction, all alias-setting MUST go through `setAlias` and `ensureAlias` with their full constraints. + +### Examples + +Consider the following two chains: +- Alpha, settling to contract at address `0xAe2001f7e21d5EcABf6234E9FDd1E76F50F74962` on Ethereum mainnet. +- Testnet, currently settling to contract at address `0xf6D0D42aCE06829bECB78C74F49879528fC632c1` on Sepolia. + +Assuming +- Alpha is aliased to `alpha_flying_bison`, and pointed to by `aztec.on.eth`. +- Testnet is aliased to `testnet_gravastar`. + +Consider an arbitrary Aztec address, `0x9203544e42ba86847CA8458432F7C0265CE567e74064cB25B2a9723C390463C2`. + +#### Chain IDs + +- Alpha: `alpha_flying_bison`, `2LKN5QVpKjqRxc2KsPM4nMojhvryewCs`. +- Testnet: `testnet_gravastar`, `1DQUdRx75WPNrWmkcyVEyeuu9FQ6tT7x` + +#### CAIP-10-style chain-specific addresses + +- Alpha + - `aztec:alpha_flying_bison:9203544e42ba86847CA8458432F7C0265CE567e74064cB25B2a9723C390463C2` + - `aztec:2LKN5QVpKjqRxc2KsPM4nMojhvryewCs:9203544e42ba86847CA8458432F7C0265CE567e74064cB25B2a9723C390463C2` +- Testnet + - `aztec:testnet_gravastar:9203544e42bA86847Ca8458432F7c0265cE567E74064cb25B2a9723C390463c2` + - `aztec:1DQUdRx75WPNrWmkcyVEyeuu9FQ6tT7x:9203544e42bA86847Ca8458432F7c0265cE567E74064cb25B2a9723C390463c2` + +Notice the differing mixed-case checksum: +``` + _ _ _ _ _ _ _ +alpha: 9203544e42ba86847CA8458432F7C0265CE567e74064cB25B2a9723C390463C2 +testnet: 9203544e42bA86847Ca8458432F7c0265cE567E74064cb25B2a9723C390463c2 +``` + +#### Interop-style chain-specific addresses + +- Alpha + - `9203544e42ba86847CA8458432F7C0265CE567e74064cB25B2a9723C390463C2@aztec` + - `9203544e42ba86847CA8458432F7C0265CE567e74064cB25B2a9723C390463C2@aztec:alpha_flying_bison` + - `9203544e42ba86847CA8458432F7C0265CE567e74064cB25B2a9723C390463C2@aztec:2LKN5QVpKjqRxc2KsPM4nMojhvryewCs` +- Testnet + - `9203544e42bA86847Ca8458432F7c0265cE567E74064cb25B2a9723C390463c2@aztec:testnet_gravastar` + - `9203544e42bA86847Ca8458432F7c0265cE567E74064cb25B2a9723C390463c2@aztec:1DQUdRx75WPNrWmkcyVEyeuu9FQ6tT7x` + +## Rationale + +### Using the Chain Agnostic namespace + +Chain Agnostic is the dominant standard for cross-chain identifiers and addresses it directly. + +CAIP-2 and CAIP-10 are ubiquitous. Out of the 42 namespaces registered as of 2026-05-22, CAIP-2 is present in 41 of them, and CAIP-10 in 26. + +CAIP-350 (the foundation for interop) introduces the definition of the *binary* representation, which allows for an on-chain representation. Coupled with an `aztec.on.eth` subdomain registration, this unlocks interop names that look like `
@aztec`. + +### Chain definition + +By binding an Aztec chain ID to pairs of EVM chain ID and contract address, it's implicitly assumed that there's no more information pertaining a chain's definition. E.g., if the rollup contract address is a proxy that gets updated, the chain ID will still be the same. + +A further versioning integer could be used, so that changes within the same rollup contract would make the previous chain ID invalid (forever). + +Aztec chain changes can be categorized based on whether they affect the meaning of an Aztec address. This could happen, e.g., if the address derivation scheme is changed (as in [AZIP-9](./azip-9.md)), or if either the AVM or the proving system is changed. + +Changes that don't change the meaning of Aztec addresses don't affect the validity of recipients by definition. In such a case, a chain ID change would impose an unnecessary migration cost. + +In contrast, if a chain update changed the meaning of Aztec addresses, an ensuing change of chain ID would prevent protocols from sending funds to addresses that are now bricked. In the bigger picture, opening up to such possibility would require making portals version-dependent as well, as hardcoded values for e.g. a wrapped token's L1 contract would render them unusable after such a change. + +We decided to keep the chain ID constant under such changes on the grounds that when such changes happen, the chain is switched in place much in the same way a non-splitting hard fork does it. + +### Chain ID's binary representation + +The existing CAIP-350 profiles' binary and text chain IDs are each just a representation of the other, and hence the conversion can be done offline. We could've defined the binary representation of the chain ID as the binary encoding of the text representation as well. + +The chosen representation incurs the cost of an Ethereum mainnet call in order to look for the binary form from the text form, but in exchange encodes useful information in the binary representation. E.g., a token bridge going from mainnet to any other mainnet-based Aztec chain can extract the chain ID to assert it's the proper one, and the rollup contract address in order to send the messages, *without the need to look this info up* in the registry at any point. The registry's lookup is only for off-chain services that receive user input. + +### Chain ID's text representation + +CAIP-2's chain ID is restricted to 32 characters from a character set of 64 characters, which is a total of 192 bits at 6 bits per character. CAIP-350's chain ID's text representation releases this constraint, from `[-_a-zA-Z0-9]{1,32}` to `[.-:_a-zA-Z0-9]*` (see EIP-7828 on interoperable names). + +The latter constraint, along with introducing a reasonable limit to chain IDs (2 ** 64), and disregarding human-readable names, would allow for a reasonably-small (~38 characters) bijective representation between text and binary, where both had the complete rollup information. + +We decided to constrain the CAIP-350 to be the same as the CAIP-2 representation, in order not to introduce two differing standards for the same task (representing the chain). This would break the bijectiveness between CAIP-350 and CAIP-2 representations. + +Within the alphabet permitted by CAIP-2, the hash form is encoded as base58btc. Its alphabet avoids `-`, which breaks double-click word selection in most UIs and terminals. + +Within that constraint, four approaches were considered. + +#### Hash only (rejected) + +A chain's ID is the base58btc encoding of the 23-byte hash (left-padded to 32 chars), with no governance-assigned alternative. Binary-to-text conversion is offline; the on-chain registry's sole purpose is providing the inverse (text-to-binary) lookup for off-chain services' convenience. + +Rejected because it leaves no room for short, memorable identifiers for popular chains. + +#### Governance-assigned name replaces the hash (rejected) + +When governance assigns a human-readable name, that name *becomes* the chain ID and the hash form is no longer valid for the chain. + +Rejected because it makes the registry a *requirement* for binary-to-text lookup of any chain that ever gets a name, and forces consumers to deal with a single chain having two different canonical IDs across its lifetime. + +#### Hash as canonical, with optional human-readable alias (chosen) + +The hash is always a valid chain ID, so binary-to-text conversion is offline by default. Governance MAY additionally assign a human-readable alias, queryable via `getTextChainId` and accepted as an alternative text form for the same chain. + +This preserves offline binary-to-text conversion for the default case while still letting popular Aztec chains advertise short, memorable IDs (e.g., `alpha_flying_bison`, with prefixes available to denote development status). The registry lookup cost for resolving an alias is deemed acceptable, since cross-chain interactions already require a functioning network. + +The human-readable alias is purposefully limited to one character short of the deterministic derivation in order to prevent governance attacks, as described in the [security considerations](#security-considerations) section. + +#### Storing compressed chain ID lookup information (rejected) + +The rationales in favour of human-readable names are strong enough to justify discarding this as well, but the following reasons also apply. + +We considered using the concatenation of a representation of the settlement chain ID and the contract address. + +The full contract address requires 27 base 64 characters, leaving 5 characters for the chain ID, bounding the chain ID to be smaller than `2 ** 30`. While this is a high bound (100x Sepolia's chain ID), it's lower than the currently proposed bound. + +Truncating the contract address (by the one character required to reach the bound) in order to expand the chain ID was deemed too cumbersome for data lookup. + +Alternatively, we considered compressing the block-number and the truncated TX hash of the deploying TX. This way, lookup could happen by checking known EVM chains at the given block number and looking for the TX whose first bits matched the truncated TX hash. However, this already involves more than one node query, in contrast with the one required via the use of a registry. + +#### Address representations + +Including a checksum dependent on chain ID makes direct substitution of the chain ID invalid. + +We considered using a base 64 representation for addresses, with a replacement for `_` (not available for CAIP-10 addresses), or a base58btc representation. This would require approximately 43 characters in contrast to the 64 required for hexadecimal representation. A few more characters could be used to include a checksum that prevented direct replacement of the chain ID in the full specification of chain and address. + +We went in favour of the hexadecimal representation with the mixed-case checksum because we believe many UIs (potentially including hardware wallets) will expect hexadecimal for the address, and this would introduce again two standards for the same task. The mixed-case checksum should already prevent just trimming the address, and having the same representation allows people to do quick visual inspection to ensure two addresses are the same. + +### Chain registry + +We chose to specify a standalone contract to act as a registry instead of bundling into the rollup registry. This avoids a protocol-contract upgrade. Considering that the functionality for the chain registry is only that of documenting, it's simple enough not to merit further upgrades. + +The registry is intentionally immutable: off-chain consumers can hardcode its address with confidence that the contract and its semantics will not change. + +In order to prevent Governance from assigning names to chains not related to governance, the `ensureAlias` function has been proposed so that the chain owner can request the chain not to be aliased *or* a specific alias for the chain. + +Two ways to gate this function have been explored. +1. Allow `ensureAlias` to work over any settlement chain ID. Introduce a `startEnsureAlias` function, which should be called a certain amount of time (e.g. 1 month) before enabling `ensureAlias` to succeed. During said time, Governance could veto the intention forever. +2. Only allow `ensureAlias` on mainnet, and check the owner of the contract at `rollupContractAddress`. + +Alternative 1 was discarded because it would introduce unnecessary load on the governance process. While alternative 2 only protects networks settling on mainnet, it was preferred due to its simplicity. + +## Backwards Compatibility + +No backwards incompatibilities are introduced by this AZIP. + +## Test Cases + +The two reference chains used throughout the [Examples](#examples) section define the inputs: + +- **Alpha**: `evmChainId = 1`, `rollupContractAddress = 0xAe2001f7e21d5EcABf6234E9FDd1E76F50F74962` +- **Testnet**: `evmChainId = 11155111`, `rollupContractAddress = 0xf6D0D42aCE06829bECB78C74F49879528fC632c1` + +Reference Aztec address: `0x9203544e42ba86847ca8458432f7c0265ce567e74064cb25b2a9723c390463c2`. + +### Deterministic chain ID + +`base58btc(keccak256(abi.encodePacked(evmChainId, rollupContractAddress))[:23])`, left-padded with `'1'` to 32 characters: + +| chain | text chain ID | +| --- | --- | +| Alpha | `2LKN5QVpKjqRxc2KsPM4nMojhvryewCs` | +| Testnet | `1DQUdRx75WPNrWmkcyVEyeuu9FQ6tT7x` | + +### CAIP-350 binary chain ID + +`abi.encodePacked(evmChainId, rollupContractAddress)` (52 bytes): + +| chain | binary (hex) | +| --- | --- | +| Alpha | `0x0000000000000000000000000000000000000000000000000000000000000001ae2001f7e21d5ecabf6234e9fdd1e76f50f74962` | +| Testnet | `0x0000000000000000000000000000000000000000000000000000000000aa36a7f6d0d42ace06829becb78c74f49879528fc632c1` | + +### CAIP-10 mixed-case checksum + +Computed against `binary_chain_hash = keccak256(abi.encodePacked(evmChainId, rollupContractAddress))`: + +| chain | checksummed address | +| --- | --- | +| Alpha | `9203544e42ba86847CA8458432F7C0265CE567e74064cB25B2a9723C390463C2` | +| Testnet | `9203544e42bA86847Ca8458432F7c0265cE567E74064cb25B2a9723C390463c2` | + +A reference implementation generating these vectors is in [`../assets/azip-x/checksum.py`](../assets/azip-x/checksum.py). + +## Security Considerations + +### Hash security + +Attackers can mine chain IDs by trying out different salts for the `CREATE2` opcode, until one of these lands a malicious contract at an address that results in the same chain ID as another one. Since lookup relies necessarily on the chain registry by definition, the attacker only has time between chain ID publication and the first call to `storeChainDetails` (which may even be done *before* chain ID publication). As long as anyone performs the call in a timely manner, the scheme is secure regardless of the hash length: a successful attack requires winning a race against any honest caller, not breaking the hash. + +In particular, the 32-character base58btc-encoded hash used here carries 184 bits of entropy. + +### Governance chain renaming + +The `ensureAlias` function forbids Governance from attributing ill-purposed alias to any Aztec chain on Ethereum mainnet. Aztec chains settling on other EVM chains are not protected this way, but may be protected via a governance proposal itself. The worst case scenario is an ill-purposed alias being assigned to an Aztec chain. + +The `setAlias` constrains the provided text chain ID to either be trivially differentiable from the deterministic hash, or be exactly that of the hash, in order to prevent governance from aliasing a chain ID to another deterministically derived chain ID. + +### Changing the default Aztec chain + +Changing the `aztec.on.eth` subdomain silently either breaks all previously shared interop names or makes some previously shared interop names point at unusable Aztec addresses. Governance should wait for maturity before setting this value to a chain. + +### Unchecked code in the registry + +No check is proposed for the code residing in the provided `rollupContractAddress` when calling any of the modifying methods of the chain registry. + +Externally calling a method on an arbitrary address, counting on a specific behaviour, opens room for: +- Reentrancy +- Grievance +- Unexpected reverts +- Silent failures +- Loss of funds + +It's up to the relying party to check that the address referred to by the chain ID corresponds to a valid rollup contract. + +Similarly, `storeChainDetails` does not verify that any contract is deployed at `rollupContractAddress`. Registered entries are claims about a deterministic chain ID derivation, not guarantees that the chain exists; consumers MUST resolve the actual rollup contract via standard means before relying on it. + +## Copyright Waiver + +Copyright and related rights waived via [CC0](/LICENSE). diff --git a/assets/azip-15/caip-10.md b/assets/azip-15/caip-10.md new file mode 100644 index 0000000..86465da --- /dev/null +++ b/assets/azip-15/caip-10.md @@ -0,0 +1,108 @@ +--- +namespace-identifier: <{name of folder}-caip10> +title: <{namespace common name} [, aka ecosystem name] - Account ID Specification> +author: <["FirstName1 LastName1 (@GitHubUsername1)", "AnonHandle2 "]> +discussions-to: +status: Draft +type: Informational +created: +requires (*optional): CAIP-2, CAIP-10 +--- + + + +# CAIP-10 + +*For context, see the [CAIP-10][] specification.* + +## Introduction + + + +## Specification + +### Semantics + + + +### Syntax + + + +### Resolution Mechanics + + + +## Rationale + + + +### Backwards Compatibility + + + +## Test Cases + + + +## Additional Considerations (*OPTIONAL) + + + +## References + + + +[CAIP-2 Profile]: ./caip2.md +[CAIP-2]: https://chainagnostic.org/CAIPs/caip-2 +[CAIP-10]: https://chainagnostic.org/CAIPs/caip-10 + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/assets/azip-15/caip-2.md b/assets/azip-15/caip-2.md new file mode 100644 index 0000000..99fe70e --- /dev/null +++ b/assets/azip-15/caip-2.md @@ -0,0 +1,104 @@ +--- +namespace-identifier: <{name of folder}-caip2> +title: <{namespace common name} [, aka ecosystem name] - Blockchain ID Specification> +author: <["FirstName1 LastName1 (@GitHubUsername1)", "AnonHandle2 "]> +discussions-to: +status: Draft +type: Informational +created: +requires (*optional): CAIP-2 +--- + + + +# CAIP-2 + +*For context, see the [CAIP-2][] specification.* + +## Introduction + + + +## Specification + +### Semantics + + + +### Syntax + + + +### Resolution Mechanics + + + +## Rationale + + + +### Backwards Compatibility + + + +## Test Cases + + + +## Additional Considerations (*OPTIONAL) + + + +## References + + + +[CAIP-2]: https://chainagnostic.org/CAIPs/caip-2 + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/assets/azip-15/caip-350.md b/assets/azip-15/caip-350.md new file mode 100644 index 0000000..52094b2 --- /dev/null +++ b/assets/azip-15/caip-350.md @@ -0,0 +1,101 @@ +--- +namespace-identifier: +binary-key: +title: <{namespace common name} [, aka ecosystem name]> +discussions-to: +author: <["FirstName1 LastName1 (@GitHubUsername1)", "AnonHandle2 "]> +status: Draft +type: Informational +created: +requires: +--- + +## Namespace Reference +ChainType binary key: `0xa27c` +[CAIP-104] namespace: `aztec` + +## Chain reference + +Aztec chains are L2s that settle to EVM. As such, every one can be identified via the EVM chain they settle to + + +### Text representation + + + + + +#### Text -> customary (CAIP-2) conversion + + + +#### Customary (CAIP-2) -> text conversion + + + +### Binary representation + + + +#### Text -> binary conversion + + + +#### Binary -> text conversion + + + +### Examples + +## Addresses + +### Text representation + + + +#### Text -> native conversion + + + + + +#### Native -> text conversion + + + + +### Binary representation + + + +#### Text -> binary conversion + + + +#### Binary -> text conversion + + + +### Examples + +## Error handling + + + + + +## Implementation considerations + + + + + +## Extra considerations + + + diff --git a/assets/azip-15/checksum.py b/assets/azip-15/checksum.py new file mode 100644 index 0000000..6abf04c --- /dev/null +++ b/assets/azip-15/checksum.py @@ -0,0 +1,43 @@ +import base58 + +from eth_hash.auto import keccak + + +def binary_chain_id(evm_chain_id: int, rollup_contract_address: bytes) -> bytes: + # abi.encodePacked(uint256, address) = 32-byte big-endian uint || 20-byte address. + return evm_chain_id.to_bytes(32, "big") + rollup_contract_address + + +def deterministic_chain_id(evm_chain_id: int, rollup_contract_address: bytes) -> str: + # 23 bytes (184 bits) so the base58btc encoding fits within CAIP-2's 32-char limit. + truncated_hash = keccak(binary_chain_id(evm_chain_id, rollup_contract_address))[:23] + encoded = base58.b58encode(truncated_hash).decode("ascii") + # Left-pad with '1' (base58btc's zero) to guarantee a fixed 32-char length. + return encoded.rjust(32, "1") + + +def checksum_encode(aztec_address: bytes, evm_chain_id: int, rollup_contract_address: bytes) -> str: + hex_addr = aztec_address.hex() # 64 lower-case hex chars + chain_hash = keccak(binary_chain_id(evm_chain_id, rollup_contract_address))[:8] # first 64 bits + + out = [] + for i, ch in enumerate(hex_addr): + bit = (chain_hash[i >> 3] >> (7 - (i & 7))) & 1 + if ch in "abcdef" and bit == 1: + out.append(ch.upper()) + else: + out.append(ch) + return "".join(out) + + +if __name__ == "__main__": + aztec_address = bytes.fromhex( + "9203544e42ba86847ca8458432f7c0265ce567e74064cb25b2a9723c390463c2" + ) + alpha = (1, bytes.fromhex("Ae2001f7e21d5EcABf6234E9FDd1E76F50F74962")) + testnet = (11155111, bytes.fromhex("f6D0D42aCE06829bECB78C74F49879528fC632c1")) + + for name, (cid, addr) in [("alpha", alpha), ("testnet", testnet)]: + print(f"{name}:") + print(f" chain id : {deterministic_chain_id(cid, addr)}") + print(f" address : {checksum_encode(aztec_address, cid, addr)}") From a17c072300349b9c1ce5e57398aa30c19bc5b323 Mon Sep 17 00:00:00 2001 From: Paperclip Minimizer Date: Fri, 22 May 2026 14:44:13 -0300 Subject: [PATCH 2/3] fix: TBD to just - --- AZIPs/azip-15.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AZIPs/azip-15.md b/AZIPs/azip-15.md index 8f2da43..2d21996 100644 --- a/AZIPs/azip-15.md +++ b/AZIPs/azip-15.md @@ -4,7 +4,7 @@ | `azip` | `title` | `description` | `author` | `discussions-to` | `status` | `category` | `created` | | --- | --- | --- | --- | --- | --- | --- | --- | -| 15 | Aztec Namespace | Define a Chain Agnostic Namespace for Aztec | Paperclip Minimizer (@paperclip-minim) | TBD | Draft | Standard | 2026-05-22 | +| 15 | Aztec Namespace | Define a Chain Agnostic Namespace for Aztec | Paperclip Minimizer (@paperclip-minim) | - | Draft | Standard | 2026-05-22 | ## Abstract From 66b253c3832b08859b5f23e92679164353149c01 Mon Sep 17 00:00:00 2001 From: Paperclip Minimizer Date: Fri, 22 May 2026 15:02:44 -0300 Subject: [PATCH 3/3] fix: promote Address Representation to H3 in rationale section --- AZIPs/azip-15.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AZIPs/azip-15.md b/AZIPs/azip-15.md index 2d21996..24afe29 100644 --- a/AZIPs/azip-15.md +++ b/AZIPs/azip-15.md @@ -309,7 +309,7 @@ Truncating the contract address (by the one character required to reach the boun Alternatively, we considered compressing the block-number and the truncated TX hash of the deploying TX. This way, lookup could happen by checking known EVM chains at the given block number and looking for the TX whose first bits matched the truncated TX hash. However, this already involves more than one node query, in contrast with the one required via the use of a registry. -#### Address representations +### Address representations Including a checksum dependent on chain ID makes direct substitution of the chain ID invalid.