@bananapus/address-registry-v6 0.0.14 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ You are auditing a permissionless address registry for Juicebox V6. The contract
6
6
 
7
7
  | Setting | Value |
8
8
  |---------|-------|
9
- | Solidity version | ^0.8.26 |
9
+ | Solidity version | 0.8.28 |
10
10
  | EVM target | cancun |
11
11
  | Optimizer | enabled, 200 runs |
12
12
  | via-IR | not enabled |
package/CHANGE_LOG.md CHANGED
@@ -6,18 +6,32 @@ This document describes all changes between `nana-address-registry` (v5) and `na
6
6
 
7
7
  - **Nonce range extended from `uint32` to `uint64`**: Fixes silent address miscalculation for large nonces — previously truncated without error, now correctly RLP-encodes up to `uint64` and reverts above.
8
8
  - **New `NonceTooLarge` error**: Explicit revert replaces silent truncation for nonces exceeding `uint64.max`.
9
+ - **New `ZeroDeployer` error**: Both `registerAddress` overloads revert if `deployer == address(0)`.
9
10
  - **No ABI-breaking changes**: Interface and function signatures are identical — only the internal nonce encoding logic changed.
10
11
 
12
+ ## ABI Status
13
+
14
+ This repo is intentionally close to ABI-stable across v5 → v6:
15
+ - external function selectors are unchanged;
16
+ - event signature is unchanged;
17
+ - the ABI-surface additions that most off-chain tooling will notice are the new custom errors `JBAddressRegistry_NonceTooLarge(uint256)` and `JBAddressRegistry_ZeroDeployer()`.
18
+
19
+ For most integrations, this is an import/address upgrade rather than a contract-interface rewrite.
20
+
11
21
  ---
12
22
 
13
23
  ## 1. Breaking Changes
14
24
 
15
- - **Solidity version bump**: `0.8.23` → `^0.8.26`. Contracts compiled against v5 ABIs will still be compatible (no ABI-level breaking changes), but the compiler version requirement has changed.
25
+ - **Solidity version bump**: `0.8.23` → `0.8.28`. Contracts compiled against v5 ABIs will still be compatible (no ABI-level breaking changes), but the compiler version requirement has changed.
16
26
  - **Nonce range extended from `uint32` to `uint64`**: In v5, the `_addressFrom` function silently produced incorrect addresses for nonces at or above `2^32`. In v6, nonces up to `uint64.max` are correctly RLP-encoded, and nonces above `uint64.max` revert with `JBAddressRegistry_NonceTooLarge`. Any off-chain tooling that assumed the `uint32` ceiling must be updated.
17
27
 
18
28
  ## 2. New Features
19
29
 
20
30
  - **Extended nonce support (uint40 through uint64)**: Four new RLP encoding branches handle nonces in the ranges `uint40`, `uint48`, `uint56`, and `uint64`, covering any realistic Ethereum account nonce.
31
+ - **No calling-pattern changes**: Both registration flows remain the same:
32
+ - `registerAddress(address deployer, uint256 nonce)` for `create`
33
+ - `registerAddress(address deployer, bytes32 salt, bytes memory bytecode)` for `create2`
34
+ Off-chain callers do not need new arguments or a new event subscription pattern.
21
35
 
22
36
  ## 3. Event Changes
23
37
 
@@ -32,10 +46,24 @@ event AddressRegistered(address indexed addr, address indexed deployer, address
32
46
  | Error | v5 | v6 |
33
47
  |---|---|---|
34
48
  | `JBAddressRegistry_NonceTooLarge(uint256 nonce)` | Does not exist | **Added** — reverts when `nonce > type(uint64).max` |
49
+ | `JBAddressRegistry_ZeroDeployer()` | Does not exist | **Added** — reverts when `deployer == address(0)` in either `registerAddress` overload |
50
+
51
+ Unchanged and still relevant:
52
+ - `JBAddressRegistry_AlreadyRegistered(address addr)` still guards duplicate registration attempts.
35
53
 
36
54
  In v5, passing a nonce larger than `uint32` fell through to the `else` branch, which cast the nonce to `uint32`, silently truncating it and producing an incorrect address. v6 replaces this silent truncation with an explicit revert.
37
55
 
38
- ## 5. Implementation Changes (Non-Interface)
56
+ ## 5. Function Surface
57
+
58
+ All external function signatures are unchanged, which means ABI consumers can usually migrate by swapping package/import paths:
59
+
60
+ | Function | v5 | v6 | Integration impact |
61
+ |---|---|---|---|
62
+ | `deployerOf(address)` | Same | Same | No code changes beyond import/address updates |
63
+ | `registerAddress(address,uint256)` | Same | Same | `create` registration still works; high nonces now succeed through `uint64.max` |
64
+ | `registerAddress(address,bytes32,bytes)` | Same | Same | `create2` flow unchanged |
65
+
66
+ ## 6. Implementation Changes (Non-Interface)
39
67
 
40
68
  ### `_addressFrom` — RLP nonce encoding
41
69
 
@@ -82,13 +110,21 @@ The v6 interface (`IJBAddressRegistry`) adds full NatDoc documentation that was
82
110
 
83
111
  No function signatures, parameter types, or return types changed.
84
112
 
85
- ## 6. Migration Table
113
+ ## 7. Migration Table
86
114
 
87
115
  | v5 | v6 | Action Required |
88
116
  |---|---|---|
89
117
  | `IJBAddressRegistry` | `IJBAddressRegistry` | **None** — ABI-identical. Update import path only. |
90
- | `JBAddressRegistry` | `JBAddressRegistry` | **None** — ABI-compatible. Deploy new instance compiled with Solidity ^0.8.26. |
118
+ | `JBAddressRegistry` | `JBAddressRegistry` | **None** — ABI-compatible. Deploy new instance compiled with Solidity 0.8.28. |
91
119
  | `registerAddress(address, uint256)` | `registerAddress(address, uint256)` | **None** — signature unchanged. Nonces > `uint32` now work correctly; nonces > `uint64` now revert instead of silently producing wrong addresses. |
92
120
  | `registerAddress(address, bytes32, bytes)` | `registerAddress(address, bytes32, bytes)` | **None** — signature unchanged. |
93
121
  | `deployerOf(address)` | `deployerOf(address)` | **None** — signature unchanged. |
94
122
  | (no error) | `JBAddressRegistry_NonceTooLarge(uint256)` | **New** — callers passing nonces > `uint64.max` must handle this revert. |
123
+ | (no error) | `JBAddressRegistry_ZeroDeployer()` | **New** — callers passing `address(0)` as deployer must handle this revert. |
124
+
125
+ Practical migration checklist:
126
+ - Update the package/import path from v5 to v6.
127
+ - Keep existing ABI encoders/decoders; the external surface is unchanged.
128
+ - If you predict `create` addresses off-chain, remove any hardcoded `uint32` nonce ceiling assumption.
129
+ - Handle `JBAddressRegistry_NonceTooLarge` if you expose arbitrary nonce input to users or tooling.
130
+ - Handle `JBAddressRegistry_ZeroDeployer` if callers might pass `address(0)` as the deployer.
package/SKILLS.md CHANGED
@@ -39,15 +39,17 @@ Deployed on: Ethereum, Optimism, Arbitrum, Base, and their Sepolia testnets.
39
39
  | Function | What it does |
40
40
  |----------|--------------|
41
41
  | `_addressFrom(address origin, uint256 nonce) returns (address)` | Computes `create` address using RLP encoding. Handles 10 nonce ranges: `0`, `1-0x7f`, `0x80-0xff`, `0x100-0xffff`, `0x10000-0xffffff`, `0x1000000-0xffffffff`, `0x100000000-0xffffffffff`, `0x10000000000-0xffffffffffff`, `0x1000000000000-0xffffffffffffff`, `0x100000000000000-0xffffffffffffffff`. Reverts with `JBAddressRegistry_NonceTooLarge` for nonces above `uint64` max. Uses `keccak256` of the RLP-encoded `[origin, nonce]` and extracts the low 160 bits via assembly. |
42
- | `_registerAddress(address addr, address deployer)` | Writes `deployerOf[addr] = deployer` and emits `AddressRegistered`. Shared by both public `registerAddress` overloads. |
42
+ | `_registerAddress(address addr, address deployer)` | Reverts with `JBAddressRegistry_ZeroDeployer` if `deployer == address(0)`. Reverts with `JBAddressRegistry_AlreadyRegistered` if `deployerOf[addr] != address(0)`. Otherwise writes `deployerOf[addr] = deployer` and emits `AddressRegistered`. Shared by both public `registerAddress` overloads. |
43
43
 
44
44
  ## Errors
45
45
 
46
46
  | Error | Defined In | Trigger Condition |
47
47
  |-------|-----------|-------------------|
48
48
  | `JBAddressRegistry_NonceTooLarge(uint256 nonce)` | `JBAddressRegistry` | `registerAddress(deployer, nonce)` is called with a `nonce` greater than `type(uint64).max` (18,446,744,073,709,551,615). Reverts inside `_addressFrom` before any state change. In practice unreachable since no EOA or contract can reach this nonce. |
49
+ | `JBAddressRegistry_AlreadyRegistered(address addr)` | `JBAddressRegistry` | Either `registerAddress` overload is called with parameters that compute to an address already present in `deployerOf`. Reverts inside `_registerAddress` before any state change. |
50
+ | `JBAddressRegistry_ZeroDeployer()` | `JBAddressRegistry` | Either `registerAddress` overload is called with `deployer == address(0)`. Reverts inside `_registerAddress` before any state change. |
49
51
 
50
- This is the only custom error in the contract. The `create2` overload of `registerAddress` has no revert paths (invalid parameters silently compute the wrong address).
52
+ Both `registerAddress` overloads can revert with `JBAddressRegistry_ZeroDeployer` (if `deployer == address(0)`) and `JBAddressRegistry_AlreadyRegistered` (if the computed address was previously registered). The `create` overload can additionally revert with `JBAddressRegistry_NonceTooLarge`. Invalid `create2` parameters (wrong salt or bytecode) do not revert they silently compute the wrong address.
51
53
 
52
54
  ## Integration Points
53
55
 
@@ -89,13 +91,13 @@ No arrays, no structs, no linked lists. One mapping, that is all.
89
91
  ## Gotchas
90
92
 
91
93
  - **Nonce limit**: `_addressFrom` supports nonces up to `uint64` max (18,446,744,073,709,551,615). Nonces above this revert with `JBAddressRegistry_NonceTooLarge`. In practice this limit is unreachable.
92
- - **No overwrite protection**: Calling `registerAddress` with parameters that compute to an already-registered address will overwrite the `deployerOf` entry. This is safe because only the correct deployer + parameters produce a given address. But be aware that the same address can be "re-registered" by anyone at any time (with the same result).
94
+ - **No overwrite — duplicate reverts**: Calling `registerAddress` with parameters that compute to an already-registered address reverts with `JBAddressRegistry_AlreadyRegistered`. Only the first registration is accepted.
93
95
  - **Permissionless**: Anyone can call `registerAddress`, not just the deployer. `msg.sender` is recorded in the event as `caller` but is NOT stored in the mapping. Only the computed deployer is stored.
94
96
  - **No validation**: The registry does not check that `addr` has code deployed, or that the deployer is a real deployer. It purely does math and stores the result. If you pass wrong parameters, it silently registers a mapping for the wrong address. Frontends MUST verify `addr.code.length > 0` (or `extcodesize(addr) > 0` in assembly) before trusting a registry entry.
95
- - **`deployerOf` returns `address(0)` for unregistered addresses**: This is the default mapping value, not a sentinel. There is no way to distinguish "never registered" from "registered with deployer = address(0)" (though the latter would require someone to call `registerAddress(address(0), ...)` deliberately).
97
+ - **`deployerOf` returns `address(0)` for unregistered addresses**: This is the default mapping value, not a sentinel. Since `JBAddressRegistry_ZeroDeployer` prevents registering `address(0)` as a deployer, `deployerOf[addr] == address(0)` reliably means "not registered".
96
98
  - **`create2` bytecode must include constructor args**: When registering a `create2` deployment, the `bytecode` parameter must be the full creation bytecode including ABI-encoded constructor arguments: `abi.encodePacked(type(Contract).creationCode, abi.encode(arg1, arg2, ...))`. Omitting constructor args will compute the wrong address.
97
99
  - **Contract nonces start at 1**: When using the `create` overload to register a contract deployed by another contract, remember that contract nonces start at 1 (not 0 like EOAs). The first contract deployed by a factory is at nonce 1.
98
- - **Solidity version**: The implementation uses `pragma solidity ^0.8.26`. The interface uses `pragma solidity ^0.8.0` (flexible) so it can be imported by any 0.8.x consumer.
100
+ - **Solidity version**: The implementation uses `pragma solidity 0.8.28`. The interface uses `pragma solidity ^0.8.0` (flexible) so it can be imported by any 0.8.x consumer.
99
101
 
100
102
  ## Example: Register a `create` Deployment
101
103
 
package/STYLE_GUIDE.md CHANGED
@@ -21,7 +21,7 @@ One contract/interface/struct/enum per file. Name the file after the type it con
21
21
 
22
22
  ```solidity
