@bananapus/address-registry-v6 0.0.16 → 0.0.18

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/ADMINISTRATION.md CHANGED
@@ -1,48 +1,67 @@
1
1
  # Administration
2
2
 
3
- Admin privileges and their scope in nana-address-registry-v6.
3
+ ## At A Glance
4
+
5
+ | Item | Details |
6
+ | --- | --- |
7
+ | Scope | Permissionless provenance registration for CREATE and CREATE2 addresses |
8
+ | Control posture | Fully permissionless and adminless |
9
+ | Highest-risk actions | Incorrect first registration or bad derivation assumptions in offchain tooling |
10
+ | Recovery posture | No in-place recovery; replacement contract is the only fix for logic mistakes |
11
+
12
+ ## Purpose
13
+
14
+ `nana-address-registry-v6` has no admin surface. It is a permissionless first-write provenance registry.
15
+
16
+ ## Control Model
17
+
18
+ - No owner
19
+ - No governance
20
+ - No pause
21
+ - No upgrade
22
+ - Registration is permissionless and correctness comes from deterministic address derivation
4
23
 
5
24
  ## Roles
6
25
 
7
- None. `JBAddressRegistry` has no owner, no admin, and no access control. The contract does not inherit from `Ownable`, `AccessControl`, or any permissioned pattern.
26
+ | Role | How Assigned | Scope | Notes |
27
+ | --- | --- | --- | --- |
28
+ | Anyone | No assignment | Global | Can register an address if they provide correct CREATE or CREATE2 inputs |
29
+
30
+ ## Privileged Surfaces
8
31
 
9
- ## Privileged Functions
32
+ There are no privileged functions. `registerAddress(...)` is permissionless for both CREATE and CREATE2 registration paths.
10
33
 
11
- ### JBAddressRegistry
34
+ ## Immutable And One-Way
12
35
 
13
- | Function | Required Role | Permission ID | Scope | What It Does |
14
- |----------|--------------|---------------|-------|--------------|
15
- | `registerAddress(address deployer, uint256 nonce)` | None | N/A | Global | Computes a `create` address from deployer + nonce and stores the deployer mapping |
16
- | `registerAddress(address deployer, bytes32 salt, bytes bytecode)` | None | N/A | Global | Computes a `create2` address from deployer + salt + bytecode and stores the deployer mapping |
17
- | `deployerOf(address)` | None | N/A | Global | View function — returns the registered deployer for a given address |
36
+ - Registration is first-write only.
37
+ - There is no overwrite or delete path for `deployerOf[address]`.
18
38
 
19
- Every function is callable by any address. There are no restricted operations.
39
+ ## Operational Notes
20
40
 
21
- ## Registration Model
41
+ - Treat registration as provenance, not endorsement.
42
+ - Register addresses from trustworthy operational pipelines because bad first registration is sticky even though anyone can submit the correct derivation inputs.
22
43
 
23
- - **Fully permissionless.** Any address can register any deployer/nonce or deployer/salt/bytecode combination.
24
- - **No caller verification.** The registry does not check whether `msg.sender` is the deployer. It only verifies that the computed address is valid by storing the mapping.
25
- - **Overwritable.** A second registration for the same computed address overwrites the previous deployer mapping. Last writer wins.
26
- - **Permanent storage, no removal.** There is no `unregister` or `removeAddress` function. Entries can be overwritten but never deleted.
27
- - **No approval or queue.** Registrations take effect immediately in the same transaction.
44
+ ## Machine Notes
28
45
 
29
- ## Client-Side Trust
46
+ - Do not treat registration as a safety certification or allowlist signal.
47
+ - `src/JBAddressRegistry.sol` is the only control-relevant runtime file; there is no hidden owner path.
48
+ - If offchain derivation and onchain registration disagree, stop and resolve the derivation logic rather than assuming overwrite is possible.
30
49
 
31
- The registry stores deployer mappings without making trust judgments. All trust decisions are delegated to clients:
50
+ ## Recovery
32
51
 
33
- - **No on-chain filtering.** The contract does not distinguish "trusted" from "untrusted" deployers. Clients must maintain their own allowlist of known deployer addresses and cross-reference against `deployerOf()`.
34
- - **Event-based discovery.** The contract emits an `AddressRegistered(address indexed addr, address indexed deployer, address caller)` event on every registration. Clients can monitor this event to discover new registrations in real time.
35
- - **Overwrite risk.** Since registrations are overwritable, a client that caches `deployerOf(addr)` at time T may see a different result at time T+1 if someone re-registers the same address with a different deployer/nonce or deployer/salt/bytecode combination. Clients should re-check at time of use rather than caching indefinitely.
36
- - **No validation of deployment.** The registry computes the expected address from the inputs but does not verify that a contract actually exists at that address. A registration can be created for an address that has not yet been deployed (or will never be deployed).
52
+ - There is no admin recovery surface.
53
+ - If derivation logic were ever wrong, the contract would need replacement rather than intervention.
37
54
 
