@bananapus/core-v6 0.0.29 → 0.0.31

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.
Files changed (44) hide show
  1. package/ADMINISTRATION.md +43 -13
  2. package/ARCHITECTURE.md +62 -137
  3. package/AUDIT_INSTRUCTIONS.md +149 -428
  4. package/CHANGELOG.md +73 -0
  5. package/README.md +90 -201
  6. package/RISKS.md +27 -12
  7. package/SKILLS.md +31 -441
  8. package/STYLE_GUIDE.md +52 -19
  9. package/USER_JOURNEYS.md +76 -627
  10. package/package.json +2 -3
  11. package/references/entrypoints.md +160 -0
  12. package/references/types-errors-events.md +297 -0
  13. package/script/Deploy.s.sol +7 -2
  14. package/script/DeployPeriphery.s.sol +51 -4
  15. package/src/JBController.sol +11 -3
  16. package/src/JBDirectory.sol +1 -0
  17. package/src/JBMultiTerminal.sol +126 -72
  18. package/src/JBRulesets.sol +2 -1
  19. package/src/JBTerminalStore.sol +22 -11
  20. package/src/abstract/JBControlled.sol +7 -1
  21. package/src/abstract/JBPermissioned.sol +1 -1
  22. package/src/interfaces/IJBRulesetDataHook.sol +5 -4
  23. package/src/libraries/JBCashOuts.sol +1 -1
  24. package/src/libraries/JBConstants.sol +1 -1
  25. package/src/libraries/JBCurrencyIds.sol +1 -1
  26. package/src/libraries/JBFees.sol +1 -1
  27. package/src/libraries/JBFixedPointNumber.sol +1 -1
  28. package/src/libraries/JBMetadataResolver.sol +1 -1
  29. package/src/libraries/JBPayoutSplitGroupLib.sol +3 -1
  30. package/src/libraries/JBRulesetMetadataResolver.sol +1 -1
  31. package/src/libraries/JBSplitGroupIds.sol +1 -1
  32. package/src/libraries/JBSurplus.sol +1 -1
  33. package/src/structs/JBSplit.sol +4 -1
  34. package/test/TestForwardedTokenConsumption.sol +418 -0
  35. package/test/audit/CycledSurplusAllowanceReset.t.sol +184 -0
  36. package/test/units/static/JBController/TestPreviewMintOf.sol +5 -3
  37. package/test/units/static/JBMultiTerminal/TestCashOutTokensOf.sol +15 -11
  38. package/test/units/static/JBMultiTerminal/TestExecutePayout.sol +6 -0
  39. package/test/units/static/JBMultiTerminal/TestExecuteProcessFee.sol +3 -0
  40. package/test/units/static/JBMultiTerminal/TestMigrateBalanceOf.sol +3 -0
  41. package/test/units/static/JBMultiTerminal/TestPay.sol +7 -15
  42. package/test/units/static/JBMultiTerminal/TestSendPayoutsOf.sol +1 -1
  43. package/test/units/static/JBMultiTerminal/TestUseAllowanceOf.sol +1 -1
  44. package/CHANGE_LOG.md +0 -479
