@bananapus/ownable-v6 0.0.18 → 0.0.19
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/RISKS.md +34 -34
- package/package.json +1 -1
package/RISKS.md
CHANGED
|
@@ -1,51 +1,51 @@
|
|
|
1
1
|
# Juicebox Ownable Risk Register
|
|
2
2
|
|
|
3
|
-
This file
|
|
3
|
+
This file covers the ownership-model risks in `JBOwnable`: dynamic ownership through project NFTs, delegated owner authority, and mismatches with standard `Ownable` expectations.
|
|
4
4
|
|
|
5
|
-
## How
|
|
5
|
+
## How To Use This File
|
|
6
6
|
|
|
7
|
-
- Read `Priority risks` first
|
|
8
|
-
- Use the
|
|
9
|
-
- Treat `Invariants to
|
|
7
|
+
- Read `Priority risks` first. Most failures here come from authority-model mistakes, not arithmetic bugs.
|
|
8
|
+
- Use the later sections to understand what changes when ownership follows a project instead of a fixed address.
|
|
9
|
+
- Treat `Invariants to verify` as the minimum proof that owner resolution stays coherent.
|
|
10
10
|
|
|
11
|
-
## Priority
|
|
11
|
+
## Priority Risks
|
|
12
12
|
|
|
13
13
|
| Priority | Risk | Why it matters | Primary controls |
|
|
14
14
|
|----------|------|----------------|------------------|
|
|
15
|
-
| P1 | Misunderstanding dynamic owner resolution | Ownership can move when the project NFT moves or when permissions change,
|
|
16
|
-
| P1 | Over-broad delegated owner permissions | `JBPermissions` can broaden who effectively acts as owner
|
|
17
|
-
| P2 |
|
|
18
|
-
|
|
15
|
+
| P1 | Misunderstanding dynamic owner resolution | Ownership can move when the project NFT moves or when permissions change, which breaks static `Ownable` assumptions. | Clear docs, careful integration review, and explicit tests around transfer paths. |
|
|
16
|
+
| P1 | Over-broad delegated owner permissions | `JBPermissions` can broaden who effectively acts as owner. Bad configuration expands blast radius quickly. | Permission hygiene and explicit review of delegated grants. |
|
|
17
|
+
| P2 | Tooling assumptions about standard `Ownable` | Some tooling assumes `owner()` maps to one address with no external permission system behind it. | Integration testing and clear documentation of the semantic differences. |
|
|
19
18
|
|
|
20
19
|
## 1. Trust Assumptions
|
|
21
20
|
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
- **
|
|
25
|
-
- **Deployment inputs.** If `initialProjectIdOwner != 0`,
|
|
21
|
+
- **`JBPermissions` works correctly.** A bug there affects every `JBOwnable` contract that relies on delegated owner access.
|
|
22
|
+
- **`JBProjects` ownership is the source of truth.** When a contract is project-owned, whoever holds the project NFT has owner access.
|
|
23
|
+
- **Delegated permission means owner-equivalent access.** Anyone granted the configured `permissionId` through `JBPermissions` can satisfy owner checks for the scoped contract.
|
|
24
|
+
- **Deployment inputs are intentional.** If `initialProjectIdOwner != 0`, deployers must understand whether that project already exists.
|
|
26
25
|
|
|
27
26
|
## 2. Known Risks
|
|
28
27
|
|
|
29
|
-
- **Project NFT transfer
|
|
30
|
-
- **
|
|
31
|
-
- **`renounceOwnership`
|
|
32
|
-
- **Constructor pre-binding can intentionally lock the contract.** If a deployer
|
|
33
|
-
- **`PROJECTS == address(0)`
|
|
28
|
+
- **Project NFT transfer changes contract ownership.** Anyone who acquires the project NFT gains owner access to contracts using that project-owned mode.
|
|
29
|
+
- **Two ownership modes can confuse integrations.** Setting both `newOwner` and `projectId` is disallowed, but integrators still need to check which mode is active.
|
|
30
|
+
- **`renounceOwnership` is final.** Once called, `owner()` resolves to `address(0)` and owner-gated functions stop working permanently unless a downstream contract adds its own recovery path.
|
|
31
|
+
- **Constructor pre-binding can intentionally lock the contract.** If a deployer points ownership at a future project ID, `owner()` resolves to `address(0)` until that project exists.
|
|
32
|
+
- **`PROJECTS == address(0)` breaks project-owned mode.** The constructor defends against this, but wrappers should still treat it as a high-signal deployment surface.
|
|
33
|
+
- **Unminted project ID ownership.** Contracts using `JBOwnableOverrides` can be configured with an `initialProjectIdOwner` that references a project ID not yet minted. The first account to mint that sequential project ID will become the effective owner of the contract. Deployers must ensure the referenced project ID is already minted, or deploy the ownable contract and the project in the same transaction to prevent front-running.
|
|
34
34
|
|
|
35
35
|
## 3. Accepted Behaviors
|
|
36
36
|
|
|
37
|
-
- **Permission ID
|
|
38
|
-
- **`permissionId = 0` means direct-owner-only mode.**
|
|
39
|
-
- **
|
|
40
|
-
- **`transferOwnershipToProject` rejects non-existent projects.** The function checks
|
|
41
|
-
- **Constructor pre-binding to a future project ID
|
|
42
|
-
- **Transfer events can temporarily show `address(0)
|
|
43
|
-
|
|
44
|
-
## 4. Invariants
|
|
45
|
-
|
|
46
|
-
-
|
|
47
|
-
- `_checkOwner()` reverts for all callers when the owner resolves to `address(0)
|
|
48
|
-
- `permissionId`
|
|
49
|
-
-
|
|
50
|
-
- `transferOwnershipToProject(projectId)` reverts for all `projectId > PROJECTS.count()` at call time
|
|
51
|
-
- `initialProjectIdOwner != 0` with `PROJECTS == address(0)` always reverts during construction
|
|
37
|
+
- **Permission ID resets on transfer.** `permissionId` resets to `0` on ownership transfer so old delegated operators do not automatically retain power.
|
|
38
|
+
- **`permissionId = 0` means direct-owner-only mode.** This is a valid configuration, not an error state.
|
|
39
|
+
- **Invalid project ownership resolves fail-closed.** If `ownerOf` cannot resolve, the contract is effectively renounced until ownership becomes readable again.
|
|
40
|
+
- **`transferOwnershipToProject` rejects non-existent projects.** The function checks existence at transfer time.
|
|
41
|
+
- **Constructor pre-binding to a future project ID is supported.** This is useful in controlled deployment flows, but dangerous if the deployer does not control mint sequencing.
|
|
42
|
+
- **Transfer events can temporarily show `address(0)`.** When ownership points to an unminted future project, the transfer event shows `address(0)` until ownership can resolve dynamically.
|
|
43
|
+
|
|
44
|
+
## 4. Invariants To Verify
|
|
45
|
+
|
|
46
|
+
- ownership is always exactly one of: direct address or project NFT holder
|
|
47
|
+
- `_checkOwner()` reverts for all callers when the owner resolves to `address(0)`
|
|
48
|
+
- `permissionId` resets to `0` on every ownership transfer
|
|
49
|
+
- after `renounceOwnership()`, `jbOwner()` returns `(address(0), 0, 0)` and no address can pass `_checkOwner()`
|
|
50
|
+
- `transferOwnershipToProject(projectId)` reverts for all `projectId > PROJECTS.count()` at call time
|
|
51
|
+
- `initialProjectIdOwner != 0` with `PROJECTS == address(0)` always reverts during construction
|