38
55
  ## Admin Boundaries
39
56
 
40
- There are no admins. Specifically:
57
+ - Nobody can curate allowlists, edit entries, or block registration.
58
+ - Nobody can use this registry to certify code safety.
41
59
 
42
- - **No pause mechanism.** The registry cannot be paused or frozen.
43
- - **No upgrade path.** The contract is not proxied or upgradeable.
44
- - **No fee extraction.** The contract holds no funds and collects no fees.
45
- - **No blocklist.** No address can be prevented from registering.
46
- - **No migration.** There is no way to transfer state to a new registry contract.
60
+ ## Source Map
47
61
 
48
- The only trust assumption is on the frontend side: clients must maintain their own list of trusted deployers and use `deployerOf()` to check whether a contract was deployed by one of them. The registry itself makes no trust judgments.
62
+ - `src/JBAddressRegistry.sol`
63
+ - `src/interfaces/IJBAddressRegistry.sol`
64
+ - `script/Deploy.s.sol`
65
+ - `script/helpers/AddressRegistryDeploymentLib.sol`
66
+ - `test/JBAddressRegistry_Fork.t.sol`
67
+ - `test/regression/NonceTruncation.t.sol`
package/ARCHITECTURE.md CHANGED
@@ -1,57 +1,84 @@
1
- # nana-address-registry-v6 — Architecture
1
+ # Architecture
2
2
 
3
3
  ## Purpose
4
4
 
5
- Juicebox projects can attach arbitrary hook contracts (pay hooks, cashout hooks, 721 tier hooks, etc.) that execute during payments, cashouts, and payouts. A malicious hook could steal funds or mislead users. Frontends need a way to answer the question: "Was this hook deployed by a trusted deployer like `JB721TiersHookDeployer`?"
5
+ `nana-address-registry-v6` is a narrow provenance primitive. It records which deployer could have created a contract address by recomputing CREATE or CREATE2 derivation inputs and storing the verified result on-chain.
6
6
 
7
- `JBAddressRegistry` solves this by letting contracts deployed via `create` or `create2` publicly register their deployer's address. A frontend can then call `deployerOf(hookAddress)` and check the result against its own list of trusted deployers — displaying warnings or blocking interactions for hooks with unknown origins.
7
+ ## System Overview
8
8
 
9
- ## Contract Map
9
+ The repo is intentionally small. `JBAddressRegistry` accepts deterministic deployment inputs, reconstructs the resulting address, and records the deployer if that address has not already been registered. It does not judge code safety, manage upgrades, or gate deployments.
10
10
 
11
- ```
12
- src/
13
- ├── JBAddressRegistry.sol — Registry: registerAddress (create/create2), deployerOf mapping
14
- └── interfaces/
15
- └── IJBAddressRegistry.sol — Interface
16
- ```
17
-
18
- ## Key Operations
19
-
20
- ### Registration (create)
21
- ```
22
- Deployer → JBAddressRegistry.registerAddress(deployer, nonce)
23
- → Compute address via RLP encoding of [deployer, nonce]
24
- → Store deployerOf[computedAddress] = deployer
25
- → Emit AddressRegistered
26
- ```
11
+ ## Core Invariants
27
12
 
28
- ### Registration (create2)
29
- ```
30
- Deployer JBAddressRegistry.registerAddress(deployer, salt, bytecode)
31
- Compute address via keccak256(0xff ++ deployer ++ salt ++ keccak256(bytecode))
32
- → Store deployerOf[computedAddress] = deployer
33
- → Emit AddressRegistered
34
- ```
35
-
36
- ### Verification
37
- ```
38
- Frontend → JBAddressRegistry.deployerOf(hookAddress)
39
- → Returns deployer address (or address(0) if unregistered)
40
- → Frontend checks deployer against trusted deployer list
41
- ```
13
+ - Registration is permissionless because correctness comes from deterministic derivation, not caller authority.
14
+ - A contract address can only be registered once.
15
+ - Registration must fail until runtime code actually exists at the derived address.
16
+ - CREATE and CREATE2 derivation must match EVM rules exactly.
42
17
 
43
- ## Design Decisions
18
+ ## Modules
44
19
 