package/CHANGE_LOG.md DELETED
@@ -1,479 +0,0 @@
1
- # nana-core-v6 Changelog (v5 -> v6)
2
-
3
- This document describes all changes between `nana-core` (v5, Solidity 0.8.23) and `nana-core-v6` (v6, Solidity 0.8.28).
4
-
5
- ## Summary
6
-
7
- - **Preview APIs**: New `previewPayFor` and `previewCashOutFrom` view functions on terminal and store for simulating payments/cashouts without state changes.
8
- - **Fee-free cashout bypass closed**: Intra-terminal payouts now tracked via `_feeFreeSurplusOf` to prevent round-trip fee evasion through zero-tax cashouts.
9
- - **Approval hook hardening**: Reverting approval hooks now return `Failed` status instead of propagating, preventing permanent project freezing.
10
- - **Weight cache overhaul**: Cache threshold raised from 1,000 to 20,000 iterations; exceeding the threshold now reverts instead of silently iterating.
11
- - **Token metadata now mutable**: New `setTokenMetadataOf` allows changing a project token's name and symbol post-deployment.
12
-
13
- ---
14
-
15
- ## 0. Post-Release Changes
16
-
17
- ### 0.1 JBSplits -- Self-Auth GroupId Restriction
18
-
19
- `setSplitGroupsOf` self-auth now requires the upper 96 bits of the `groupId` to be non-zero. The full self-auth check is: `uint160(groupId) == msg.sender && groupId >> 160 != 0`. GroupIds with zero upper 96 bits (bare addresses like `uint256(uint160(tokenAddress))`) are protocol-reserved for terminal payout groups and always require controller authorization. This prevents accepted token contracts from writing a project's payout splits without controller auth. The 721 hook is unaffected since it already uses `hookAddress | tierId << 160` (non-zero upper bits).
20
-
21
- ### 0.2 JBMultiTerminal -- Fee-Free Cashout Bypass Prevention
22
-
23
- A new `_feeFreeSurplusOf` mapping (`projectId => token => uint256`) tracks cumulative fee-free intra-terminal payouts received by each project. When a split payout lands on the same terminal (intra-terminal routing, i.e. `terminal == this`), the net payout amount is added to `_feeFreeSurplusOf[projectId][token]`. After any outflow (payouts via `sendPayoutsOf`, surplus allowance via `useAllowanceOf`, non-zero-tax or feeless cashouts), the counter is capped at the remaining balance — non-fee-free funds are considered to leave first, preserving the fee-free counter as long as possible. During a cashout with `cashOutTaxRate == 0`, fees are charged on the reclaim amount up to the tracked fee-free surplus (and the tracker is decremented accordingly). Cashouts beyond the fee-free surplus remain fee-free. The counter is cleared on terminal migration. This closes a round-trip fee bypass where funds could be routed fee-free into a project via an intra-terminal split payout and then cashed out fee-free via a zero-tax cashout.
24
-
25
- ### 0.3 JBBeforeCashOutRecordedContext -- beneficiaryIsFeeless Field
26
-
27
- A `bool beneficiaryIsFeeless` field was added to the `JBBeforeCashOutRecordedContext` struct (before the `metadata` field). `recordCashOutFor` in `IJBTerminalStore` gained a corresponding `bool beneficiaryIsFeeless` parameter. The terminal passes the result of its feeless address check, allowing data hooks to skip their own fees when the beneficiary is already feeless (e.g., project-to-project routing via the router terminal). This is a **breaking change** to both the struct layout and the `recordCashOutFor` function signature.
28
-
29
- ### 0.4 JBTerminalStore -- Preview Functions
30
-
31
- Two `view` functions on `JBTerminalStore` and `IJBTerminalStore`:
32
-
33
- - `previewPayFrom(address terminal, address payer, JBTokenAmount amount, uint256 projectId, address beneficiary, bytes metadata)` -- Simulates a payment and returns `(JBRuleset ruleset, uint256 tokenCount, JBPayHookSpecification[] hookSpecifications)`. Uses the explicit `terminal` parameter for balance/surplus lookups. Invokes data hooks if configured. Does not modify state.
34
- - `previewCashOutFrom(address terminal, address holder, uint256 projectId, uint256 cashOutCount, address tokenToReclaim, bool beneficiaryIsFeeless, bytes metadata)` -- Simulates a cash out and returns `(JBRuleset ruleset, uint256 reclaimAmount, uint256 cashOutTaxRate, JBCashOutHookSpecification[] hookSpecifications)`. Uses the explicit `terminal` parameter for balance/surplus lookups. Invokes data hooks if configured. Does not modify state.
35
-
36
- Internal computation logic was extracted into shared `_computePayFrom` and `_computeCashOutFrom` view helpers; the existing `recordPaymentFrom` and `recordCashOutFor` functions were refactored to call these helpers before writing state.
37
-
38
- ### 0.5 Terminal-Level Preview APIs
39
-
40
- New `view` functions on `JBMultiTerminal`, `JBController`, and their interfaces provide user-facing preview entry points that compose the store-level previews with the mint token split:
41
-
42
- - `JBMultiTerminal.previewPayFor(uint256 projectId, address token, uint256 amount, address beneficiary, bytes metadata)` -- Simulates a full payment including the reserved/beneficiary token split. Calls `STORE.previewPayFrom` then `controller.previewMintOf`. Returns `(JBRuleset ruleset, uint256 beneficiaryTokenCount, uint256 reservedTokenCount, JBPayHookSpecification[] hookSpecifications)`.
43
- - `JBMultiTerminal.previewCashOutFrom(address holder, uint256 projectId, uint256 cashOutCount, address tokenToReclaim, address beneficiary, bytes metadata)` -- Simulates a full cash out. Resolves accounting context internally and delegates to `STORE.previewCashOutFrom`. Returns `(JBRuleset ruleset, uint256 reclaimAmount, uint256 cashOutTaxRate, JBCashOutHookSpecification[] hookSpecifications)`.
44
- - `JBController.previewMintOf(uint256 projectId, uint256 tokenCount, bool useReservedPercent)` -- Previews how a mint splits between beneficiary and reserved tokens under the current ruleset. Returns `(uint256 beneficiaryTokenCount, uint256 reservedTokenCount)`.
45
-
46
- Also in this release:
47
- - **Error consolidation**: Three separate `UnderMin*` errors on `JBMultiTerminal` consolidated into a single `JBMultiTerminal_UnderMin()` error for bytecode size reduction.
48
- - **`via_ir = true`**: Added to `foundry.toml` to enable the Solidity IR optimizer pipeline, reducing deployed bytecode size (EIP-170 compliance).
49
- - Internal helpers extracted: `_accountingContextOf` and `_tokenAmountOf` on `JBMultiTerminal`, `_splitTokenCount` on `JBController`.
50
-
51
- ### 0.6 JBMultiTerminal -- Migration Fee
52
-
53
- `migrateBalanceOf` now charges the standard 2.5% protocol fee when migrating to a non-feeless terminal, consistent with all other fund egress. This also settles any `_feeFreeSurplusOf` liability that would otherwise be lost on the new terminal. The fee is deducted from the migrated balance before transfer. Feeless terminals are exempt.
54
-
55
- ### 0.8 JBDirectory -- ADD_TERMINALS Permission on Implicit Addition
56
-
57
- `setPrimaryTerminalOf` now requires the `ADD_TERMINALS` permission when the specified terminal is not already in the project's terminal list. Previously, `setPrimaryTerminalOf` would implicitly add the terminal to the project's terminal list without any permission check beyond `SET_PRIMARY_TERMINAL`. Now, if `isTerminalOf(projectId, terminal)` returns false, the caller (or the account they're acting on behalf of) must also hold the `ADD_TERMINALS` permission for the project. Terminals already in the list are unaffected.
58
-
59
- ### 0.9 JBController -- Split Hook Try-Catch
60
-
61
- `_sendReservedTokensToSplitsOf` now wraps the `split.hook.processSplitWith(...)` call in a try-catch. If a split hook reverts, the tokens already transferred to the hook remain with the hook (they were transferred via `safeTransfer` before the `processSplitWith` call), and the controller emits a `SplitHookReverted(projectId, hook, reason)` event instead of propagating the revert. This prevents a single reverting split hook from blocking the entire reserved token distribution. A new event `SplitHookReverted` was added to `IJBController`.
62
-
63
- ### 0.10 JBChainlinkV3SequencerPriceFeed -- Sequencer Down Check
64
-
65
- The sequencer status check changed from `answer == 1` to `answer != 0`. The Chainlink sequencer uptime feed returns `0` for "up" and `1` for "down", but may return other non-zero values in future feed versions. The new check treats any non-zero answer as sequencer-down, which is the safer default.
66
-
67
- ### 0.11 JBMultiTerminal -- forceApprove
68
-
69
- `_beforeSendFor` now uses `forceApprove` (from OpenZeppelin's `SafeERC20`) instead of `safeIncreaseAllowance` when setting token allowances for outbound ERC-20 transfers. `safeIncreaseAllowance` could fail if a previous allowance was partially consumed and a non-standard token (e.g., USDT) requires the allowance to be zero before setting a new value. `forceApprove` resets the allowance to zero first if needed, then sets it to the desired amount.
70
-
71
- ### 0.12 JBChainlinkV3PriceFeed -- answeredInRound Check
72
-
73
- `currentUnitPrice` now checks `answeredInRound < roundId` after retrieving `latestRoundData()`. If `answeredInRound` is less than `roundId`, the answer was carried over from a previous round and the current round is incomplete. This reverts with `JBChainlinkV3PriceFeed_IncompleteRound()`, complementing the existing `updatedAt == 0` check to catch additional incomplete round scenarios.
74
-
75
- ### 0.7 JBMultiTerminal -- Self-Pay Revert
76
-
77
- `_pay` now reverts with `JBMultiTerminal_MintNotAllowed()` when `payer == address(this)`. This prevents same-project intra-terminal payout splits (where `preferAddToBalance == false`) from minting tokens against existing balance without new funds entering the system. The try-catch in `JBPayoutSplitGroupLib` catches this revert and restores the balance via `recordAddedBalanceFor`. Projects that want to mint should do so explicitly via the controller.
78
-
79
- ---
80
-
81
- ## 1. Breaking Changes
82
-
83
- ### 1.1 Interface Signature Changes
84
-
85
- #### IJBRulesets
86
-
87
- | Change | v5 | v6 |
88
- |--------|----|----|
89
- | `updateRulesetWeightCache` signature | `updateRulesetWeightCache(uint256 projectId)` | `updateRulesetWeightCache(uint256 projectId, uint256 rulesetId)` |
90
-
91
- A `rulesetId` parameter was added. Callers must now specify which ruleset to cache the weight for. This should be the ruleset that `currentOf()` actually uses (which may differ from `latestRulesetIdOf` if the latest was rejected by an approval hook).
92
-
93
- #### IJBTerminalStore
94
-
95
- | Change | v5 | v6 |
96
- |--------|----|----|
97
- | `currentReclaimableSurplusOf` parameter rename | `uint256 tokenCount` (4-param overload) | `uint256 cashOutCount` |
98
- | `recordCashOutFor` new parameter | No `beneficiaryIsFeeless` parameter | `bool beneficiaryIsFeeless` added after `balanceAccountingContexts` |
99
-
100
- The parameter was renamed from `tokenCount` to `cashOutCount` in the simple 4-parameter overload.
101
-
102
- `recordCashOutFor` gained a `bool beneficiaryIsFeeless` parameter so the terminal can pass through its feeless address check to data hooks via the `JBBeforeCashOutRecordedContext` struct.
103
-
104
- #### IJBPayoutTerminal
105
-
106
- | Change | v5 | v6 |
107
- |--------|----|----|
108
- | `sendPayoutsOf` return value | `returns (uint256 netLeftoverPayoutAmount)` | `returns (uint256 amountPaidOut)` |
109
-
110
- The return variable name was corrected from `netLeftoverPayoutAmount` to `amountPaidOut` to match the actual implementation semantics (total amount paid out). The v5 implementation already returned the total amount from `STORE.recordPayoutFor()`, not the leftover — only the interface had the misleading name.
111
-
112
- #### IJBController
113
-
114
- | Change | v5 | v6 |
115
- |--------|----|----|
116
- | `launchProjectFor` terminal configs | `JBTerminalConfig[] memory terminalConfigurations` | `JBTerminalConfig[] calldata terminalConfigurations` |
117
- | `launchRulesetsFor` terminal configs | `JBTerminalConfig[] memory terminalConfigurations` | `JBTerminalConfig[] calldata terminalConfigurations` |
118
-
119
- Parameters changed from `memory` to `calldata` for gas efficiency.
120
- > **Cross-repo impact**: The `calldata` change affects `nana-omnichain-deployers-v6` and `revnet-core-v6`, which call `launchProjectFor`/`launchRulesetsFor`.
121
-
122
- #### IJBSplits
123
-
124
- | Change | v5 | v6 |
125
- |--------|----|----|
126
- | `setSplitGroupsOf` splits param | `JBSplitGroup[] memory splitGroups` | `JBSplitGroup[] calldata splitGroups` |
127
-
128
- #### IJBFundAccessLimits
129
-
130
- | Change | v5 | v6 |
131
- |--------|----|----|
132
- | `setFundAccessLimitsFor` param | `JBFundAccessLimitGroup[] memory fundAccessLimitGroups` | `JBFundAccessLimitGroup[] calldata fundAccessLimitGroups` |
133
-
134
- ### 1.2 Removed Errors
135
-
136
- | Contract | v5 Error | v6 Replacement |
137
- |----------|----------|----------------|
138
- | `JBMultiTerminal` | `JBMultiTerminal_ZeroAccountingContextDecimals()` | `JBMultiTerminal_AccountingContextDecimalsMismatch()` |
139
-
140
- ---
141
-
142
- ## 2. New Features
143
-
144
- ### 2.1 New Functions
145
-
146
- #### IJBController / JBController
147
-
148
- | Function | Description |
149
- |----------|-------------|
150
- | `setTokenMetadataOf(uint256 projectId, string name, string symbol)` | Sets the name and symbol of a project's ERC-20 token. Requires the `SET_TOKEN_METADATA` permission. |
151
- | `afterReceiveMigrationFrom(IERC165 from, uint256 projectId)` | Called by the directory after this controller has been set as the active controller. Added to the `IJBMigratable` interface. |
152
-
153
- #### IJBTerminalStore / JBTerminalStore
154
-
155
- | Function | Description |
156
- |----------|-------------|
157
- | `currentTotalReclaimableSurplusOf(uint256 projectId, uint256 cashOutCount, uint256 decimals, uint256 currency)` | Convenience view that returns the reclaimable surplus across all terminals using all tokens. Delegates to `currentReclaimableSurplusOf` with empty `terminals` and `tokens` arrays. Mirrors the `currentTotalSurplusOf` pattern. |
158
-
159
- #### IJBTokens / JBTokens
160
-
161
- | Function | Description |
162
- |----------|-------------|
163
- | `setTokenMetadataFor(uint256 projectId, string name, string symbol)` | Sets the name and symbol of a project's token. Only callable by the project's controller. |
164
-
165
- #### IJBToken / JBERC20
166
-
167
- | Function | Description |
168
- |----------|-------------|
169
- | `setMetadata(string name, string symbol)` | Sets the token's name and symbol. Only callable by the token's owner (JBTokens). |
170
-
171
- #### IJBMigratable
172
-
173
- | Function | Description |
174
- |----------|-------------|
175
- | `afterReceiveMigrationFrom(IERC165 from, uint256 projectId)` | New lifecycle hook called after a controller migration completes. |
176
-
177
- #### JBCashOuts (Library)
178
-
179
- | Function | Description |
180
- |----------|-------------|
181
- | `minCashOutCountFor(uint256 surplus, uint256 desiredOutput, uint256 totalSupply, uint256 cashOutTaxRate)` | Inverse bonding curve: returns the minimum number of tokens to cash out to receive at least `desiredOutput`. Uses binary search for the general case. |
182
-
183
- ### 2.2 New Events
184
-
185
- | Contract | Event |
186
- |----------|-------|
187
- | `IJBTokens` | `SetTokenMetadata(uint256 indexed projectId, string name, string symbol, address caller)` |
188
- | `IJBPermitTerminal` | `Permit2AllowanceFailed(address indexed token, address indexed owner, bytes reason)` |
189
- | `IJBController` | `SplitHookReverted(uint256 indexed projectId, address hook, bytes reason)` |
190
-
191
- ### 2.3 New Errors
192
-
193
- | Contract | Error |
194
- |----------|-------|
195
- | `JBController` | `JBController_TerminalTokensNotTransferred()` |
196
- | `JBMultiTerminal` | `JBMultiTerminal_AccountingContextDecimalsMismatch()` |
197
- | `JBRulesets` | `JBRulesets_WeightCacheRequired(uint256 projectId)` |
198
- | `JBTerminalStore` | `JBTerminalStore_Uint224Overflow(uint256 value)` |
199
- | `JBCashOuts` | `JBCashOuts_DesiredOutputNotAchievable()` |
200
- | `JBERC20` | `JBERC20_AlreadyInitialized()` |
201
-
202
- ### 2.4 New Permission IDs
203
-
204
- | Permission | Description |
205
- |------------|-------------|
206
- | `LAUNCH_RULESETS` | Required for `launchRulesetsFor`. In v5, `QUEUE_RULESETS` was used. |
207
- | `SET_TOKEN_METADATA` | Required for `setTokenMetadataOf`. |
208
- > **Cross-repo impact**: `nana-permission-ids-v6` defines these new IDs. `nana-omnichain-deployers-v6` and `revnet-core-v6` use `LAUNCH_RULESETS` for their deployment flows.
209
-
210
- ---
211
-
212
- ## 3. Event Changes
213
-
214
- ### 3.0 Indexer Notes
215
-
216
- For subgraph migrations, this repo is the protocol-level anchor:
217
- - when an event signature gains parameters, prefer widening the existing entity schema instead of treating it as an unrelated event stream;
218
- - preview/noop behavior in core-v6 means some routing diagnostics now come from returned hook specs rather than only from emitted callback events;
219
- - if your v5 graph correlated protocol actions to hook callbacks only, re-check those assumptions against v6 preview/noop patterns.
220
-
221
- ### 3.1 New Events
222
-
223
- See section 2.2 above.
224
-
225
- ### 3.2 Modified Events
226
-
227
- | Contract | Event | Change |
228
- |----------|-------|--------|
229
- | `IJBCashOutTerminal` | `CashOutTokens` | Event order changed in the interface (moved before `HookAfterRecordCashOut`); NatSpec added. No field changes. |
230
- | `IJBCashOutTerminal` | `HookAfterRecordCashOut` | Event order changed in the interface (moved after `CashOutTokens`); NatSpec added. No field changes. |
231
-
232
- ### 3.3 All Interfaces Gained NatSpec
233
-
234
- Every interface file in v6 has comprehensive NatSpec documentation added to all functions, events, errors, and return values. This is a documentation-only change that does not affect the ABI.
235
-
236
- ---
237
-
238
- ## 4. Error Changes
239
-
240
- ### 4.1 Errors with Added Parameters (More Informative Reverts)
241
-
242
- | Contract | v5 | v6 |
243
- |----------|----|----|
244
- | `JBController` | `JBController_AddingPriceFeedNotAllowed()` | `JBController_AddingPriceFeedNotAllowed(uint256 projectId)` |
245
- | `JBController` | `JBController_MintNotAllowedAndNotTerminalOrHook()` | `JBController_MintNotAllowedAndNotTerminalOrHook(address caller)` |
246
- | `JBController` | `JBController_RulesetsAlreadyLaunched()` | `JBController_RulesetsAlreadyLaunched(uint256 projectId)` |
247
- | `JBController` | `JBController_RulesetSetTokenNotAllowed()` | `JBController_RulesetSetTokenNotAllowed(uint256 projectId)` |
248
- | `JBMultiTerminal` | `JBMultiTerminal_FeeTerminalNotFound()` | `JBMultiTerminal_FeeTerminalNotFound(address token)` |
249
- | `JBMultiTerminal` | `JBMultiTerminal_TerminalTokensIncompatible()` | `JBMultiTerminal_TerminalTokensIncompatible(uint256 projectId, address token, IJBTerminal terminal)` |
250
- | `JBDirectory` | `JBDirectory_SetControllerNotAllowed()` | `JBDirectory_SetControllerNotAllowed(uint256 projectId)` |
251
- | `JBDirectory` | `JBDirectory_SetTerminalsNotAllowed()` | `JBDirectory_SetTerminalsNotAllowed(uint256 projectId)` |
252
- | `JBSplits` | `JBSplits_PreviousLockedSplitsNotIncluded()` | `JBSplits_PreviousLockedSplitsNotIncluded(uint256 projectId, uint256 rulesetId)` |
253
- | `JBTokens` | `JBTokens_EmptyToken()` | `JBTokens_EmptyToken(uint256 projectId)` |
254
- | `JBTerminalStore` | `JBTerminalStore_RulesetNotFound()` | `JBTerminalStore_RulesetNotFound(uint256 projectId)` |
255
- | `JBPermissions` | `JBPermissions_Unauthorized()` | `JBPermissions_Unauthorized(address account, address operator, uint256 projectId, uint256 permissionId)` |
256
-
257
- ### 4.2 Renamed Errors
258
-
259
- | Contract | v5 | v6 |
260
- |----------|----|----|
261
- | `JBMultiTerminal` | `JBMultiTerminal_ZeroAccountingContextDecimals()` | `JBMultiTerminal_AccountingContextDecimalsMismatch()` |
262
-
263
- ### 4.3 Removed Errors
264
-
265
- | Contract | Error | Notes |
266
- |----------|-------|-------|
267
- | `JBMultiTerminal` | `JBMultiTerminal_ZeroAccountingContextDecimals()` | Replaced by `AccountingContextDecimalsMismatch` |
268
-
269
- ### 4.4 New Errors
270
-
271
- See section 2.3 above.
272
-
273
- ---
274
-
275
- ## 5. Struct Changes
276
-
277
- All structs are identical between v5 and v6 except:
278
-
279
- | Struct | Change |
280
- |--------|--------|
281
- | `JBBeforeCashOutRecordedContext` | New `bool beneficiaryIsFeeless` field added before `metadata`. Indicates whether the cash out's beneficiary is a feeless address, allowing data hooks to skip their own fees for in-protocol routing. |
282
-
283
- Other struct-level differences (non-functional):
284
- - `forge-lint: disable-next-line(pascal-case-struct)` comments added to all struct definitions.
285
- - `JBSplit`: Additional NatSpec documentation on the `beneficiary` field behavior when set to `address(0)`.
286
-
287
- ---
288
-
289
- ## 6. Enum Changes
290
-
291
- `JBApprovalStatus` is **identical** between v5 and v6.
292
-
293
- ---
294
-
295
- ## 7. Library Changes
296
-
297
- ### JBCashOuts
298
-
299
- | Change | Description |
300
- |--------|-------------|
301
- | **New function** `minCashOutCountFor` | Inverse bonding curve calculation using binary search. Returns the minimum tokens to cash out for a desired output. |
302
- | **New error** `JBCashOuts_DesiredOutputNotAchievable` | Thrown when the cash out tax rate is 100% and no output is possible. |
303
- | **Bug fix**: Early return for zero `cashOutCount` | `cashOutFrom` now returns `0` immediately when `cashOutCount == 0` (v5 would compute with zero). |
304
-
305
- ### JBMetadataResolver
306
-
307
- | Change | Description |
308
- |--------|-------------|
309
- | Assembly blocks marked `"memory-safe"` | All inline assembly blocks now use the `assembly ("memory-safe")` annotation. |
310
- | **Bug fix**: `_sliceBytes` copy loop | The loop bound changed from `end` (absolute source offset) to `length` (relative), preventing over-copy past the allocated buffer. |
311
- | **Bug fix**: Overflow protection | Offset increment now checks for `> 255` overflow before casting to `uint8`, reverting with `JBMetadataResolver_MetadataTooLong()`. |
312
- | **Bug fix**: Memory alignment | Free memory pointer in `_sliceBytes` now rounds up to 32-byte boundary to prevent overlapping allocations. |
313
- | Empty input handling | `createMetadata` now returns empty bytes for empty input arrays. |
314
- | Named parameters in `_sliceBytes` calls | All calls now use named parameters (`data:`, `start:`, `end:`). |
315
-
316
- ### JBRulesetMetadataResolver
317
-
318
- | Change | Description |
319
- |--------|-------------|
320
- | Bit 77 comment fix | Changed from "allow controller migration" to "owner must send payouts" to match actual bit semantics. |
321
- | `baseCurrency` range comment fix | Changed from `0-16777215` (24-bit) to `0-4294967295` (32-bit). |
322
- | `currency` range comment fix | Changed from `0-4294967296` to `0-4294967295`. |
323
- | Named field syntax | `expandMetadata()` now uses named field syntax (`reservedPercent:`, etc.) instead of positional. |
324
-
325
- ### JBFees
326
-
327
- | Change | Description |
328
- |--------|-------------|
329
- | NatSpec improvements | Clarified that `feeAmountFrom` forward-calculates and `feeAmountIn` back-calculates. Added documentation about rounding bounds. |
330
-
331
- ### JBSurplus
332
-
333
- | Change | Description |
334
- |--------|-------------|
335
- | Typo fix | `termainls` -> `terminals`. |
336
-
337
- ### JBConstants, JBFixedPointNumber, JBSplitGroupIds, JBCurrencyIds
338
-
339
- No changes.
340
-
341
- ---
342
-
343
- ## 8. Implementation Changes (Non-Interface)
344
-
345
- ### 8.1 JBController
346
-
347
- | Change | Description |
348
- |--------|-------------|
349
- | **Migration lifecycle** | `afterReceiveMigrationFrom` added — called by directory after migration completes (validates caller is directory). |
350
- | **`launchRulesetsFor` permission** | Changed from `QUEUE_RULESETS` to `LAUNCH_RULESETS`. |
351
- | **Split token transfer assertion** | `assert(allowance == 0)` replaced with explicit `revert JBController_TerminalTokensNotTransferred()`. |
352
- | **Split hook try-catch** | `processSplitWith` in `_sendReservedTokensToSplitsOf` is now wrapped in a try-catch. A reverting split hook emits `SplitHookReverted` instead of propagating. Transferred tokens stay with the hook. |
353
- | **Code organization** | External views moved after external transactions. Internal views moved to end of file. |
354
-
355
- ### 8.2 JBMultiTerminal
356
-
357
- | Change | Description |
358
- |--------|-------------|
359
- | **Decimal validation** | `ZeroAccountingContextDecimals` renamed to `AccountingContextDecimalsMismatch`. Non-standard ERC-20s that revert on `decimals()` bypass validation (documented). |
360
- | **Permit2 failure event** | Failed Permit2 allowance approvals now emit `Permit2AllowanceFailed` instead of silently catching. |
361
- | **Migration held fees** | Migration intentionally does not transfer held fees (documented: held fees belong to fee beneficiary, not the migrating project). |
362
- | **Held fee processing (reentrancy hardening)** | `processHeldFeesOf` now re-reads the storage index each iteration (instead of caching), deletes the entry before the external call, and updates the index before the external call. |
363
- | **Split payout documentation** | Failed split payouts documented as consuming payout limit by design. |
364
- | **Fee-free cashout bypass prevention** | New `_feeFreeSurplusOf` mapping tracks cumulative fee-free intra-terminal payouts per project/token. Capped at remaining balance after outflows including non-zero-tax/feeless cashouts (non-fee-free funds leave first). During zero-tax cashouts, fees are charged up to this tracked amount (then decremented). Cleared on migration. See Section 0.2. |
365
- | **beneficiaryIsFeeless passthrough** | `cashOutTokensOf` now passes `_isFeeless(beneficiary)` to `recordCashOutFor`, which forwards it to data hooks via `JBBeforeCashOutRecordedContext.beneficiaryIsFeeless`. |
366
- | **forceApprove** | `_beforeSendFor` now uses `forceApprove` instead of `safeIncreaseAllowance` for outbound ERC-20 token approvals, avoiding reverts on tokens (e.g. USDT) that require zero allowance before re-approval. |
367
-
368
- ### 8.3 JBRulesets
369
-
370
- | Change | Description |
371
- |--------|-------------|
372
- | **Cache threshold** | `_WEIGHT_CUT_MULTIPLE_CACHE_LOOKUP_THRESHOLD` increased from `1,000` to `20,000`. |
373
- | **Cache cap removed** | `_MAX_WEIGHT_CUT_MULTIPLE_CACHE_THRESHOLD` (`50,000`) removed entirely. |
374
- | **Weight cache required** | `_deriveWeightFrom` now reverts with `JBRulesets_WeightCacheRequired(projectId)` when iteration count exceeds the threshold, instead of silently iterating. |
375
- | **Approval hook try/catch** | `_approvalStatusOf` now wraps the external `approvalHook.approvalStatusOf()` call in a try/catch. A reverting approval hook returns `JBApprovalStatus.Failed` instead of propagating the revert. This prevents a malicious or buggy approval hook from permanently freezing a project. |
376
-
377
- ### 8.4 JBDirectory
378
-
379
- | Change | Description |
380
- |--------|-------------|
381
- | **Migration ordering** | `setControllerOf` now calls `migrate()` on the old controller BEFORE updating `controllerOf` in storage (so `migrate()` runs while the directory still points to the old controller). After updating storage, it calls `afterReceiveMigrationFrom` on the new controller. |
382
- | **ADD_TERMINALS permission on implicit addition** | `setPrimaryTerminalOf` now requires the `ADD_TERMINALS` permission when the terminal is not already in the project's terminal list. Previously, implicit addition had no permission check beyond `SET_PRIMARY_TERMINAL`. |
383
-
384
- ### 8.5 JBSplits
385
-
386
- | Change | Description |
387
- |--------|-------------|
388
- | **Stale storage cleanup** | `_setSplitsOf` now deletes stale packed split data when the new split count is smaller than the previous count, preventing leftover storage from prior configurations. |
389
-
390
- ### 8.6 JBTokens
391
-
392
- | Change | Description |
393
- |--------|-------------|
394
- | **Overflow check timing** | `mintFor` now checks `totalSupplyOf(projectId) + count > type(uint208).max` BEFORE minting (v5 checked after). |
395
-
396
- ### 8.7 JBERC20
397
-
398
- | Change | Description |
399
- |--------|-------------|
400
- | **Named revert** | `initialize()` now reverts with `JBERC20_AlreadyInitialized()` instead of a bare `revert()`. |
401
-
402
- ### 8.8 JBChainlinkV3PriceFeed
403
-
404
- | Change | Description |
405
- |--------|-------------|
406
- | **Incomplete round check order** | The check for `updatedAt == 0` (incomplete round) now runs BEFORE the stale price check, avoiding false stale errors on incomplete rounds. |
407
- | **answeredInRound check** | `currentUnitPrice` now checks `answeredInRound < roundId` and reverts with `IncompleteRound` if the answer was carried over from a previous round. |
408
-
409
- ### 8.9 JBChainlinkV3SequencerPriceFeed
410
-
411
- | Change | Description |
412
- |--------|-------------|
413
- | **Typo fix** | Error parameter `gradePeriodTime` corrected to `gracePeriodTime` in `JBChainlinkV3SequencerPriceFeed_SequencerDown`. |
414
- | **Threshold docs** | Constructor parameter `threshold` documentation corrected from "blocks" to "seconds". |
415
- | **Sequencer down check** | Changed `answer == 1` to `answer != 0` in the sequencer uptime check. Any non-zero answer is now treated as sequencer-down, which is the safer default for future Chainlink feed versions. |
416
-
417
- ### 8.10 Solidity Version
418
-
419
- All contracts upgraded from `pragma solidity 0.8.23` to `pragma solidity 0.8.28`.
420
-
421
- ### 8.11 Named Arguments
422
-
423
- Throughout the codebase, function calls were updated to use named argument syntax (e.g., `foo({bar: 1, baz: 2})`) for improved readability.
424
-
425
- ---
426
-
427
- ## 9. Migration Table
428
-
429
- ### Interfaces
430
-
431
- | v5 | v6 | Notes |
432
- |----|----|-------|
433
- | `IJBController` | `IJBController` | Gained `setTokenMetadataOf`. `calldata` for terminal configs. |
434
- | `IJBRulesets` | `IJBRulesets` | `updateRulesetWeightCache` gained `rulesetId` parameter |
435
- | `IJBTerminalStore` | `IJBTerminalStore` | `tokenCount` renamed to `cashOutCount` in `currentReclaimableSurplusOf`. `recordCashOutFor` gained `beneficiaryIsFeeless` param. New `currentTotalReclaimableSurplusOf` convenience view. View functions reordered. |
436
- | `IJBPayoutTerminal` | `IJBPayoutTerminal` | `sendPayoutsOf` returns `amountPaidOut` (was `netLeftoverPayoutAmount`). `SendPayoutToSplit` event moved. |
437
- | `IJBPermitTerminal` | `IJBPermitTerminal` | Gained `Permit2AllowanceFailed` event |
438
- | `IJBMigratable` | `IJBMigratable` | Gained `afterReceiveMigrationFrom` function |
439
- | `IJBTokens` | `IJBTokens` | Gained `setTokenMetadataFor`, `SetTokenMetadata` event |
440
- | `IJBToken` | `IJBToken` | Gained `setMetadata` function |
441
- | `IJBSplits` | `IJBSplits` | `setSplitGroupsOf` param changed to `calldata` |
442
- | `IJBFundAccessLimits` | `IJBFundAccessLimits` | `setFundAccessLimitsFor` param changed to `calldata` |
443
- | `IJBFeelessAddresses` | `IJBFeelessAddresses` | Param names: `account` -> `addr`. NatSpec added. |
444
- | All other interfaces | Same name | NatSpec documentation added. No functional changes. |
445
-
446
- ### Contracts
447
-
448
- | v5 | v6 | Notes |
449
- |----|----|-------|
450
- | `JBController` | `JBController` | Token metadata, migration lifecycle (`afterReceiveMigrationFrom`), `LAUNCH_RULESETS` permission |
451
- | `JBMultiTerminal` | `JBMultiTerminal` | Reentrancy hardening, decimal validation rename, Permit2 event, fee-free bypass prevention (`_feeFreeSurplusOf`), `beneficiaryIsFeeless` passthrough |
452
- | `JBRulesets` | `JBRulesets` | Approval hook try/catch, weight cache changes, threshold increase |
453
- | `JBDirectory` | `JBDirectory` | Migration ordering fix, afterReceiveMigration call |
454
- | `JBTokens` | `JBTokens` | Token metadata support, overflow check timing |
455
- | `JBERC20` | `JBERC20` | `setMetadata`, named revert |
456
- | `JBDeadline` | `JBDeadline` | No functional changes |
457
- | All others | Same name | Error parameter enrichment, named arguments, NatSpec |
458
-
459
- ### Libraries
460
-
461
- | v5 | v6 | Notes |
462
- |----|----|-------|
463
- | `JBCashOuts` | `JBCashOuts` | Added `minCashOutCountFor` (inverse bonding curve) |
464
- | `JBMetadataResolver` | `JBMetadataResolver` | Memory safety, overflow protection, copy loop fix |
465
- | `JBRulesetMetadataResolver` | `JBRulesetMetadataResolver` | Comment fixes, named field syntax |
466
- | `JBCurrencyIds` | `JBCurrencyIds` | No changes |
467
- | All others | Same name | No changes |
468
-
469
- ### Structs
470
-
471
- | v5 | v6 | Notes |
472
- |----|----|-------|
473
- | All 22 structs | Same names | All identical except `JBBeforeCashOutRecordedContext` (gained `beneficiaryIsFeeless` field). Lint comments added to all. |
474
-
475
- ### Enums
476
-
477
- | v5 | v6 | Notes |
478
- |----|----|-------|
479
- | `JBApprovalStatus` | `JBApprovalStatus` | Identical |