23
23
  // Contracts — pin to exact version
24
- pragma solidity ^0.8.26;
24
+ pragma solidity 0.8.28;
25
25
 
26
26
  // Interfaces, structs, enums — caret for forward compatibility
27
27
  pragma solidity ^0.8.0;
@@ -326,7 +326,7 @@ Standard config across all repos:
326
326
 
327
327
  ```toml
328
328
  [profile.default]
329
- solc = '0.8.26'
329
+ solc = '0.8.28'
330
330
  evm_version = 'cancun'
331
331
  optimizer_runs = 200
332
332
  libs = ["node_modules", "lib"]
package/foundry.toml CHANGED
@@ -1,5 +1,5 @@
1
1
  [profile.default]
2
- solc = '0.8.26'
2
+ solc = '0.8.28'
3
3
  evm_version = 'cancun'
4
4
  optimizer_runs = 200
5
5
  libs = ["node_modules", "lib"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananapus/address-registry-v6",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
5
5
  import {Script} from "forge-std/Script.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {stdJson} from "forge-std/Script.sol";
5
5
  import {Vm} from "forge-std/Vm.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {IJBAddressRegistry} from "./interfaces/IJBAddressRegistry.sol";
5
5
 
@@ -23,6 +23,9 @@ contract JBAddressRegistry is IJBAddressRegistry {
23
23
  /// @notice Thrown when a nonce exceeds the maximum value supported by the RLP encoding (uint64 max).
24
24
  error JBAddressRegistry_NonceTooLarge(uint256 nonce);
25
25
 
26
+ /// @notice Thrown when attempting to register with `address(0)` as the deployer.
27
+ error JBAddressRegistry_ZeroDeployer();
28
+
26
29
  //*********************************************************************//
27
30
  // --------------------- public stored properties -------------------- //
28
31
  //*********************************************************************//
@@ -124,6 +127,7 @@ contract JBAddressRegistry is IJBAddressRegistry {
124
127
  /// @param addr The deployed contract's address.
125
128
  /// @param deployer The deployer's address.
126
129
  function _registerAddress(address addr, address deployer) internal {
130
+ if (deployer == address(0)) revert JBAddressRegistry_ZeroDeployer();
127
131
  if (deployerOf[addr] != address(0)) revert JBAddressRegistry_AlreadyRegistered(addr);
128
132
 
129
133
  deployerOf[addr] = deployer;
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {Test} from "forge-std/Test.sol";
5
5
  import {JBAddressRegistry} from "../src/JBAddressRegistry.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {Test} from "forge-std/Test.sol";
5
5
  import {JBAddressRegistry} from "../src/JBAddressRegistry.sol";
@@ -235,13 +235,16 @@ contract JBAddressRegistryEdge is Test {
235
235
  // address(0) deployer
236
236
  // =========================================================================
237
237
 
238
- /// @notice Registration with address(0) as deployer succeeds (permissionless).
239
- function test_zeroAddressDeployer_succeeds() public {
240
- // This should not revert - the registry is permissionless and doesn't validate.
238
+ /// @notice Registration with address(0) as deployer reverts with `ZeroDeployer`.
239
+ function test_zeroAddressDeployer_reverts() public {
240
+ vm.expectRevert(JBAddressRegistry.JBAddressRegistry_ZeroDeployer.selector);
241
241
  registry.registerAddress(address(0), 1);
242
+ }
242
243
 
243
- // The computed address for (address(0), nonce=1) gets mapped to address(0).
244
- // We just verify no revert and the mapping is set.
244
+ /// @notice Create2 registration with address(0) as deployer reverts with `ZeroDeployer`.
245
+ function test_zeroAddressDeployer_create2_reverts() public {
246
+ vm.expectRevert(JBAddressRegistry.JBAddressRegistry_ZeroDeployer.selector);
247
+ registry.registerAddress(address(0), bytes32(uint256(42)), hex"60006000f3");
245
248
  }
246
249
 
247
250
  // =========================================================================
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {Test} from "forge-std/Test.sol";
5
5
  import {JBAddressRegistry} from "../src/JBAddressRegistry.sol";
@@ -0,0 +1,31 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.28;
3
+
4
+ import {Test} from "forge-std/Test.sol";
5
+
6
+ import {JBAddressRegistry} from "src/JBAddressRegistry.sol";
7
+
8
+ contract ZeroDeployerRegistrationTest is Test {
9
+ JBAddressRegistry internal registry;
10
+
11
+ function setUp() public {
12
+ registry = new JBAddressRegistry();
13
+ }
14
+
15
+ /// @notice Registering with `address(0)` as the deployer via `create` reverts with `ZeroDeployer`.
16
+ function test_createRegistrationWithZeroDeployerReverts() external {
17
+ uint256 nonce = 1;
18
+
19
+ vm.expectRevert(JBAddressRegistry.JBAddressRegistry_ZeroDeployer.selector);
20
+ registry.registerAddress(address(0), nonce);
21
+ }
22
+
23
+ /// @notice Registering with `address(0)` as the deployer via `create2` reverts with `ZeroDeployer`.
24
+ function test_create2RegistrationWithZeroDeployerReverts() external {
25
+ bytes32 salt = keccak256("salt");
26
+ bytes memory bytecode = hex"60006000f3";
27
+
28
+ vm.expectRevert(JBAddressRegistry.JBAddressRegistry_ZeroDeployer.selector);
29
+ registry.registerAddress(address(0), salt, bytecode);
30
+ }
31
+ }
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {Test} from "forge-std/Test.sol";
5
5
  import {JBAddressRegistry} from "../../src/JBAddressRegistry.sol";