45
- **Deployer verification, not a whitelist.** The registry records *who* deployed a contract, not *whether* a contract is approved. This keeps the registry permissionless and neutral — any deployer can register, and trust decisions are made by each frontend independently. There is no governance or admin role.
20
+ | Module | Responsibility | Notes |
21
+ | --- | --- | --- |
22
+ | `JBAddressRegistry` | Address derivation and first-write provenance storage | Main contract |
23
+ | `IJBAddressRegistry` | Minimal lookup and registration interface | External surface |
46
24
 
47
- **Both `create` and `create2` support.** Deployers that use `create` (nonce-based) and `create2` (salt + bytecode) both exist in the Juicebox ecosystem. Supporting both ensures any deployer can register its contracts regardless of deployment strategy.
25
+ ## Trust Boundaries
48
26
 
49
- **No validation beyond hash match.** The registry does not check that registered addresses contain code, implement a particular interface, or were recently deployed. It only verifies that the provided deployer + nonce/salt/bytecode deterministically produce the claimed address. This keeps the contract simple and gas-efficient — frontends already perform their own trust checks on the deployer address.
27
+ - The registry attests to deterministic provenance, not code quality.
28
+ - It does not manage ownership, upgrades, or allowlists.
29
+ - External systems may trust its recorded provenance, so derivation correctness is the whole product.
50
30
 
51
- **Anyone can call `registerAddress`.** Registration is not restricted to the deployer itself. Any account that knows the deployer address and nonce (or salt + bytecode) can register a contract. This is safe because the mapping is deterministic — providing incorrect inputs simply computes a different address, not a false registration for the target contract.
31
+ ## Critical Flows
52
32
 
53
- ## Dependencies
33
+ ### Register
54
34
 
55
- - `@sphinx-labs/plugins` — Deployment tooling (devDependency only)
35
+ ```text
36
+ caller
37
+ -> supplies deployer plus CREATE nonce or CREATE2 salt and bytecode
38
+ -> registry recomputes the target address
39
+ -> registry records the deployer if the address was previously unregistered
40
+ ```
56
41
 
57
- No runtime Solidity dependencies — this is a standalone contract.
42
+ ## Accounting Model
43
+
44
+ No economic accounting lives here. The only critical state is `deployerOf[address]`.
45
+
46
+ ## Security Model
47
+
48
+ - The risk is concentrated in a small amount of address-derivation logic.
49
+ - The registry records the derived deployer, not the transaction caller. Mixing those concepts would turn provenance into an authority bug.
50
+ - Overengineering is more dangerous than minimal, auditable derivation code.
51
+
52
+ ## Safe Change Guide
53
+
54
+ - Treat derivation code like cryptographic plumbing.
55
+ - Keep the undeployed-address check and first-write-only rule intact; they are part of the provenance guarantee, not optional hygiene.
56
+ - If nonce handling or bytecode hashing changes, keep CREATE and CREATE2 tests aligned.
57
+ - Do not expand the repo into an allowlist or trust-oracle system.
58
+
59
+ ## Canonical Checks
60
+
61
+ - CREATE and CREATE2 derivation correctness:
62
+ `test/JBAddressRegistry.t.sol`
63
+ - edge-path validation and first-write behavior:
64
+ `test/JBAddressRegistryEdge.t.sol`
65
+ - pre-registration, frontrun, and undeployed-code defenses:
66
+ `test/audit/CodexFrontRunRegistrationDoS.t.sol`
67
+ - provenance abuse and zero-deployer edge cases:
68
+ `test/audit/CodexUnauthorizedRegistrar.t.sol`
69
+ `test/audit/ZeroDeployerRegistration.t.sol`
70
+
71
+ ## Source Map
72
+
73
+ - `src/JBAddressRegistry.sol`
74
+ - `src/interfaces/IJBAddressRegistry.sol`
75
+ - `test/JBAddressRegistry.t.sol`
76
+ - `test/JBAddressRegistryEdge.t.sol`
77
+ - `test/audit/CodexFrontRunRegistrationDoS.t.sol`
78
+ - `test/audit/CodexUnauthorizedRegistrar.t.sol`
79
+ - `test/audit/ZeroDeployerRegistration.t.sol`
80
+ - `test/regression/NonceTruncation.t.sol`
81
+ - `script/Deploy.s.sol`
82
+ - `script/helpers/AddressRegistryDeploymentLib.sol`
83
+ - `references/runtime.md`
84
+ - `references/operations.md`
@@ -1,147 +1,66 @@
1
- # Audit Instructions -- nana-address-registry-v6
1
+ # Audit Instructions
2
2
 
3
- You are auditing a permissionless address registry for Juicebox V6. The contract stores a mapping from deployed contract addresses to their deployers, computed deterministically from `create` or `create2` parameters. It has no owner, no access control, no constructor arguments, and no external dependencies. Read [RISKS.md](./RISKS.md) first -- it documents all known risks and trust assumptions. Then come back here.
3
+ This repo is a small registry, but it participates in deployer verification across the ecosystem. Treat incorrect registration as a security boundary failure.
4
4
 
