@bananapus/core-v6 0.0.30 → 0.0.32
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 +43 -13
- package/ARCHITECTURE.md +62 -137
- package/AUDIT_INSTRUCTIONS.md +149 -428
- package/CHANGELOG.md +73 -0
- package/README.md +90 -201
- package/RISKS.md +27 -12
- package/SKILLS.md +31 -441
- package/STYLE_GUIDE.md +52 -19
- package/USER_JOURNEYS.md +76 -627
- package/package.json +1 -2
- package/references/entrypoints.md +160 -0
- package/references/types-errors-events.md +297 -0
- package/script/Deploy.s.sol +7 -2
- package/script/DeployPeriphery.s.sol +51 -4
- package/src/JBController.sol +45 -17
- package/src/JBDirectory.sol +26 -13
- package/src/JBFundAccessLimits.sol +28 -7
- package/src/JBMultiTerminal.sol +180 -86
- package/src/JBPermissions.sol +17 -17
- package/src/JBRulesets.sol +82 -23
- package/src/JBSplits.sol +31 -12
- package/src/JBTerminalStore.sol +137 -53
- package/src/JBTokens.sol +5 -2
- package/src/abstract/JBControlled.sol +10 -3
- package/src/abstract/JBPermissioned.sol +1 -1
- package/src/interfaces/IJBRulesetDataHook.sol +5 -4
- package/src/libraries/JBCashOuts.sol +1 -1
- package/src/libraries/JBConstants.sol +1 -1
- package/src/libraries/JBCurrencyIds.sol +1 -1
- package/src/libraries/JBFees.sol +1 -1
- package/src/libraries/JBFixedPointNumber.sol +1 -1
- package/src/libraries/JBMetadataResolver.sol +5 -2
- package/src/libraries/JBPayoutSplitGroupLib.sol +7 -2
- package/src/libraries/JBRulesetMetadataResolver.sol +1 -1
- package/src/libraries/JBSplitGroupIds.sol +1 -1
- package/src/libraries/JBSurplus.sol +5 -2
- package/src/structs/JBSplit.sol +4 -1
- package/test/TestForwardedTokenConsumption.sol +419 -0
- package/test/audit/CrossTerminalSurplusSpoof.t.sol +140 -0
- package/test/audit/CycledSurplusAllowanceReset.t.sol +184 -0
- package/test/units/static/JBController/TestPreviewMintOf.sol +5 -4
- package/test/units/static/JBMultiTerminal/TestCashOutTokensOf.sol +15 -12
- package/test/units/static/JBMultiTerminal/TestExecutePayout.sol +6 -0
- package/test/units/static/JBMultiTerminal/TestExecuteProcessFee.sol +3 -0
- package/test/units/static/JBMultiTerminal/TestMigrateBalanceOf.sol +3 -0
- package/test/units/static/JBMultiTerminal/TestPay.sol +7 -15
- package/test/units/static/JBMultiTerminal/TestSendPayoutsOf.sol +1 -1
- package/test/units/static/JBMultiTerminal/TestUseAllowanceOf.sol +1 -1
- package/CHANGE_LOG.md +0 -479
package/ADMINISTRATION.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
Admin privileges and their scope in nana-core-v6.
|
|
4
4
|
|
|
5
|
+
## At A Glance
|
|
6
|
+
|
|
7
|
+
| Item | Details |
|
|
8
|
+
|------|---------|
|
|
9
|
+
| Scope | Core Juicebox V6 protocol control plane: projects, permissions, directory, controller, terminals, tokens, prices, splits, and fund access limits. |
|
|
10
|
+
| Operators | Protocol-level contract owners, project owners, delegated operators, controllers, terminals, and ruleset-selected hooks. |
|
|
11
|
+
| Highest-risk actions | Adding immutable price feeds, changing controllers or terminals, deploying or setting a project's ERC-20, and granting broad operator or ROOT permissions. |
|
|
12
|
+
| Recovery posture | Bad immutable choices usually require deploying new infrastructure and migrating project configuration rather than "editing" the existing contracts. |
|
|
13
|
+
|
|
14
|
+
## Routine Operations
|
|
15
|
+
|
|
16
|
+
- Whitelist or remove first-controller setters on `JBDirectory` only when rolling out a new controller implementation.
|
|
17
|
+
- Add price feeds only after confirming the exact project scope and pair, because feeds cannot be replaced once written.
|
|
18
|
+
- Manage project operators through `JBPermissions` with the narrowest possible project scope and permission bitmap.
|
|
19
|
+
- Reconfigure controllers, terminals, splits, fund access limits, and rulesets only when the current ruleset flags permit the change.
|
|
20
|
+
- Use protocol-owner functions on `JBFeelessAddresses`, `JBProjects`, and `JBPrices` sparingly because they affect many projects at once.
|
|
21
|
+
|
|
22
|
+
## One-Way Or High-Risk Actions
|
|
23
|
+
|
|
24
|
+
- `JBPrices.addPriceFeedFor` is immutable for a given project/currency pair. A bad feed entry cannot be edited in place.
|
|
25
|
+
- `JBController.deployERC20For` and `JBTokens.setTokenFor` are effectively one-time token-binding decisions for a project.
|
|
26
|
+
- The fee beneficiary is hardcoded to project `1` inside `JBMultiTerminal`; changing that requires new terminal deployments.
|
|
27
|
+
- Over-broad ROOT or wildcard permissions can hand an operator more power than intended across a project's full control surface.
|
|
28
|
+
|
|
29
|
+
## Recovery Notes
|
|
30
|
+
|
|
31
|
+
- If an immutable contract reference or price feed is wrong, the normal recovery path is redeploying the affected contract layer and migrating projects to the new controller or terminal stack.
|
|
32
|
+
- If a project's controller or terminal setup is wrong but the ruleset still allows migration, recover with `JBDirectory` updates before deploying replacement infrastructure.
|
|
33
|
+
|
|
5
34
|
## Roles
|
|
6
35
|
|
|
7
36
|
### Project Owner
|
|
@@ -90,14 +119,14 @@ Admin privileges and their scope in nana-core-v6.
|
|
|
90
119
|
|----------|--------------|---------------|-------|-------------|
|
|
91
120
|
| `setControllerOf` | Project owner or operator, OR an `isAllowedToSetFirstController` address (for first controller only) | SET_CONTROLLER (14) | Per project | Sets or migrates a project's controller. Also requires the current ruleset's `allowSetController` flag to be true (unless setting the first controller). Triggers migration lifecycle hooks on both old and new controllers. |
|
|
92
121
|
| `setIsAllowedToSetFirstController` | Contract owner | N/A (onlyOwner) | Protocol-wide | Adds or removes an address from the allowlist of addresses that can set a project's first controller. |
|
|
93
|
-
| `setPrimaryTerminalOf` | Project owner or operator | SET_PRIMARY_TERMINAL (16) | Per project | Sets which terminal is the default for a given token. Adds the terminal to the project if not already present. |
|
|
122
|
+
| `setPrimaryTerminalOf` | Project owner or operator | SET_PRIMARY_TERMINAL (17), plus ADD_TERMINALS (16) if the terminal is not already configured | Per project | Sets which terminal is the default for a given token. Adds the terminal to the project if not already present. |
|
|
94
123
|
| `setTerminalsOf` | Project owner, operator, or the project's controller | SET_TERMINALS (15) | Per project | Replaces the entire list of terminals for a project. If the caller is not the controller, the ruleset must have `allowSetTerminals` enabled. |
|
|
95
124
|
|
|
96
125
|
### JBController
|
|
97
126
|
|
|
98
127
|
| Function | Required Role | Permission ID | Scope | What It Does |
|
|
99
128
|
|----------|--------------|---------------|-------|-------------|
|
|
100
|
-
| `addPriceFeedFor` | Project owner or operator | ADD_PRICE_FEED (
|
|
129
|
+
| `addPriceFeedFor` | Project owner or operator | ADD_PRICE_FEED (20) | Per project | Adds a price feed for a project. Requires the ruleset's `allowAddPriceFeed` flag. Price feeds are immutable once set. |
|
|
101
130
|
| `burnTokensOf` | Token holder, operator with BURN_TOKENS, or a project terminal | BURN_TOKENS (11) | Per project | Burns tokens or credits from a holder's balance. Terminals can burn without explicit permission (for cash outs). |
|
|
102
131
|
| `claimTokensFor` | Credit holder or operator | CLAIM_TOKENS (12) | Per project | Redeems internal credits for ERC-20 tokens. |
|
|
103
132
|
| `deployERC20For` | Project owner or operator | DEPLOY_ERC20 (8) | Per project | Deploys a new ERC-20 token contract for the project. Can only be called once per project. |
|
|
@@ -106,9 +135,9 @@ Admin privileges and their scope in nana-core-v6.
|
|
|
106
135
|
| `mintTokensOf` | Project owner, operator, terminal, or data hook (with mint permission) | MINT_TOKENS (10) | Per project | Mints new tokens. If the caller is not a terminal or data hook, the ruleset must have `allowOwnerMinting` enabled. |
|
|
107
136
|
| `queueRulesetsOf` | Project owner, operator, or OMNICHAIN_RULESET_OPERATOR | QUEUE_RULESETS (2) | Per project | Queues new rulesets at the end of the project's ruleset queue. |
|
|
108
137
|
| `sendReservedTokensToSplitsOf` | Anyone | N/A | Per project | Distributes accumulated reserved tokens to the project's reserved token split group. No permission required -- anyone can trigger this. |
|
|
109
|
-
| `setSplitGroupsOf` | Project owner or operator | SET_SPLIT_GROUPS (
|
|
138
|
+
| `setSplitGroupsOf` | Project owner or operator | SET_SPLIT_GROUPS (19) | Per project | Sets split groups for a project. Must preserve any currently locked splits. |
|
|
110
139
|
| `setTokenFor` | Project owner or operator | SET_TOKEN (9) | Per project | Assigns an external ERC-20 token to the project. Requires the ruleset's `allowSetCustomToken` flag. Can only be called once (before any token is set). |
|
|
111
|
-
| `setTokenMetadataOf` | Project owner or operator | SET_TOKEN_METADATA (
|
|
140
|
+
| `setTokenMetadataOf` | Project owner or operator | SET_TOKEN_METADATA (22) | Per project | Sets the name and symbol of a project's ERC-20 token. The project must have a token deployed. |
|
|
112
141
|
| `setUriOf` | Project owner or operator | SET_PROJECT_URI (7) | Per project | Updates the project's metadata URI. |
|
|
113
142
|
| `transferCreditsFrom` | Credit holder or operator | TRANSFER_CREDITS (13) | Per project | Transfers internal token credits between addresses. Requires the ruleset's `pauseCreditTransfers` flag to be false. |
|
|
114
143
|
| `migrate` | JBDirectory only | N/A (msg.sender == DIRECTORY) | Per project | Called by the directory during controller migration. Reverts if there are pending reserved tokens. |
|
|
@@ -121,11 +150,11 @@ Admin privileges and their scope in nana-core-v6.
|
|
|
121
150
|
|
|
122
151
|
| Function | Required Role | Permission ID | Scope | What It Does |
|
|
123
152
|
|----------|--------------|---------------|-------|-------------|
|
|
124
|
-
| `addAccountingContextsFor` | Project owner, operator, or the project's controller | ADD_ACCOUNTING_CONTEXTS (
|
|
153
|
+
| `addAccountingContextsFor` | Project owner, operator, or the project's controller | ADD_ACCOUNTING_CONTEXTS (21) | Per project | Adds tokens that the terminal will accept for a project. Requires the ruleset's `allowAddAccountingContext` flag (if a ruleset exists). |
|
|
125
154
|
| `cashOutTokensOf` | Token holder or operator | CASH_OUT_TOKENS (4) | Per project | Cashes out project tokens for a share of the project's surplus. Fees are charged unless the beneficiary is feeless or the cash out tax rate is zero. |
|
|
126
155
|
| `migrateBalanceOf` | Project owner or operator | MIGRATE_TERMINAL (6) | Per project | Migrates a project's balance from this terminal to another. The destination terminal must accept the same token. The ruleset must have `allowTerminalMigration` enabled (checked in JBTerminalStore). The standard 2.5% protocol fee is charged when migrating to a non-feeless terminal. |
|
|
127
156
|
| `sendPayoutsOf` | Anyone (unless `ownerMustSendPayouts` is set) | SEND_PAYOUTS (5) if `ownerMustSendPayouts` | Per project | Sends payouts to the project's payout split group up to the payout limit. Anyone can call unless the ruleset has `ownerMustSendPayouts` enabled, which requires the project owner or an operator with SEND_PAYOUTS permission. |
|
|
128
|
-
| `useAllowanceOf` | Project owner or operator | USE_ALLOWANCE (
|
|
157
|
+
| `useAllowanceOf` | Project owner or operator | USE_ALLOWANCE (18) | Per project | Withdraws funds from the project's surplus up to the surplus allowance. Fees are charged unless the owner or beneficiary is feeless. |
|
|
129
158
|
| `pay` | Anyone | N/A | N/A | Pays a project with tokens. No permission required. |
|
|
130
159
|
| `addToBalanceOf` | Anyone | N/A | N/A | Adds funds to a project's balance without minting tokens. Can optionally return held fees. No permission required. |
|
|
131
160
|
| `processHeldFeesOf` | Anyone | N/A | Per project | Processes held fees that have passed their 28-day unlock period. No permission required. |
|
|
@@ -242,12 +271,13 @@ JBPermissions implements a 256-bit packed permission bitmap system:
|
|
|
242
271
|
| 13 | TRANSFER_CREDITS | `JBController.transferCreditsFrom` |
|
|
243
272
|
| 14 | SET_CONTROLLER | `JBDirectory.setControllerOf` |
|
|
244
273
|
| 15 | SET_TERMINALS | `JBDirectory.setTerminalsOf` |
|
|
245
|
-
| 16 |
|
|
246
|
-
| 17 |
|
|
247
|
-
| 18 |
|
|
248
|
-
| 19 |
|
|
249
|
-
| 20 |
|
|
250
|
-
| 21 |
|
|
274
|
+
| 16 | ADD_TERMINALS | `JBDirectory.setPrimaryTerminalOf` when it must add a new terminal first |
|
|
275
|
+
| 17 | SET_PRIMARY_TERMINAL | `JBDirectory.setPrimaryTerminalOf` |
|
|
276
|
+
| 18 | USE_ALLOWANCE | `JBMultiTerminal.useAllowanceOf` |
|
|
277
|
+
| 19 | SET_SPLIT_GROUPS | `JBController.setSplitGroupsOf` |
|
|
278
|
+
| 20 | ADD_PRICE_FEED | `JBController.addPriceFeedFor` |
|
|
279
|
+
| 21 | ADD_ACCOUNTING_CONTEXTS | `JBMultiTerminal.addAccountingContextsFor` |
|
|
280
|
+
| 22 | SET_TOKEN_METADATA | `JBController.setTokenMetadataOf` |
|
|
251
281
|
|
|
252
282
|
## Immutable Configuration
|
|
253
283
|
|
|
@@ -338,7 +368,7 @@ What admins CANNOT do:
|
|
|
338
368
|
- **No admin can change the fee beneficiary.** Project ID 1 is hardcoded as the fee recipient. This cannot be changed.
|
|
339
369
|
- **Price feeds cannot be replaced.** Once a price feed is set for a currency pair (in either direction), it is permanent for that project ID. Recovery requires deploying a new JBPrices contract.
|
|
340
370
|
- **Token assignments are one-way.** Once a project's ERC-20 token is set (via `deployERC20For` or `setTokenFor`), it cannot be changed to a different token.
|
|
341
|
-
- **Locked splits cannot be removed.** Splits with a `lockedUntil` timestamp in the future must be preserved (with the same or extended lock) when updating split
|
|
371
|
+
- **Locked splits cannot be removed from the same split table.** Splits with a `lockedUntil` timestamp in the future must be preserved (with the same or extended lock) when updating that split group. This does not automatically freeze successor rulesets; operators that queue new rulesets must consciously carry forward any still-locked economic promises they intend to preserve.
|
|
342
372
|
- **Operators cannot escalate to ROOT via ROOT.** A ROOT operator can set permissions for other operators on the same project but cannot grant ROOT to them or set permissions on the wildcard project ID.
|
|
343
373
|
- **The directory owner cannot set controllers directly.** The directory owner can only manage the `isAllowedToSetFirstController` allowlist. They cannot set or change a project's controller.
|
|
344
374
|
- **Ruleset approval hooks can block changes.** If a ruleset specifies an approval hook, queued rulesets must be approved by that hook before they take effect. A rejected ruleset falls back to the previous approved ruleset's cycling behavior.
|
package/ARCHITECTURE.md
CHANGED
|
@@ -1,159 +1,84 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Architecture
|
|
2
2
|
|
|
3
3
|
## Purpose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`nana-core-v6` is the protocol root. It owns project identity, permissions, rulesets, token supply, treasury balances, payout limits, fee logic, and the hook interfaces that every extension repo composes with.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
If a change affects accounting, supply, fee behavior, terminal routing, or permission semantics, this is the repo that defines the source of truth.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
src/
|
|
11
|
-
├── JBMultiTerminal.sol — Multi-token payment terminal (pay, cash out, payouts, fees)
|
|
12
|
-
├── JBController.sol — Orchestrator (project lifecycle, rulesets, token minting, reserved tokens)
|
|
13
|
-
├── JBTerminalStore.sol — Bookkeeping (balances, payout limits, surplus, bonding curve math)
|
|
14
|
-
├── JBRulesets.sol — Ruleset lifecycle (linked-list, weight decay, approval hooks)
|
|
15
|
-
├── JBDirectory.sol — Routes projects to terminals and controllers
|
|
16
|
-
├── JBTokens.sol — Dual token system (internal credits + ERC-20)
|
|
17
|
-
├── JBSplits.sol — Packed split storage with lock enforcement
|
|
18
|
-
├── JBFundAccessLimits.sol — Payout limits and surplus allowances
|
|
19
|
-
├── JBPrices.sol — Price feeds with project-specific + default fallback
|
|
20
|
-
├── JBPermissions.sol — 256-bit packed permission system
|
|
21
|
-
├── JBProjects.sol — ERC-721 project ownership
|
|
22
|
-
├── JBERC20.sol — Cloneable ERC20Votes+Permit token
|
|
23
|
-
├── JBFeelessAddresses.sol — Fee-exempt address registry
|
|
24
|
-
├── JBDeadline.sol — Approval hook requiring minimum delay
|
|
25
|
-
├── JBChainlinkV3PriceFeed.sol — Chainlink v3 price feed with staleness + answeredInRound check
|
|
26
|
-
├── JBChainlinkV3SequencerPriceFeed.sol — L2 sequencer-aware price feed (answer != 0 = down)
|
|
27
|
-
├── abstract/
|
|
28
|
-
│ ├── JBPermissioned.sol — Base for permission-checked contracts
|
|
29
|
-
│ └── JBControlled.sol — Base for controller-gated contracts
|
|
30
|
-
├── enums/
|
|
31
|
-
│ └── JBApprovalStatus.sol — Approval hook status enum
|
|
32
|
-
├── periphery/
|
|
33
|
-
│ ├── JBDeadline1Day.sol — 1-day approval hook
|
|
34
|
-
│ ├── JBDeadline3Days.sol — 3-day approval hook
|
|
35
|
-
│ ├── JBDeadline3Hours.sol — 3-hour approval hook
|
|
36
|
-
│ ├── JBDeadline7Days.sol — 7-day approval hook
|
|
37
|
-
│ └── JBMatchingPriceFeed.sol — 1:1 price feed
|
|
38
|
-
├── interfaces/ — 30 interface files (IJBController, IJBTerminal, etc.)
|
|
39
|
-
├── structs/ — 22 struct files (JBRuleset, JBSplit, etc.)
|
|
40
|
-
└── libraries/
|
|
41
|
-
├── JBCashOuts.sol — Bonding curve math
|
|
42
|
-
├── JBConstants.sol — Protocol constants
|
|
43
|
-
├── JBCurrencyIds.sol — Currency ID constants (ETH, USD)
|
|
44
|
-
├── JBFees.sol — Fee calculation (forward/backward)
|
|
45
|
-
├── JBFixedPointNumber.sol — Decimal adjustment
|
|
46
|
-
├── JBMetadataResolver.sol — Variable-length key-value metadata
|
|
47
|
-
├── JBPayoutSplitGroupLib.sol — Payout split group helpers
|
|
48
|
-
├── JBRulesetMetadataResolver.sol — Bit-packed metadata (256 bits)
|
|
49
|
-
├── JBSplitGroupIds.sol — Split group ID constants
|
|
50
|
-
└── JBSurplus.sol — Cross-terminal surplus calculation
|
|
51
|
-
```
|
|
9
|
+
## Boundaries
|
|
52
10
|
|
|
53
|
-
|
|
11
|
+
- The core owns balance and supply transitions.
|
|
12
|
+
- Extensions may adjust economics through hooks, but they should not invent competing ledgers.
|
|
13
|
+
- The core deliberately avoids app-specific behaviors like NFT composition, DEX routing strategy, or bridge-specific message transport.
|
|
54
14
|
|
|
55
|
-
|
|
15
|
+
## Main Components
|
|
56
16
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
-> Mint beneficiary tokens
|
|
67
|
-
-> Accumulate pendingReservedTokenBalanceOf
|
|
68
|
-
-> [Optional] Pay hooks execute
|
|
69
|
-
```
|
|
17
|
+
| Component | Responsibility |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `JBMultiTerminal` | Entry point for payments, cash outs, payouts, balance additions, and fee handling |
|
|
20
|
+
| `JBTerminalStore` | Bookkeeping and preview math for payment, payout, allowance, and cash-out paths |
|
|
21
|
+
| `JBController` | Project launch, ruleset queueing, token minting and burning, split-group updates |
|
|
22
|
+
| `JBDirectory` | Maps projects to controllers and terminals |
|
|
23
|
+
| `JBRulesets` | Time-ordered ruleset lifecycle and approval-hook integration |
|
|
24
|
+
| `JBTokens`, `JBERC20`, `JBProjects` | Token and project identity surfaces |
|
|
25
|
+
| `JBSplits`, `JBFundAccessLimits`, `JBPrices`, `JBPermissions` | Shared state for distribution, limits, price conversion, and authorization |
|
|
70
26
|
|
|
71
|
-
|
|
27
|
+
## Runtime Model
|
|
72
28
|
|
|
73
|
-
|
|
74
|
-
Holder -> JBMultiTerminal.cashOutTokensOf()
|
|
75
|
-
-> JBTerminalStore.recordCashOutFor()
|
|
76
|
-
-> Calculate surplus (all terminals, converted via JBPrices)
|
|
77
|
-
-> Get totalSupply (including pending reserved)
|
|
78
|
-
-> [Optional] Data hook overrides parameters
|
|
79
|
-
-> JBCashOuts.cashOutFrom() — bonding curve
|
|
80
|
-
-> Deduct balance
|
|
81
|
-
-> JBController.burnTokensOf()
|
|
82
|
-
-> Deduct fee from reclaim amount (if applicable), transfer remainder to beneficiary
|
|
83
|
-
-> [Optional] Cash out hooks execute
|
|
84
|
-
-> Send accumulated fees to project #1
|
|
85
|
-
Fees apply when cashOutTaxRate > 0 (on full reclaim)
|
|
86
|
-
OR when cashOutTaxRate == 0 and project has unconsumed _feeFreeSurplusOf (on that portion only)
|
|
87
|
-
_feeFreeSurplusOf lifecycle:
|
|
88
|
-
- Incremented on fee-free intra-terminal payouts
|
|
89
|
-
- Capped at remaining balance after any outflow (payouts, useAllowanceOf, non-zero-tax/feeless cashouts) — non-fee-free funds leave first
|
|
90
|
-
- Consumed (decremented by feeable amount) during zero-tax cashouts
|
|
91
|
-
- Cleared to zero on terminal migration (migrateBalanceOf)
|
|
92
|
-
```
|
|
29
|
+
### Payment
|
|
93
30
|
|
|
94
|
-
|
|
31
|
+
```text
|
|
32
|
+
terminal receives funds
|
|
33
|
+
-> terminal store reads the current ruleset and optional data hooks
|
|
34
|
+
-> store computes weight-based minting results
|
|
35
|
+
-> controller mints beneficiary tokens and accrues reserved tokens
|
|
36
|
+
-> pay hooks execute only after settlement
|
|
37
|
+
```
|
|
95
38
|
|
|
96
|
-
|
|
39
|
+
### Cash Out
|
|
97
40
|
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
->
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
->
|
|
104
|
-
|
|
105
|
-
-> Returns (ruleset, beneficiaryTokenCount, reservedTokenCount, hookSpecifications)
|
|
106
|
-
|
|
107
|
-
Caller -> JBMultiTerminal.previewCashOutFrom(holder, projectId, cashOutCount, tokenToReclaim, beneficiary, metadata)
|
|
108
|
-
-> JBTerminalStore.previewCashOutFrom()
|
|
109
|
-
-> Calculate surplus, get totalSupply, apply data hook
|
|
110
|
-
-> JBCashOuts.cashOutFrom() — bonding curve
|
|
111
|
-
-> Returns (ruleset, reclaimAmount, cashOutTaxRate, hookSpecifications)
|
|
112
|
-
|
|
113
|
-
Caller -> JBController.previewMintOf(projectId, tokenCount, useReservedPercent)
|
|
114
|
-
-> Read current ruleset
|
|
115
|
-
-> Returns (beneficiaryTokenCount, reservedTokenCount)
|
|
41
|
+
```text
|
|
42
|
+
holder requests redemption
|
|
43
|
+
-> terminal store computes reclaim amount from surplus, supply, and tax settings
|
|
44
|
+
-> optional data hooks can adjust the calculation inputs
|
|
45
|
+
-> controller burns tokens
|
|
46
|
+
-> terminal pays the reclaim amount and routes protocol fees
|
|
47
|
+
-> cash-out hooks execute only after settlement
|
|
116
48
|
```
|
|
117
49
|
|
|
118
|
-
###
|
|
50
|
+
### Payouts And Allowances
|
|
119
51
|
|
|
52
|
+
```text
|
|
53
|
+
authorized caller
|
|
54
|
+
-> consumes payout limits or surplus allowances
|
|
55
|
+
-> funds move to splits, projects, hooks, or direct recipients
|
|
120
56
|
```
|
|
121
|
-
Owner -> JBMultiTerminal.sendPayoutsOf()
|
|
122
|
-
-> JBTerminalStore.recordPayoutFor()
|
|
123
|
-
-> Deduct balance, check payout limits
|
|
124
|
-
-> Distribute to splits (JBSplits)
|
|
125
|
-
-> Split to project -> pay project's terminal
|
|
126
|
-
-> Split to address -> direct transfer
|
|
127
|
-
-> Split to hook -> IJBSplitHook.processSplitWith()
|
|
128
|
-
-> Take fees on non-feeless payouts
|
|
129
|
-
```
|
|
130
57
|
|
|
131
|
-
##
|
|
58
|
+
## Critical Invariants
|
|
59
|
+
|
|
60
|
+
- Preview functions must remain behaviorally aligned with state-changing functions.
|
|
61
|
+
- Data hooks run before settlement and may alter the economics; pay and cash-out hooks run after settlement. That phase boundary is intentional.
|
|
62
|
+
- Reserved tokens and pending reserves affect supply-sensitive math even before distribution.
|
|
63
|
+
- Terminal balances, fee accounting, and surplus calculations must agree. Any drift here contaminates every product repo.
|
|
64
|
+
- Rulesets are time-ordered and approval-aware; deployment wrappers depend on predictable ID progression and activation semantics.
|
|
65
|
+
- Permission checks are not a UI concern. They are part of protocol state transition validity.
|
|
132
66
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
| Cash Out Hook | `IJBCashOutHook.afterCashOutRecordedWith` | JBMultiTerminal |
|
|
139
|
-
| Split Hook | `IJBSplitHook.processSplitWith` | JBMultiTerminal, JBController (try-catch; reverts emit `SplitHookReverted`) |
|
|
140
|
-
| Approval Hook | `IJBRulesetApprovalHook.approvalStatusOf` | JBRulesets |
|
|
67
|
+
## Where Complexity Lives
|
|
68
|
+
|
|
69
|
+
- `JBMultiTerminal`, `JBTerminalStore`, and `JBController` form one accounting pipeline and are easiest to misunderstand when read separately.
|
|
70
|
+
- Preview paths deliberately mirror state-changing paths; keeping them aligned is a permanent maintenance burden.
|
|
71
|
+
- Fee-free surplus, held fees, and payout/allowance interactions create edge cases that are small in code size but large in blast radius.
|
|
141
72
|
|
|
142
73
|
## Dependencies
|
|
143
74
|
|
|
144
|
-
-
|
|
145
|
-
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
-
|
|
153
|
-
-
|
|
154
|
-
- MAX_CASH_OUT_TAX_RATE = 10,000
|
|
155
|
-
- MAX_WEIGHT_CUT_PERCENT = 1,000,000,000 (9 decimals)
|
|
156
|
-
- SPLITS_TOTAL_PERCENT = 1,000,000,000
|
|
157
|
-
- NATIVE_TOKEN = 0x000000000000000000000000000000000000EEEe
|
|
158
|
-
- Fee holding: 28 days (2,419,200 seconds)
|
|
159
|
-
- Fee beneficiary: project ID 1
|
|
75
|
+
- `nana-permission-ids-v6` for the shared permission namespace
|
|
76
|
+
- OpenZeppelin, PRBMath, Chainlink, and Permit2 for standards and math utilities
|
|
77
|
+
|
|
78
|
+
## Safe Change Guide
|
|
79
|
+
|
|
80
|
+
- Start any nontrivial change by tracing both the preview path and the state-changing path.
|
|
81
|
+
- Read downstream hook repos before changing hook interfaces or metadata expectations.
|
|
82
|
+
- Keep fee logic, balance logic, and surplus logic in sync; "small" tweaks here are almost always ecosystem-wide changes.
|
|
83
|
+
- When adding permissions or changing who is checked against a permission, update ecosystem docs and downstream assumptions immediately.
|
|
84
|
+
- If a change seems local inside core, assume it is not until proven otherwise.
|