@bananapus/ownable-v6 0.0.17 → 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/ADMINISTRATION.md +55 -71
- package/ARCHITECTURE.md +75 -48
- package/AUDIT_INSTRUCTIONS.md +46 -165
- package/CHANGELOG.md +39 -0
- package/README.md +72 -92
- package/RISKS.md +42 -18
- package/SKILLS.md +28 -172
- package/STYLE_GUIDE.md +58 -20
- package/USER_JOURNEYS.md +81 -162
- package/foundry.toml +2 -0
- package/package.json +3 -3
- package/references/operations.md +14 -0
- package/references/runtime.md +19 -0
- package/src/JBOwnableOverrides.sol +4 -0
- package/src/structs/JBOwner.sol +0 -1
- package/test/CodexUnmintedProjectHijack.t.sol +45 -0
- package/CHANGE_LOG.md +0 -235
package/CHANGE_LOG.md
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
# nana-ownable-v6 Changelog (v5 → v6)
|
|
2
|
-
|
|
3
|
-
This document describes all changes between `nana-ownable` (v5) and `nana-ownable-v6` (v6).
|
|
4
|
-
|
|
5
|
-
## Summary
|
|
6
|
-
|
|
7
|
-
- **Defensive `try-catch` on all `PROJECTS.ownerOf()` calls**: `owner()` now returns `address(0)` instead of reverting for burned/invalid project NFTs — changes observable behavior for callers.
|
|
8
|
-
- **New safety validations**: `transferOwnershipToProject()` checks project existence; constructor rejects zero-address `PROJECTS` with project-based ownership.
|
|
9
|
-
- **Solidity version pinned**: Changed from floating `^0.8.23` to exact `^0.8.26`.
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## 1. Breaking Changes
|
|
14
|
-
|
|
15
|
-
### Solidity Version Pinned
|
|
16
|
-
|
|
17
|
-
All contracts changed from `pragma solidity ^0.8.23` (floating) to `pragma solidity ^0.8.26` (pinned). This means v6 can only compile with Solidity ^0.8.26 exactly.
|
|
18
|
-
|
|
19
|
-
**Affected files:** `JBOwnable.sol`, `JBOwnableOverrides.sol`
|
|
20
|
-
|
|
21
|
-
### Import Paths Updated
|
|
22
|
-
|
|
23
|
-
All imports reference `@bananapus/core-v6` instead of `@bananapus/core-v5`. Any project depending on `nana-ownable` must also migrate to `nana-core-v6`.
|
|
24
|
-
|
|
25
|
-
### `owner()` Returns `address(0)` Instead of Reverting for Invalid Projects
|
|
26
|
-
|
|
27
|
-
In v5, if a project NFT was burned or otherwise invalid, `owner()` would revert because `PROJECTS.ownerOf()` reverts for nonexistent tokens.
|
|
28
|
-
|
|
29
|
-
In v6, `owner()` wraps the call in `try-catch` and returns `address(0)` if `ownerOf()` reverts. This changes the observable behavior: callers that previously relied on a revert to detect invalid project ownership will now receive `address(0)` instead.
|
|
30
|
-
|
|
31
|
-
### `_checkOwner()` Behavior Change for Invalid Projects
|
|
32
|
-
|
|
33
|
-
In v5, `_checkOwner()` would revert with the ERC-721 "nonexistent token" error if the owning project NFT was burned.
|
|
34
|
-
|
|
35
|
-
In v6, it resolves the owner to `address(0)` via `try-catch` and then passes `address(0)` to `_requirePermissionFrom`. This still causes a revert (no one can authenticate as `address(0)`), but the revert reason changes from an ERC-721 error to a permissions error.
|
|
36
|
-
|
|
37
|
-
### `transferOwnershipToProject()` Now Validates Project Existence
|
|
38
|
-
|
|
39
|
-
In v6, `transferOwnershipToProject()` checks `projectId > PROJECTS.count()` and reverts with `JBOwnableOverrides_ProjectDoesNotExist()` if the project has not been created yet. In v5, no such check existed, so ownership could be transferred to a nonexistent project ID.
|
|
40
|
-
|
|
41
|
-
### Constructor Validates `PROJECTS` Address for Project-Based Ownership
|
|
42
|
-
|
|
43
|
-
In v6, the constructor reverts with `JBOwnableOverrides_ZeroAddressProjectsWithProjectOwner()` if `initialProjectIdOwner != 0` and `address(projects) == address(0)`. In v5, this combination was silently accepted, which would permanently break ownership resolution since `ownerOf()` calls on `address(0)` would always revert.
|
|
44
|
-
|
|
45
|
-
### `IJBOwnable` Return Name Changes
|
|
46
|
-
|
|
47
|
-
The second return value of `jbOwner()` was renamed from `projectOwner` (v5) to `projectId` (v6) in the interface. The type (`uint88`) and position are unchanged, so the ABI is identical, but code referencing the named return will need updating.
|
|
48
|
-
|
|
49
|
-
Additionally, `PROJECTS()` and `owner()` gained named return values in the interface:
|
|
50
|
-
|
|
51
|
-
- `PROJECTS()`: `returns (IJBProjects)` (v5) -> `returns (IJBProjects projects)` (v6)
|
|
52
|
-
- `owner()`: `returns (address)` (v5) -> `returns (address owner)` (v6)
|
|
53
|
-
|
|
54
|
-
These are ABI-compatible but change the Solidity-level interface signature.
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## 2. New Features
|
|
59
|
-
|
|
60
|
-
### Defensive `try-catch` on All `PROJECTS.ownerOf()` Calls
|
|
61
|
-
|
|
62
|
-
Every call to `PROJECTS.ownerOf()` in v6 is wrapped in a `try-catch` block. If the call reverts (e.g., burned NFT, broken ERC-721 implementation), the resolved owner falls back to `address(0)`. This applies to:
|
|
63
|
-
|
|
64
|
-
- `owner()` -- returns `address(0)` instead of reverting.
|
|
65
|
-
- `_checkOwner()` -- resolves to `address(0)`, causing a permissions revert.
|
|
66
|
-
- `_transferOwnership(address, uint88)` -- resolves old owner to `address(0)` for the transfer event.
|
|
67
|
-
|
|
68
|
-
### Project Existence Validation on `transferOwnershipToProject()`
|
|
69
|
-
|
|
70
|
-
`transferOwnershipToProject()` now calls `PROJECTS.count()` to verify the target project exists before transferring ownership, preventing accidental loss of contract control by transferring to a nonexistent project.
|
|
71
|
-
|
|
72
|
-
### Constructor Guard Against Zero-Address `PROJECTS` with Project Ownership
|
|
73
|
-
|
|
74
|
-
A new constructor check prevents deploying with `projects == address(0)` when `initialProjectIdOwner != 0`, which would make ownership irrecoverable.
|
|
75
|
-
|
|
76
|
-
### Comprehensive NatSpec Documentation on `IJBOwnable`
|
|
77
|
-
|
|
78
|
-
The v6 interface adds full NatSpec documentation for all events, functions, parameters, and return values. The v5 interface had no NatSpec comments at all.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## 3. Event Changes
|
|
83
|
-
|
|
84
|
-
No event signatures changed. Both versions define the same two events with identical parameters and indexing:
|
|
85
|
-
|
|
86
|
-
- `OwnershipTransferred(address indexed previousOwner, address indexed newOwner, address caller)`
|
|
87
|
-
- `PermissionIdChanged(uint8 newId, address caller)`
|
|
88
|
-
|
|
89
|
-
The only difference is the addition of NatSpec documentation on both events in v6's `IJBOwnable.sol`, and the declaration order was swapped (v5: `PermissionIdChanged` first, then `OwnershipTransferred`; v6: `OwnershipTransferred` first, then `PermissionIdChanged`).
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## 4. Error Changes
|
|
94
|
-
|
|
95
|
-
### New Errors
|
|
96
|
-
|
|
97
|
-
| Error | Contract | Description |
|
|
98
|
-
|---|---|---|
|
|
99
|
-
| `JBOwnableOverrides_ProjectDoesNotExist()` | `JBOwnableOverrides` | Reverts in `transferOwnershipToProject()` if `projectId > PROJECTS.count()`. |
|
|
100
|
-
| `JBOwnableOverrides_ZeroAddressProjectsWithProjectOwner()` | `JBOwnableOverrides` | Reverts in constructor if `initialProjectIdOwner != 0` and `address(projects) == address(0)`. |
|
|
101
|
-
|
|
102
|
-
### Unchanged Errors
|
|
103
|
-
|
|
104
|
-
| Error | Status |
|
|
105
|
-
|---|---|
|
|
106
|
-
| `JBOwnableOverrides_InvalidNewOwner()` | Unchanged -- still used for zero-address owner, zero project ID, and dual-set owner+project scenarios. |
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
## 5. Struct Changes
|
|
111
|
-
|
|
112
|
-
### `JBOwner` (unchanged)
|
|
113
|
-
|
|
114
|
-
The struct itself is identical in both versions:
|
|
115
|
-
|
|
116
|
-
```solidity
|
|
117
|
-
struct JBOwner {
|
|
118
|
-
address owner;
|
|
119
|
-
uint88 projectId;
|
|
120
|
-
uint8 permissionId;
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
The only difference is the addition of a `// forge-lint: disable-next-line(pascal-case-struct)` comment in v6.
|
|
125
|
-
|
|
126
|
-
---
|
|
127
|
-
|
|
128
|
-
## 6. Implementation Changes (Non-Interface)
|
|
129
|
-
|
|
130
|
-
### `JBOwnableOverrides._checkOwner()` -- Refactored Owner Resolution
|
|
131
|
-
|
|
132
|
-
**v5:**
|
|
133
|
-
```solidity
|
|
134
|
-
function _checkOwner() internal view virtual {
|
|
135
|
-
JBOwner memory ownerInfo = jbOwner;
|
|
136
|
-
_requirePermissionFrom({
|
|
137
|
-
account: ownerInfo.projectId == 0 ? ownerInfo.owner : PROJECTS.ownerOf(ownerInfo.projectId),
|
|
138
|
-
projectId: ownerInfo.projectId,
|
|
139
|
-
permissionId: ownerInfo.permissionId
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
**v6:**
|
|
145
|
-
```solidity
|
|
146
|
-
function _checkOwner() internal view virtual {
|
|
147
|
-
JBOwner memory ownerInfo = jbOwner;
|
|
148
|
-
address resolvedOwner;
|
|
149
|
-
if (ownerInfo.projectId == 0) {
|
|
150
|
-
resolvedOwner = ownerInfo.owner;
|
|
151
|
-
} else {
|
|
152
|
-
try PROJECTS.ownerOf(ownerInfo.projectId) returns (address projectOwner) {
|
|
153
|
-
resolvedOwner = projectOwner;
|
|
154
|
-
} catch {
|
|
155
|
-
resolvedOwner = address(0);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
_requirePermissionFrom({
|
|
159
|
-
account: resolvedOwner, projectId: ownerInfo.projectId, permissionId: ownerInfo.permissionId
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
The ternary expression is replaced with an explicit `if/else` block and `try-catch` for defensive error handling.
|
|
165
|
-
|
|
166
|
-
### `JBOwnableOverrides.owner()` -- Try-Catch on Project Lookup
|
|
167
|
-
|
|
168
|
-
**v5:**
|
|
169
|
-
```solidity
|
|
170
|
-
return PROJECTS.ownerOf(ownerInfo.projectId);
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
**v6:**
|
|
174
|
-
```solidity
|
|
175
|
-
try PROJECTS.ownerOf(ownerInfo.projectId) returns (address projectOwner) {
|
|
176
|
-
return projectOwner;
|
|
177
|
-
} catch {
|
|
178
|
-
return address(0);
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### `JBOwnableOverrides._transferOwnership(address, uint88)` -- Try-Catch on Old Owner Lookup
|
|
183
|
-
|
|
184
|
-
**v5:**
|
|
185
|
-
```solidity
|
|
186
|
-
address oldOwner = ownerInfo.projectId == 0 ? ownerInfo.owner : PROJECTS.ownerOf(ownerInfo.projectId);
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
**v6:**
|
|
190
|
-
```solidity
|
|
191
|
-
address oldOwner;
|
|
192
|
-
if (ownerInfo.projectId == 0) {
|
|
193
|
-
oldOwner = ownerInfo.owner;
|
|
194
|
-
} else {
|
|
195
|
-
try PROJECTS.ownerOf(ownerInfo.projectId) returns (address projectOwner) {
|
|
196
|
-
oldOwner = projectOwner;
|
|
197
|
-
} catch {
|
|
198
|
-
oldOwner = address(0);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
### Named Arguments Used Throughout
|
|
204
|
-
|
|
205
|
-
All internal function calls in v6 use named arguments (e.g., `_transferOwnership({newOwner: initialOwner, projectId: initialProjectIdOwner})`) instead of positional arguments. This is a style-only change with no behavioral impact.
|
|
206
|
-
|
|
207
|
-
### NatSpec Improvements
|
|
208
|
-
|
|
209
|
-
- `JBOwnable._emitTransferEvent()`: Incomplete comment in v5 (`"some contracts will try to deploy contracts for a project before"`) is completed in v6 (`"some contracts need to deploy contracts for a project before the project's NFT has been minted, so the transfer event resolves the project's current owner at emission time."`). A new `@dev` comment also explains why this function intentionally does NOT use try-catch (unlike `_transferOwnership`): reverting on a nonexistent new project is desirable to prevent transferring ownership to an invalid project.
|
|
210
|
-
- `JBOwnableOverrides._emitTransferEvent()`: Added `@param` tags for `previousOwner`, `newOwner`, and `newProjectId`.
|
|
211
|
-
- `renounceOwnership()`, `setPermissionId()`: Changed `@notice This can only be called by the current owner.` to `@dev`.
|
|
212
|
-
- `transferOwnership()`, `transferOwnershipToProject()`: Added documentation about `permissionId` being reset to 0 on transfer.
|
|
213
|
-
- Constructor `@param initialOwner`: Fixed typo `intialProjectIdOwner` to `initialProjectIdOwner`.
|
|
214
|
-
|
|
215
|
-
### Comment/Formatting Fixes
|
|
216
|
-
|
|
217
|
-
- Fixed malformed section header comment in v5 (`custom errors --------------------------//b`) to properly formatted (`custom errors ------------------------- //`).
|
|
218
|
-
|
|
219
|
-
---
|
|
220
|
-
|
|
221
|
-
## 7. Migration Table
|
|
222
|
-
|
|
223
|
-
| v5 | v6 | Change Type |
|
|
224
|
-
|---|---|---|
|
|
225
|
-
| `pragma solidity ^0.8.23` | `pragma solidity ^0.8.26` | Pinned compiler version |
|
|
226
|
-
| `@bananapus/core-v5` imports | `@bananapus/core-v6` imports | Dependency upgrade |
|
|
227
|
-
| `PROJECTS.ownerOf()` called directly | `try PROJECTS.ownerOf() catch` in `owner()`, `_checkOwner()`, `_transferOwnership()` | Defensive error handling |
|
|
228
|
-
| `transferOwnershipToProject()` -- no existence check | Reverts with `JBOwnableOverrides_ProjectDoesNotExist()` if `projectId > PROJECTS.count()` | New validation |
|
|
229
|
-
| Constructor allows `projects == address(0)` with `initialProjectIdOwner != 0` | Reverts with `JBOwnableOverrides_ZeroAddressProjectsWithProjectOwner()` | New validation |
|
|
230
|
-
| `IJBOwnable.jbOwner()` returns `(address owner, uint88 projectOwner, uint8 permissionId)` | Returns `(address owner, uint88 projectId, uint8 permissionId)` | Return name change (ABI compatible) |
|
|
231
|
-
| `IJBOwnable.PROJECTS()` returns `(IJBProjects)`, `owner()` returns `(address)` | Returns `(IJBProjects projects)`, `(address owner)` | Named return values added (ABI compatible) |
|
|
232
|
-
| `IJBOwnable` -- no NatSpec | Full NatSpec on all events, functions, params, and returns | Documentation |
|
|
233
|
-
| Positional arguments in internal calls | Named arguments throughout | Style only |
|
|
234
|
-
| 1 custom error | 3 custom errors (`+ ProjectDoesNotExist`, `+ ZeroAddressProjectsWithProjectOwner`) | New errors |
|
|
235
|
-
| `JBOwner` struct | Identical (added forge-lint comment only) | No change |
|