5
- ## Compiler and Version Info
5
+ ## Audit Objective
6
6
 
7
- | Setting | Value |
8
- |---------|-------|
9
- | Solidity version | 0.8.28 |
10
- | EVM target | cancun |
11
- | Optimizer | enabled, 200 runs |
12
- | via-IR | not enabled |
13
- | Fuzz runs | 4,096 |
14
- | Invariant runs | 1,024 (depth 100) |
15
-
16
- Source: [`foundry.toml`](./foundry.toml)
17
-
18
- ## Previous Audit Findings
19
-
20
- A Nemesis automated audit was conducted on 2026-03-17. Results are in [`.audit/findings/nemesis-verified.md`](./.audit/findings/nemesis-verified.md). Summary:
21
-
22
- | ID | Severity | Title | Status |
23
- |----|----------|-------|--------|
24
- | NM-001 | LOW | Deployment library project name mismatch (`"nana-address-registry"` vs `"nana-address-registry-v6"`) | Open (deployment script only, no runtime impact) |
25
-
26
- The core contract (`JBAddressRegistry`) was verified sound -- RLP encoding is correct across all 10 nonce ranges, CREATE2 computation matches EIP-1014. No CRITICAL, HIGH, or MEDIUM findings were identified.
27
-
28
- No prior formal audit with finding IDs from an external security firm has been conducted.
7
+ Find issues that:
8
+ - let callers register contracts under the wrong deployer
9
+ - break determinism or uniqueness assumptions around registration
10
+ - let a malicious deployer spoof provenance for contracts it did not create
11
+ - create stale or truncation-related collisions in recorded mappings
29
12
 
30
13
  ## Scope
31
14
 
32
- **In scope -- all Solidity in `src/`:**
33
- ```
34
- src/JBAddressRegistry.sol # Registry implementation (~127 lines)
35
- src/interfaces/IJBAddressRegistry.sol # Interface (~27 lines)
36
- ```
37
-
38
- **Out of scope:** Test files, deployment scripts, forge-std.
39
-
40
- ## Architecture
41
-
42
- ### JBAddressRegistry
43
-
44
- A standalone, stateless-logic contract with a single storage mapping:
45
-
46
- ```
47
- mapping(address addr => address deployer) public deployerOf;
48
- ```
49
-
50
- Two public `registerAddress` overloads accept deployer parameters, compute the deterministic address, and store the mapping. No validation is performed beyond address computation and a nonce range check.
51
-
52
- ### Registration (create)
53
-
54
- `registerAddress(address deployer, uint256 nonce)`:
55
- 1. Calls `_addressFrom(deployer, nonce)` to compute the `create` address via RLP encoding
56
- 2. Stores `deployerOf[computedAddress] = deployer`
57
- 3. Emits `AddressRegistered(computedAddress, deployer, msg.sender)`
58
-
59
- ### Registration (create2)
60
-
61
- `registerAddress(address deployer, bytes32 salt, bytes calldata bytecode)`:
62
- 1. Computes `address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, keccak256(bytecode))))))`
63
- 2. Stores `deployerOf[computedAddress] = deployer`
64
- 3. Emits `AddressRegistered(computedAddress, deployer, msg.sender)`
65
-
66
- ### RLP Encoding (_addressFrom)
67
-
68
- The internal `_addressFrom(address origin, uint256 nonce)` function implements RLP encoding of `[origin, nonce]` for `create` address computation. It handles 10 nonce ranges covering `0` through `type(uint64).max`:
69
-
70
- | Nonce Range | RLP Prefix Byte | Nonce Length Prefix |
71
- |-------------|----------------|---------------------|
72
- | `0` | `0xd6` | `0x80` (empty byte) |
73
- | `1 - 0x7f` | `0xd6` | (none, raw byte) |
74
- | `0x80 - 0xff` | `0xd7` | `0x81` |
75
- | `0x100 - 0xffff` | `0xd8` | `0x82` |
76
- | `0x10000 - 0xffffff` | `0xd9` | `0x83` |
77
- | `0x1000000 - 0xffffffff` | `0xda` | `0x84` |
78
- | `0x100000000 - 0xffffffffff` | `0xdb` | `0x85` |
79
- | `0x10000000000 - 0xffffffffffff` | `0xdc` | `0x86` |
80
- | `0x1000000000000 - 0xffffffffffffff` | `0xdd` | `0x87` |
81
- | `0x100000000000000 - 0xffffffffffffffff` | `0xde` | `0x88` |
82
-
83
- The final address is extracted from `keccak256(rlp_data)` via inline assembly: `mstore(0, hash); addr := mload(0)`.
84
-
85
- Nonces above `type(uint64).max` revert with `JBAddressRegistry_NonceTooLarge`.
86
-
87
- ## Priority Audit Areas
88
-
89
- ### 1. RLP Encoding Correctness (Highest Priority)
90
-
91
- The `_addressFrom` function is the only non-trivial logic in the contract. Verify:
15
+ In scope:
16
+ - `src/JBAddressRegistry.sol`
17
+ - `src/interfaces/IJBAddressRegistry.sol`
18
+ - all deployment helpers in `script/`
92
19
 
