@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.
- package/AUDIT_INSTRUCTIONS.md +1 -1
- package/CHANGE_LOG.md +40 -4
- package/SKILLS.md +7 -5
- package/STYLE_GUIDE.md +2 -2
- package/foundry.toml +1 -1
- package/package.json +1 -1
- package/script/Deploy.s.sol +1 -1
- package/script/helpers/AddressRegistryDeploymentLib.sol +1 -1
- package/src/JBAddressRegistry.sol +5 -1
- package/test/JBAddressRegistry.t.sol +1 -1
- package/test/JBAddressRegistryEdge.t.sol +9 -6
- package/test/JBAddressRegistry_Fork.t.sol +1 -1
- package/test/audit/ZeroDeployerRegistration.t.sol +31 -0
- package/test/regression/NonceTruncation.t.sol +1 -1
package/AUDIT_INSTRUCTIONS.md
CHANGED
|
@@ -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 |
|
|
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` →
|
|
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.
|
|
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
|
-
##
|
|
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
|
|
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)` |
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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
package/package.json
CHANGED
package/script/Deploy.s.sol
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity
|
|
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
|
|
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
|
|
239
|
-
function
|
|
240
|
-
|
|
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
|
-
|
|
244
|
-
|
|
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
|
// =========================================================================
|
|
@@ -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
|
+
}
|