93
- - **Every nonce range boundary is correct.** The if/else chain must produce correct RLP for every boundary value: `0`, `1`, `0x7f`, `0x80`, `0xff`, `0x100`, `0xffff`, `0x10000`, etc., up to `type(uint64).max`. An off-by-one at any boundary would silently produce wrong addresses.
94
- - **RLP prefix bytes are correct.** The first byte (`0xd6`-`0xde`) encodes the total length of the list. Verify each prefix matches the actual encoded data length (20-byte address + nonce encoding + overhead).
95
- - **Nonce encoding is correct.** For nonce `0`, the RLP encoding is `0x80` (empty byte string), not `0x00`. For nonces `1-0x7f`, the nonce IS the RLP encoding (single byte). For `0x80+`, a length prefix is prepended.
96
- - **Assembly address extraction.** The final `mstore(0, hash); addr := mload(0)` extracts the low 160 bits of the keccak256 hash. Verify this is equivalent to `address(uint160(uint256(hash)))`.
97
- - **Comparison with reference implementations.** Cross-check against the Ethereum Yellow Paper, OpenZeppelin's `Create2` library, and the linked StackExchange reference (https://ethereum.stackexchange.com/a/87840/68134).
20
+ ## Start Here
98
21
 
99
- ### 2. create2 Address Computation
22
+ 1. `src/JBAddressRegistry.sol`
23
+ 2. `script/Deploy.s.sol`
100
24
 
101
- The `create2` overload uses `abi.encodePacked(bytes1(0xff), deployer, salt, keccak256(bytecode))`. Verify:
102
- - This matches the EIP-1014 specification exactly.
103
- - The `bytes calldata bytecode` parameter is hashed correctly (constructor arguments must be included by the caller; the contract does not append them).
104
- - No length ambiguity in the packed encoding (each component has fixed size: 1 + 20 + 32 + 32 = 85 bytes).
25
+ ## Security Model
105
26
 
106
- ### 3. Overwrite Behavior
27
+ The registry maps deployed addresses to the deployer that created them. Downstream repos use it to:
28
+ - validate provenance for clones or deterministically deployed instances
29
+ - discover whether a contract came from an approved deployer path
107
30
 
108
- `_registerAddress` unconditionally overwrites `deployerOf[addr]`. Verify:
109
- - A re-registration with the same parameters produces the same result (idempotent).
110
- - A re-registration with different parameters that happen to compute the same address (collision) would overwrite. Since address collisions require a keccak256 collision, this is cryptographically infeasible -- but confirm there is no cheaper attack vector.
111
- - The `caller` field in the `AddressRegistered` event correctly reflects `msg.sender`, not the `deployer` parameter.
31
+ ## Roles And Privileges
112
32
 
113
- ### 4. Gas and DoS
33
+ | Role | Powers | How constrained |
34
+ |------|--------|-----------------|
35
+ | Deployer | Register contracts as its outputs | Must prove authentic deployment provenance |
36
+ | Registry reader | Trust provenance for privileged decisions | Must not observe spoofable or mutable history |
114
37
 
115
- The contract has no loops, no arrays, and no unbounded storage growth beyond the mapping. Verify:
116
- - `registerAddress` has bounded gas cost regardless of inputs.
117
- - The `bytecode` parameter in the `create2` overload is hashed in memory. For very large bytecode, this could consume significant memory gas but cannot cause an OOG in the registry itself (the caller pays).
38
+ ## Integration Assumptions
118
39
 
119
- ## Invariants to Verify
40
+ | Dependency | Assumption | What breaks if wrong |
41
+ |------------|------------|----------------------|
42
+ | Approved deployers | Produce the addresses they claim | Downstream provenance gates become meaningless |
120
43
 
121
- 1. **Determinism**: For any `(deployer, nonce)` pair, `_addressFrom` always returns the same address, and that address matches what the EVM would produce for a `create` deployment from `deployer` at `nonce`.
122
- 2. **create2 correctness**: For any `(deployer, salt, bytecode)` triple, the computed address matches what the EVM would produce for a `create2` deployment.
123
- 3. **No side effects**: `registerAddress` only modifies `deployerOf[computedAddress]` and emits one event. No other state is touched.
124
- 4. **Nonce boundary completeness**: Every valid nonce (0 through `type(uint64).max`) produces a correct RLP encoding. No nonce in this range falls through without being encoded.
44
+ ## Critical Invariants
125
45
 
126
- ## Testing Setup
46
+ 1. Provenance cannot be forged
47
+ Only the actual deployer path the registry intends to trust may create a successful registration for a contract.
127
48
 
128
- ```bash
129
- cd nana-address-registry-v6
130
- npm install
131
- forge build
132
- forge test
49
+ 2. One contract maps to one authoritative deployer record
50
+ No aliasing or overwrite path should let a later caller replace provenance unexpectedly.
133
51
 
134
- # Run edge case tests
135
- forge test --match-contract JBAddressRegistryEdge -vvv
52
+ 3. Registration metadata is stable
53
+ Nonce, salt, or address truncation must not allow collisions or stale reads.
136
54
 
137
- # Run nonce truncation regression test
138
- forge test --match-path test/regression/NonceTruncation.t.sol -vvv
55
+ ## Attack Surfaces
139
56
 
140
- # Run fork tests
141
- forge test --match-contract Fork -vvv
57
+ - registration entrypoints that rely on deployer provenance
58
+ - overwrite and replay paths
59
+ - deterministic deployment assumptions
60
+ - zero-address or malformed registration attempts
142
61
 
143
- # Write a PoC
144
- forge test --match-path test/audit/ExploitPoC.t.sol -vvv
145
- ```
62
+ ## Verification
146
63
 
147
- Go break it.
64
+ - `npm install`
65
+ - `forge build`
66
+ - `forge test`
package/CHANGELOG.md ADDED
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ ## Scope
4
+
5
+ This file describes the verified change from `nana-address-registry-v5` to the current `nana-address-registry-v6` repo.
6
+
7
+ ## Current v6 surface
8
+
9
+ - `JBAddressRegistry`
10
+ - `IJBAddressRegistry`
11
+
12
+ ## Summary
13
+
14
+ - Nonce handling is safer than in v5. The registry now guards against oversized nonces instead of silently producing the wrong derived address once the old encoding assumptions stopped holding.
15
+ - Zero-address deployers are explicitly rejected.
16
+ - The external surface remains intentionally small. This repo changed behavior more than shape.
17
+ - The repo moved from the v5 Solidity baseline to `0.8.28`.
18
+
19
+ ## Verified deltas
20
+
21
+ - `_addressFrom(...)` now supports RLP nonce encoding through `uint64` instead of stopping at the old `uint32` path.
22
+ - `JBAddressRegistry_NonceTooLarge(uint256)` is thrown above that supported range.
23
+ - `JBAddressRegistry_ZeroDeployer()` is thrown when trying to register against `address(0)`.
24
+ - Duplicate registration now explicitly reverts with `JBAddressRegistry_AlreadyRegistered(address)`.
25
+
26
+ ## Breaking ABI changes
27
+
28
+ - There is no meaningful function-selector migration here.
29
+ - The practical ABI-visible change is new custom errors that callers and tooling may need to decode.
30
+
31
+ ## Indexer impact
32
+
33
+ - Event shape is effectively unchanged.
34
+ - The real migration concern is stricter revert behavior for previously tolerated bad inputs.
35
+
36
+ ## Migration notes
37
+
38
+ - If you treated this repo as ABI-stable, that is mostly still true, but behavior around bad inputs is stricter.
39
+ - Recheck any tool that depended on silent high-nonce behavior. v6 makes that path explicit instead of permissive.
package/README.md CHANGED
@@ -1,99 +1,111 @@
1
1
  # Juicebox Address Registry
2
2
 
3
- Knowing who deployed a contract is the first step toward trusting it. This registry lets anyone prove a contract's deployer on-chain -- no access control and no admin keys.
3
+ `@bananapus/address-registry-v6` is a permissionless registry that records deployer provenance for contracts when callers provide matching `create` or `create2` deployment inputs. It is meant to make deployer provenance visible on-chain, especially for hooks and helper contracts that users may need to trust before interacting with them.
4
4
 
5
- `JBAddressRegistry` maps contract addresses to their deployers using deterministic address computation. Provide the deployer address and deployment parameters, and the registry verifies the relationship and stores it permanently. Frontend clients can then look up any registered contract to see who deployed it, which is especially useful for vetting Juicebox pay and cash-out hooks before interacting with them.
5
+ Architecture: [ARCHITECTURE.md](./ARCHITECTURE.md)
6
+ User journeys: [USER_JOURNEYS.md](./USER_JOURNEYS.md)
7
+ Skills: [SKILLS.md](./SKILLS.md)
8
+ Risks: [RISKS.md](./RISKS.md)
9
+ Administration: [ADMINISTRATION.md](./ADMINISTRATION.md)
10
+ Audit instructions: [AUDIT_INSTRUCTIONS.md](./AUDIT_INSTRUCTIONS.md)
6
11
 
7
- ## Deployed Address
12
+ ## Overview
8
13
 
9
- `JBAddressRegistry` is deployed at the same address on all supported networks via deterministic `create2` deployment:
14
+ The registry supports both `create` and `create2` style deployments:
10
15
 
11
- ```
12
- 0x2d9b78cb37ca724cfb9b32cd8e9a5dc1c88bc7bb
13
- ```
16
+ - for `create`, it reconstructs the deployed address from the deployer and nonce
17
+ - for `create2`, it reconstructs the deployed address from the deployer, salt, and deployment bytecode
14
18
 
15
- | Network | Chain ID |
16
- |---------|----------|
17
- | Ethereum | 1 |
18
- | Optimism | 10 |
19
- | Arbitrum | 42161 |
20
- | Base | 8453 |
21
- | Ethereum Sepolia | 11155111 |
22
- | Optimism Sepolia | 11155420 |
23
- | Arbitrum Sepolia | 421614 |
24
- | Base Sepolia | 84532 |
19
+ Because the address is computed deterministically, registrations do not require access control. Anyone can submit the correct deployment inputs, and the registry records the deployer for the computed address after confirming code already exists there.
25
20
 
26
- ## Architecture
21
+ Use this repo when deployer provenance matters. Do not confuse it with an allowlist, audit registry, or trust oracle.
27
22
 
28
- | Contract | Description |
29
- |----------|-------------|
30
- | `JBAddressRegistry` | Standalone registry. Computes deployed addresses deterministically from deployer parameters and stores the deployer in `deployerOf`. No constructor arguments, no access control, no external dependencies. |
23
+ If the question is "is this hook safe?" this repo can only tell you who deployed it, not whether the code is good.
31
24
 
32
- ### Interface
25
+ ## Key Contract
33
26
 
34
- | Type | Description |
35
- |------|-------------|
36
- | `IJBAddressRegistry` | Interface exposing `deployerOf`, both `registerAddress` overloads, and the `AddressRegistered` event. |
27
+ | Contract | Role |
28
+ | --- | --- |
29
+ | `JBAddressRegistry` | Standalone registry that stores `deployerOf[address]` and exposes overloaded `registerAddress` entrypoints. |
37
30
 
38
- ### How It Works
31
+ ## Mental Model
39
32
 
40
- Anyone can register a contract by providing its deployer and deployment parameters:
33
+ The registry is intentionally narrow:
41
34
 
42
- - **`create` deployments**: Provide the deployer address and the nonce at the time of deployment. The registry reconstructs the address using RLP encoding (the same encoding the EVM uses internally to compute `create` addresses).
43
- - **`create2` deployments**: Provide the deployer address, the `create2` salt, and the full deployment bytecode (creation code + encoded constructor arguments). The registry computes `keccak256(0xff ++ deployer ++ salt ++ keccak256(bytecode))`.
35
+ 1. reconstruct an address from deployment inputs
36
+ 2. bind that address to a deployer once
37
+ 3. expose the result for other systems and clients
44
38
 
45
- In both cases, the registry stores the mapping `deployerOf[computedAddress] = deployer` and emits an `AddressRegistered` event. Frontend clients can then look up any contract's deployer to verify trust.
39
+ Anything beyond that is out of scope by design.
46
40
 
47
- No access control is needed -- only the correct deployer + parameters can produce a given address, so registrations cannot be faked.
41
+ ## Read These Files First
48
42
 
49
- ```solidity
50
- // Register a contract deployed via create.
51
- registry.registerAddress(deployer, nonce);
43
+ 1. `src/JBAddressRegistry.sol`
44
+ 2. `test/JBAddressRegistry.t.sol`
45
+ 3. `test/JBAddressRegistryEdge.t.sol`
46
+ 4. `test/audit/CodexFrontRunRegistrationDoS.t.sol`
52
47
 
53
- // Register a contract deployed via create2.
54
- registry.registerAddress(deployer, salt, bytecode);
48
+ ## Integration Traps
55
49
 
56
- // Look up who deployed a contract.
57
- address deployer = registry.deployerOf(contractAddress);
58
- ```
50
+ - provenance is only meaningful if callers also know what the deployer is supposed to be trusted for
51
+ - permissionless registration is intentional, so integrations should verify the computed inputs rather than assuming caller authority
52
+ - `create` nonce reconstruction and `create2` salt-bytecode reconstruction are different trust paths and should be reasoned about separately
53
+
54
+ ## Where State Lives
59
55
 
60
- ### Events
56
+ - deployer provenance lives in `JBAddressRegistry`
57
+ - deployment truth still lives outside this repo in the target chain history and bytecode inputs
61
58
 
62
- | Event | Fields | Emitted When |
63
- |-------|--------|-------------|
64
- | `AddressRegistered` | `address indexed addr`, `address indexed deployer`, `address caller` | A contract address is registered via either `registerAddress` overload. `caller` is `msg.sender`, which may differ from the deployer. |
59
+ ## High-Signal Tests
65
60
 
66
- ### Risks
61
+ 1. `test/JBAddressRegistry.t.sol`
62
+ 2. `test/JBAddressRegistryEdge.t.sol`
63
+ 3. `test/audit/CodexUnauthorizedRegistrar.t.sol`
67
64
 
68
- Hooks have token minting access, making malicious hooks dangerous. A registered deployer does not guarantee a hook is safe -- it only tells you who deployed it. Clients should warn project owners and users about any potential for unintended or adversarial behavior, especially for unknown hooks.
65
+ ## Install
66
+
67
+ ```bash
68
+ npm install @bananapus/address-registry-v6
69
+ ```
69
70
 
70
- Deployers can be exploited or act maliciously. Clients should still communicate risk to users even when the deployer is a known entity.
71
+ ## Development
71
72
 
72
- ### Limitations
73
+ ```bash
74
+ npm install
75
+ forge build
76
+ forge test
77
+ ```
73
78
 
74
- - The `_addressFrom` function for `create` addresses uses RLP encoding that only supports nonces up to `uint64` max (18,446,744,073,709,551,615). Higher nonces revert with `JBAddressRegistry_NonceTooLarge`. In practice, this limit is unreachable.
75
- - Re-registration is prevented: registering the same computed address again reverts with `JBAddressRegistry_AlreadyRegistered`. Only the first registration is accepted.
76
- - Registration is permissionless -- anyone can call `registerAddress`, not just the deployer. Security relies entirely on deterministic address computation.
79
+ Useful scripts:
77
80
 
78
- ## Deployment
81
+ - `npm run test:fork`
82
+ - `npm run deploy:mainnets`
83
+ - `npm run deploy:testnets`
79
84
 
80
- The deploy script uses [Sphinx](https://github.com/sphinx-labs/sphinx) for deterministic multi-chain deployment. The registry is deployed via `create2` with the salt `_JBAddressRegistryV6_`, ensuring the same address on every chain. The script skips deployment if the bytecode is already present at the computed address.
85
+ ## Deployment Notes
81
86
 
82
- A helper library `AddressRegistryDeploymentLib` is provided in `script/helpers/` to resolve deployed addresses from Sphinx deployment artifacts at runtime.
87
+ The deploy script uses Sphinx for deterministic deployment. This package is intentionally small and independent because many other repos use it to record clone factories and helper deployments.
83
88
 
84
- ## Install
89
+ ## Repository Layout
85
90
 
86
- ```bash
87
- npm install
91
+ ```text
92
+ src/
93
+ JBAddressRegistry.sol
94
+ interfaces/
95
+ test/
96
+ unit, edge, fork, audit, and regression coverage
97
+ script/
98
+ Deploy.s.sol
99
+ helpers/
88
100
  ```
89
101
 
90
- ## Develop
102
+ ## Risks And Notes
103
+
104
+ - provenance is not the same thing as safety; a known deployer can still deploy unsafe code
105
+ - registrations are first-write only, so bad operational processes around initial registration can be sticky
106
+ - the `create` address path relies on nonce reconstruction and intentionally rejects unrealistic nonce ranges
107
+
108
+ ## For AI Agents
91
109
 
92
- | Command | Description |
93
- |---------|-------------|
94
- | `forge build` | Compile contracts |
95
- | `forge test` | Run unit tests |
96
- | `FOUNDRY_PROFILE=CI forge test` | Run fork tests (requires `RPC_ETHEREUM_MAINNET` env var) |
97
- | `forge coverage --match-path "./src/*.sol" --report lcov --report summary` | Generate coverage report |
98
- | `npm run deploy:mainnets` | Propose mainnet deployment via Sphinx |
99
- | `npm run deploy:testnets` | Propose testnet deployment via Sphinx |
110
+ - Describe this repo as a provenance registry, not as an allowlist or safety oracle.
111
+ - Read the edge and audit tests before making claims about frontrunning or unauthorized registration.