@bananapus/core-v6 0.0.34 → 0.0.35
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 +75 -349
- package/ARCHITECTURE.md +86 -44
- package/AUDIT_INSTRUCTIONS.md +29 -42
- package/README.md +22 -3
- package/RISKS.md +7 -0
- package/SKILLS.md +16 -4
- package/USER_JOURNEYS.md +130 -30
- package/foundry.toml +2 -0
- package/package.json +1 -1
- package/src/JBERC20.sol +0 -1
- package/src/structs/JBAccountingContext.sol +0 -1
- package/src/structs/JBAfterCashOutRecordedContext.sol +0 -1
- package/src/structs/JBAfterPayRecordedContext.sol +0 -1
- package/src/structs/JBBeforeCashOutRecordedContext.sol +0 -1
- package/src/structs/JBBeforePayRecordedContext.sol +0 -1
- package/src/structs/JBCashOutHookSpecification.sol +0 -1
- package/src/structs/JBCurrencyAmount.sol +0 -1
- package/src/structs/JBFee.sol +0 -1
- package/src/structs/JBFundAccessLimitGroup.sol +0 -1
- package/src/structs/JBPayHookSpecification.sol +0 -1
- package/src/structs/JBPermissionsData.sol +0 -1
- package/src/structs/JBRuleset.sol +0 -1
- package/src/structs/JBRulesetConfig.sol +0 -1
- package/src/structs/JBRulesetMetadata.sol +0 -1
- package/src/structs/JBRulesetWeightCache.sol +0 -1
- package/src/structs/JBRulesetWithMetadata.sol +0 -1
- package/src/structs/JBSingleAllowance.sol +0 -1
- package/src/structs/JBSplit.sol +0 -1
- package/src/structs/JBSplitGroup.sol +0 -1
- package/src/structs/JBSplitHookContext.sol +0 -1
- package/src/structs/JBTerminalConfig.sol +0 -1
- package/src/structs/JBTokenAmount.sol +0 -1
package/ADMINISTRATION.md
CHANGED
|
@@ -1,377 +1,103 @@
|
|
|
1
1
|
# Administration
|
|
2
2
|
|
|
3
|
-
Admin privileges and their scope in nana-core-v6.
|
|
4
|
-
|
|
5
3
|
## At A Glance
|
|
6
4
|
|
|
7
5
|
| Item | Details |
|
|
8
|
-
|
|
9
|
-
| Scope | Core Juicebox V6
|
|
10
|
-
|
|
|
11
|
-
| Highest-risk actions |
|
|
12
|
-
| Recovery posture |
|
|
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.
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| Scope | Core Juicebox V6 control plane: directory, controller, terminals, permissions, prices, and global protocol switches |
|
|
8
|
+
| Control posture | Mixed protocol-owner, project-owner, delegated-operator, controller, and terminal control |
|
|
9
|
+
| Highest-risk actions | Controller migration, terminal migration, token binding, price-feed installation, and broad permission grants |
|
|
10
|
+
| Recovery posture | Project-local mistakes may be fixable if rulesets permit; immutable infra mistakes usually require replacement layers and migration |
|
|
21
11
|
|
|
22
|
-
##
|
|
12
|
+
## Purpose
|
|
23
13
|
|
|
24
|
-
-
|
|
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.
|
|
14
|
+
`nana-core-v6` is the largest control plane in the stack. It combines protocol-owned contracts, project-local ownership, delegated operators through `JBPermissions`, and ruleset flags that selectively permit or forbid changes. This file is about who can still change project behavior once the core is live.
|
|
28
15
|
|
|
29
|
-
##
|
|
16
|
+
## Control Model
|
|
30
17
|
|
|
31
|
-
-
|
|
32
|
-
-
|
|
18
|
+
- Protocol-wide `Ownable` surfaces exist on `JBDirectory`, `JBProjects`, `JBPrices`, and `JBFeelessAddresses`.
|
|
19
|
+
- Project-local control runs through the project NFT owner in `JBProjects`.
|
|
20
|
+
- Fine-grained operator delegation runs through `JBPermissions`.
|
|
21
|
+
- Controllers and terminals are privileged system callers once the directory points to them.
|
|
22
|
+
- Current ruleset flags can further allow or deny certain owner or operator actions.
|
|
33
23
|
|
|
34
24
|
## Roles
|
|
35
25
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- **Scope:** Manages a single project's rulesets, tokens, splits, and fund access limits. Contracts gated by `onlyControllerOf(projectId)` (from `JBControlled`) only accept calls from the address registered as the project's controller in the directory.
|
|
45
|
-
|
|
46
|
-
### Terminal
|
|
47
|
-
|
|
48
|
-
- **How assigned:** Set via `JBDirectory.setTerminalsOf()`. Stored in the directory's `_terminalsOf[projectId]` array.
|
|
49
|
-
- **Scope:** Manages fund inflows and outflows for a single project. Terminal identity is verified via `DIRECTORY.isTerminalOf()`. Terminals interact with `JBTerminalStore` using `msg.sender`-scoped bookkeeping -- each terminal can only modify its own balances.
|
|
50
|
-
|
|
51
|
-
### Operator
|
|
52
|
-
|
|
53
|
-
- **How assigned:** Granted permissions by any address via `JBPermissions.setPermissionsFor()`. Permissions are stored as a packed `uint256` bitmap per `(operator, account, projectId)` tuple.
|
|
54
|
-
- **Scope:** Can execute specific functions on behalf of the account that granted them permissions, scoped to a specific project ID (or all projects if `projectId = 0` wildcard is used).
|
|
55
|
-
|
|
56
|
-
### ROOT Permission Holder
|
|
57
|
-
|
|
58
|
-
- **How assigned:** Granted the ROOT permission (ID 1) by an account via `JBPermissions`. ROOT on a specific project grants all permissions for that project. ROOT cannot be granted on the wildcard project ID (0) to prevent unlimited cross-project access.
|
|
59
|
-
- **Scope:** ROOT holders for a project can do anything the project owner can do for that project. ROOT holders can also grant non-ROOT permissions to other operators for the same project but cannot grant ROOT to others or set wildcard permissions.
|
|
60
|
-
|
|
61
|
-
### Directory Owner
|
|
62
|
-
|
|
63
|
-
- **How assigned:** Set at JBDirectory deployment via the Ownable constructor. Transferable via `Ownable.transferOwnership()`.
|
|
64
|
-
- **Scope:** Protocol-wide. Controls which addresses are allowed to set a project's first controller (`isAllowedToSetFirstController`).
|
|
65
|
-
|
|
66
|
-
### JBProjects Owner
|
|
67
|
-
|
|
68
|
-
- **How assigned:** Set at JBProjects deployment via the Ownable constructor. Transferable via `Ownable.transferOwnership()`.
|
|
69
|
-
- **Scope:** Protocol-wide. Can set the `tokenUriResolver` that resolves project NFT metadata URIs.
|
|
70
|
-
|
|
71
|
-
### JBPrices Owner
|
|
72
|
-
|
|
73
|
-
- **How assigned:** Set at JBPrices deployment via the Ownable constructor. Transferable via `Ownable.transferOwnership()`.
|
|
74
|
-
- **Scope:** Protocol-wide. Can add default price feeds (project ID 0) that apply to all projects as fallback.
|
|
75
|
-
|
|
76
|
-
### JBFeelessAddresses Owner
|
|
77
|
-
|
|
78
|
-
- **How assigned:** Set at JBFeelessAddresses deployment via the Ownable constructor. Transferable via `Ownable.transferOwnership()`.
|
|
79
|
-
- **Scope:** Protocol-wide. Controls which addresses are exempt from protocol fees.
|
|
80
|
-
|
|
81
|
-
### JBERC20 Access Control
|
|
82
|
-
|
|
83
|
-
- **How assigned:** The `TOKENS` reference is set to the `JBTokens` contract address during `initialize()`. `PERMISSIONS` and `PROJECTS` are constructor immutables inherited from `JBPermissioned` and the implementation contract respectively.
|
|
84
|
-
- **Scope:** Single token contract. Only the `JBTokens` contract (via the `onlyTokens` modifier) can mint, burn, and update token metadata. Project owners or operators with the `SIGN_FOR_ERC20` permission can authorize ERC-1271 signatures.
|
|
85
|
-
|
|
86
|
-
### Omnichain Ruleset Operator
|
|
87
|
-
|
|
88
|
-
- **How assigned:** Immutable address set in the `JBController` constructor as `OMNICHAIN_RULESET_OPERATOR`.
|
|
89
|
-
- **Scope:** Can call `launchRulesetsFor` and `queueRulesetsOf` on any project, bypassing owner permission checks. This allows the omnichain deployer to synchronize rulesets across chains.
|
|
90
|
-
|
|
91
|
-
### Data Hook
|
|
92
|
-
|
|
93
|
-
- **How assigned:** Specified in a ruleset's metadata as the `dataHook` address. Active only during the ruleset it is configured for.
|
|
94
|
-
- **Scope:** Can mint tokens via `JBController.mintTokensOf()` when the data hook reports `hasMintPermissionFor()` returns true. Also controls pay/cashout hook specifications returned from `JBTerminalStore`.
|
|
95
|
-
|
|
96
|
-
### Fee Beneficiary (Project ID 1)
|
|
97
|
-
|
|
98
|
-
- **How assigned:** Hardcoded as `_FEE_BENEFICIARY_PROJECT_ID = 1` in JBMultiTerminal.
|
|
99
|
-
- **Scope:** Receives all protocol fees (2.5%) from payouts, surplus allowance usage, and cash outs with non-zero tax rates. This is the first project created during deployment.
|
|
100
|
-
|
|
101
|
-
## Privileged Functions
|
|
102
|
-
|
|
103
|
-
### JBPermissions
|
|
104
|
-
|
|
105
|
-
| Function | Required Role | Permission ID | Scope | What It Does |
|
|
106
|
-
|----------|--------------|---------------|-------|-------------|
|
|
107
|
-
| `setPermissionsFor` | Account owner, or ROOT operator for that account+project | ROOT (1) | Per account + project | Sets the permission bitmap for an operator. ROOT operators can set non-ROOT permissions for the same project but cannot grant ROOT or set wildcard project permissions. |
|
|
108
|
-
|
|
109
|
-
### JBProjects
|
|
110
|
-
|
|
111
|
-
| Function | Required Role | Permission ID | Scope | What It Does |
|
|
112
|
-
|----------|--------------|---------------|-------|-------------|
|
|
113
|
-
| `setTokenUriResolver` | Contract owner | N/A (onlyOwner) | Protocol-wide | Sets the contract that resolves token URIs for all project NFTs. |
|
|
114
|
-
| `createFor` | Anyone | N/A | N/A | Creates a new project NFT. No permission required -- anyone can create a project for any owner. |
|
|
115
|
-
|
|
116
|
-
### JBDirectory
|
|
26
|
+
| Role | How Assigned | Scope | Notes |
|
|
27
|
+
| --- | --- | --- | --- |
|
|
28
|
+
| Project owner | `JBProjects.ownerOf(projectId)` | Per project | Root human control surface for a project |
|
|
29
|
+
| Project operator | `JBPermissions` grant | Per project or wildcard | Can be narrow or dangerously broad |
|
|
30
|
+
| Controller | `JBDirectory.controllerOf(projectId)` | Per project | Manages rulesets, token setup, splits, and fund-access config |
|
|
31
|
+
| Terminal | `JBDirectory` terminal set | Per project | Can move funds through `JBTerminalStore` and terminal entrypoints |
|
|
32
|
+
| Protocol owner | `Ownable(owner)` on protocol-wide contracts | Global | Different contracts have different owners |
|
|
33
|
+
| Omnichain ruleset operator | `JBController` constructor immutable | Global or broad | Bypasses some ordinary owner paths for synchronized ruleset flows |
|
|
117
34
|
|
|
118
|
-
|
|
119
|
-
|----------|--------------|---------------|-------|-------------|
|
|
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. |
|
|
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. |
|
|
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. |
|
|
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. |
|
|
35
|
+
## Privileged Surfaces
|
|
124
36
|
|
|
125
|
-
|
|
37
|
+
High-value admin functions include:
|
|
126
38
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
| `launchRulesetsFor` | Project owner, operator, or OMNICHAIN_RULESET_OPERATOR | LAUNCH_RULESETS (3) + SET_TERMINALS (15) | Per project | Queues initial rulesets and configures terminals for an existing project that has no rulesets yet. Also sets this contract as the project's controller. |
|
|
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. |
|
|
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. |
|
|
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. |
|
|
138
|
-
| `setSplitGroupsOf` | Project owner or operator | SET_SPLIT_GROUPS (19) | Per project | Sets split groups for a project. Must preserve any currently locked splits. |
|
|
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). |
|
|
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. |
|
|
141
|
-
| `setUriOf` | Project owner or operator | SET_PROJECT_URI (7) | Per project | Updates the project's metadata URI. |
|
|
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. |
|
|
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. |
|
|
144
|
-
| `beforeReceiveMigrationFrom` | JBDirectory only | N/A (msg.sender == DIRECTORY) | Per project | Called before migration to prepare the new controller. Copies metadata URI and distributes pending reserved tokens from the old controller. |
|
|
145
|
-
| `afterReceiveMigrationFrom` | JBDirectory only | N/A (msg.sender == DIRECTORY) | Per project | Called after migration completes. Currently a no-op. |
|
|
146
|
-
| `executePayReservedTokenToTerminal` | Self only | N/A (msg.sender == address(this)) | Internal | Pays a terminal with reserved tokens. Called internally via try-catch during reserved token distribution. |
|
|
147
|
-
| `previewMintOf` | Anyone | N/A (view) | Per project | Simulates a mint under the current ruleset and returns the beneficiary and reserved token counts. No state modification. |
|
|
39
|
+
- `JBDirectory.setControllerOf(...)`, `setTerminalsOf(...)`, `setPrimaryTerminalOf(...)`
|
|
40
|
+
- `JBController.queueRulesetsOf(...)`, `launchRulesetsFor(...)`, `setSplitGroupsOf(...)`, `deployERC20For(...)`, `setTokenFor(...)`, `setUriOf(...)`, `addPriceFeedFor(...)`
|
|
41
|
+
- `JBMultiTerminal.useAllowanceOf(...)`, `migrateBalanceOf(...)`, `cashOutTokensOf(...)` when permission-gated by the holder or delegated authority
|
|
42
|
+
- `JBPermissions.setPermissionsFor(...)`
|
|
43
|
+
- `JBPrices.addPriceFeedFor(...)` for protocol defaults or project-local feeds
|
|
44
|
+
- `JBFeelessAddresses.setFeelessAddress(...)`
|
|
45
|
+
- `JBProjects.setTokenUriResolver(...)`
|
|
148
46
|
|
|
149
|
-
|
|
47
|
+
The most important practical distinction is:
|
|
150
48
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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. |
|
|
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. |
|
|
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. |
|
|
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. |
|
|
158
|
-
| `pay` | Anyone | N/A | N/A | Pays a project with tokens. No permission required. |
|
|
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. |
|
|
160
|
-
| `processHeldFeesOf` | Anyone | N/A | Per project | Processes held fees that have passed their 28-day unlock period. No permission required. |
|
|
161
|
-
| `executePayout` | Self only | N/A (msg.sender == address(this)) | Internal | Executes a single payout to a split. Called internally via try-catch during payout distribution. |
|
|
162
|
-
| `executeProcessFee` | Self only | N/A (msg.sender == address(this)) | Internal | Processes a fee payment to the fee beneficiary project. Called internally via try-catch. |
|
|
163
|
-
| `executeTransferTo` | Self only | N/A (msg.sender == address(this)) | Internal | Transfers tokens to an address. Called internally via try-catch during payout leftover distribution. |
|
|
164
|
-
| `previewPayFor` | Anyone | N/A (view) | Per project | Simulates a payment and returns the ruleset, beneficiary token count, reserved token count, and hook specifications. No state modification. |
|
|
165
|
-
| `previewCashOutFrom` | Anyone | N/A (view) | Per project | Simulates a cash out and returns the ruleset, reclaim amount, cash out tax rate, and hook specifications. No state modification. |
|
|
49
|
+
- protocol owners change global infrastructure or defaults
|
|
50
|
+
- project owners and their operators change project configuration
|
|
51
|
+
- controllers and terminals are trusted system actors once the directory points to them
|
|
166
52
|
|
|
167
|
-
|
|
53
|
+
## Immutable And One-Way
|
|
168
54
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
| `deployERC20For` | Project's controller | N/A (onlyControllerOf) | Per project | Deploys a cloned JBERC20 token for the project. |
|
|
174
|
-
| `mintFor` | Project's controller | N/A (onlyControllerOf) | Per project | Mints new tokens (ERC-20 if deployed) or credits for a holder. |
|
|
175
|
-
| `setTokenFor` | Project's controller | N/A (onlyControllerOf) | Per project | Sets an external ERC-20 token for the project. Cannot be changed once set. |
|
|
176
|
-
| `setTokenMetadataFor` | Project's controller | N/A (onlyControllerOf) | Per project | Sets the name and symbol of a project's token. |
|
|
177
|
-
| `transferCreditsFrom` | Project's controller | N/A (onlyControllerOf) | Per project | Transfers credits between addresses. |
|
|
55
|
+
- Default or project-specific price feeds are write-once for a given pair.
|
|
56
|
+
- ERC-20 token binding decisions for a project are effectively one-time.
|
|
57
|
+
- The fee beneficiary project ID inside `JBMultiTerminal` is hardcoded.
|
|
58
|
+
- Constructor immutables on controller, directory, terminal, store, prices, and tokens are not patchable.
|
|
178
59
|
|
|
179
|
-
|
|
60
|
+
## Operational Notes
|
|
180
61
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
62
|
+
- Use narrow project-scoped permissions instead of wildcard or ROOT permissions whenever possible.
|
|
63
|
+
- Validate whether the active ruleset allows the change before assuming the owner or operator can perform it.
|
|
64
|
+
- Treat controller migration, terminal migration, token deployment, and price-feed installation as control-plane changes with large blast radius.
|
|
65
|
+
- Read both the permission check and the current ruleset flags before concluding an action is allowed.
|
|
66
|
+
- Keep an eye on fee-route and payout-path failure semantics: some failures are intentionally caught so funds stay recoverable instead of being permanently trapped.
|
|
184
67
|
|
|
185
|
-
|
|
68
|
+
## Machine Notes
|
|
186
69
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
70
|
+
- Do not infer authority from project ownership alone; many paths also depend on the active ruleset and permission bitmap.
|
|
71
|
+
- Treat `JBDirectory`, `JBController`, `JBMultiTerminal`, `JBPermissions`, `JBPrices`, `JBFeelessAddresses`, and `JBProjects` as the minimum source-of-truth set for control-plane crawling.
|
|
72
|
+
- If a controller, terminal, or price-feed action is not backed by the exact current directory entry, stop and resolve the mismatch first.
|
|
73
|
+
- If a permission is not named explicitly in the call path, inspect the contract check before assuming delegated authority exists.
|
|
74
|
+
- If a fee route or split payout failed, inspect whether the core intentionally restored project balance or left a retry path before calling it a permanent loss.
|
|
190
75
|
|
|
191
|
-
|
|
76
|
+
## Recovery
|
|
192
77
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
### JBPrices
|
|
199
|
-
|
|
200
|
-
| Function | Required Role | Permission ID | Scope | What It Does |
|
|
201
|
-
|----------|--------------|---------------|-------|-------------|
|
|
202
|
-
| `addPriceFeedFor` | Contract owner (for project ID 0 defaults) or project's controller (for project-specific feeds) | N/A (onlyOwner or onlyControllerOf) | Protocol-wide or per project | Adds an immutable price feed for a currency pair. Default feeds (project 0) apply as fallback for all projects. |
|
|
203
|
-
|
|
204
|
-
### JBFeelessAddresses
|
|
205
|
-
|
|
206
|
-
| Function | Required Role | Permission ID | Scope | What It Does |
|
|
207
|
-
|----------|--------------|---------------|-------|-------------|
|
|
208
|
-
| `setFeelessAddress` | Contract owner | N/A (onlyOwner) | Protocol-wide | Marks an address as feeless or not. Feeless addresses do not incur the 2.5% protocol fee on payouts, surplus allowance usage, or cash outs. |
|
|
209
|
-
|
|
210
|
-
### JBERC20
|
|
211
|
-
|
|
212
|
-
| Function | Required Role | Permission ID | Scope | What It Does |
|
|
213
|
-
|----------|--------------|---------------|-------|-------------|
|
|
214
|
-
| `mint` | JBTokens contract | N/A (onlyTokens) | Per token | Mints new tokens to an address. |
|
|
215
|
-
| `burn` | JBTokens contract | N/A (onlyTokens) | Per token | Burns tokens from an address. |
|
|
216
|
-
| `initialize` | Anyone (once) | N/A | Per token | Initializes the token name, symbol, and JBTokens contract reference. Can only be called once. |
|
|
217
|
-
| `setMetadata` | JBTokens contract | N/A (onlyTokens) | Per token | Updates the token's name and symbol. |
|
|
218
|
-
| `isValidSignature` | Anyone (view) | `SIGN_FOR_ERC20` | Per token | Validates ERC-1271 signatures for project owner or permitted operators. |
|
|
219
|
-
|
|
220
|
-
### JBTerminalStore
|
|
221
|
-
|
|
222
|
-
JBTerminalStore has no explicit access control modifiers. Instead, it uses `msg.sender`-scoped storage -- each terminal can only read and write its own balance slots. The functions are designed to be called by terminal contracts:
|
|
223
|
-
|
|
224
|
-
| Function | Implicit Caller | What It Does |
|
|
225
|
-
|----------|----------------|-------------|
|
|
226
|
-
| `recordAddedBalanceFor` | Any address (terminal) | Increments the caller's recorded balance for a project/token. |
|
|
227
|
-
| `recordCashOutFor` | Any address (terminal) | Records a cash out, calculating reclaim amounts via bonding curve. Decrements the caller's balance. |
|
|
228
|
-
| `recordPaymentFrom` | Any address (terminal) | Records a payment, calculating token issuance via weight. Increments the caller's balance. |
|
|
229
|
-
| `recordPayoutFor` | Any address (terminal) | Records a payout against payout limits. Decrements the caller's balance. |
|
|
230
|
-
| `recordTerminalMigration` | Any address (terminal) | Records a full balance migration. Requires the ruleset's `allowTerminalMigration` flag. Zeros out the caller's balance. |
|
|
231
|
-
| `recordUsedAllowanceOf` | Any address (terminal) | Records surplus allowance usage. Decrements the caller's balance. |
|
|
232
|
-
|
|
233
|
-
## Deployment Dependencies
|
|
234
|
-
|
|
235
|
-
Contracts must be deployed in dependency order. The constructor dependency graph:
|
|
236
|
-
|
|
237
|
-
1. **No dependencies:** JBPermissions, JBProjects, JBERC20 (implementation), JBFeelessAddresses
|
|
238
|
-
2. **Depends on (1):** JBDirectory (← JBPermissions, JBProjects)
|
|
239
|
-
3. **Depends on (2):** JBRulesets, JBSplits, JBFundAccessLimits, JBTokens (← JBDirectory); JBPrices (← JBDirectory, JBPermissions, JBProjects)
|
|
240
|
-
4. **Depends on (3):** JBTerminalStore (← JBDirectory, JBPrices, JBRulesets)
|
|
241
|
-
5. **Depends on (1-4):** JBController (← JBDirectory, JBFundAccessLimits, JBPermissions, JBPrices, JBProjects, JBRulesets, JBSplits, JBTokens + omnichainRulesetOperator address)
|
|
242
|
-
6. **Depends on (1-4):** JBMultiTerminal (← JBTerminalStore, JBFeelessAddresses, JBPermissions, JBProjects, JBSplits, JBTokens, Permit2)
|
|
243
|
-
|
|
244
|
-
After deployment, `JBDirectory.setIsAllowedToSetFirstController()` must be called to authorize the controller. The first project (ID 1, the fee project) is created automatically in the `JBProjects` constructor.
|
|
245
|
-
|
|
246
|
-
## Permission System
|
|
247
|
-
|
|
248
|
-
JBPermissions implements a 256-bit packed permission bitmap system:
|
|
249
|
-
|
|
250
|
-
- **256 permission slots**: Each bit in a `uint256` represents one permission. Bit 0 is reserved (cannot be set). Bits 1-255 are available for permission IDs.
|
|
251
|
-
- **ROOT permission (ID 1)**: Acts as a superuser for the granted project. A ROOT operator passes all permission checks for that project via `includeRoot: true`.
|
|
252
|
-
- **Wildcard project ID (0)**: Granting a permission on project ID 0 makes it apply to all projects for that account. ROOT cannot be granted on the wildcard project ID to prevent unlimited cross-project access.
|
|
253
|
-
- **Operator delegation**: Any address can grant any other address specific permissions. The `_requirePermissionFrom` check passes if `msg.sender == account` OR if the sender has the required permission (with ROOT fallback and wildcard fallback).
|
|
254
|
-
- **Override pattern**: `_requirePermissionAllowingOverrideFrom` adds an `alsoGrantAccessIf` boolean that bypasses the permission check entirely when true. This is used to allow terminals, controllers, and data hooks to call privileged functions without explicit operator permissions.
|
|
255
|
-
|
|
256
|
-
### Permission IDs Used in nana-core-v6
|
|
257
|
-
|
|
258
|
-
| ID | Name | Function It Gates |
|
|
259
|
-
|----|------|-------------------|
|
|
260
|
-
| 1 | ROOT | All permissions. Also allows setting non-ROOT permissions for others on the same project. |
|
|
261
|
-
| 2 | QUEUE_RULESETS | `JBController.queueRulesetsOf` |
|
|
262
|
-
| 3 | LAUNCH_RULESETS | `JBController.launchRulesetsFor` |
|
|
263
|
-
| 4 | CASH_OUT_TOKENS | `JBMultiTerminal.cashOutTokensOf` |
|
|
264
|
-
| 5 | SEND_PAYOUTS | `JBMultiTerminal.sendPayoutsOf` (only when `ownerMustSendPayouts` is set) |
|
|
265
|
-
| 6 | MIGRATE_TERMINAL | `JBMultiTerminal.migrateBalanceOf` |
|
|
266
|
-
| 7 | SET_PROJECT_URI | `JBController.setUriOf` |
|
|
267
|
-
| 8 | DEPLOY_ERC20 | `JBController.deployERC20For` |
|
|
268
|
-
| 9 | SET_TOKEN | `JBController.setTokenFor` |
|
|
269
|
-
| 10 | MINT_TOKENS | `JBController.mintTokensOf` |
|
|
270
|
-
| 11 | BURN_TOKENS | `JBController.burnTokensOf` |
|
|
271
|
-
| 12 | CLAIM_TOKENS | `JBController.claimTokensFor` |
|
|
272
|
-
| 13 | TRANSFER_CREDITS | `JBController.transferCreditsFrom` |
|
|
273
|
-
| 14 | SET_CONTROLLER | `JBDirectory.setControllerOf` |
|
|
274
|
-
| 15 | SET_TERMINALS | `JBDirectory.setTerminalsOf` |
|
|
275
|
-
| 16 | ADD_TERMINALS | `JBDirectory.setPrimaryTerminalOf` when it must add a new terminal first |
|
|
276
|
-
| 17 | SET_PRIMARY_TERMINAL | `JBDirectory.setPrimaryTerminalOf` |
|
|
277
|
-
| 18 | USE_ALLOWANCE | `JBMultiTerminal.useAllowanceOf` |
|
|
278
|
-
| 19 | SET_SPLIT_GROUPS | `JBController.setSplitGroupsOf` |
|
|
279
|
-
| 20 | ADD_PRICE_FEED | `JBController.addPriceFeedFor` |
|
|
280
|
-
| 21 | ADD_ACCOUNTING_CONTEXTS | `JBMultiTerminal.addAccountingContextsFor` |
|
|
281
|
-
| 22 | SET_TOKEN_METADATA | `JBController.setTokenMetadataOf` |
|
|
282
|
-
|
|
283
|
-
## Immutable Configuration
|
|
284
|
-
|
|
285
|
-
The following values are set at deploy time and cannot be changed:
|
|
286
|
-
|
|
287
|
-
### JBController
|
|
288
|
-
- `DIRECTORY` -- the directory contract
|
|
289
|
-
- `FUND_ACCESS_LIMITS` -- the fund access limits contract
|
|
290
|
-
- `PERMISSIONS` -- the permissions contract (from JBPermissioned)
|
|
291
|
-
- `PRICES` -- the prices contract
|
|
292
|
-
- `PROJECTS` -- the projects NFT contract
|
|
293
|
-
- `RULESETS` -- the rulesets contract
|
|
294
|
-
- `SPLITS` -- the splits contract
|
|
295
|
-
- `TOKENS` -- the tokens contract
|
|
296
|
-
- `OMNICHAIN_RULESET_OPERATOR` -- the address allowed to launch/queue rulesets for any project
|
|
297
|
-
|
|
298
|
-
### JBMultiTerminal
|
|
299
|
-
- `DIRECTORY` -- derived from STORE.DIRECTORY()
|
|
300
|
-
- `FEELESS_ADDRESSES` -- the feeless addresses registry
|
|
301
|
-
- `FEE` -- hardcoded at 25 (2.5% of MAX_FEE=1000)
|
|
302
|
-
- `PERMISSIONS` -- the permissions contract
|
|
303
|
-
- `PERMIT2` -- the Uniswap Permit2 contract
|
|
304
|
-
- `PROJECTS` -- the projects NFT contract
|
|
305
|
-
- `SPLITS` -- the splits contract
|
|
306
|
-
- `STORE` -- the terminal store contract
|
|
307
|
-
- `TOKENS` -- the tokens contract
|
|
308
|
-
- `_FEE_BENEFICIARY_PROJECT_ID` -- hardcoded as 1
|
|
309
|
-
- `_FEE_HOLDING_SECONDS` -- hardcoded as 2,419,200 (28 days)
|
|
310
|
-
|
|
311
|
-
### JBDirectory
|
|
312
|
-
- `PERMISSIONS` -- the permissions contract
|
|
313
|
-
- `PROJECTS` -- the projects NFT contract
|
|
314
|
-
|
|
315
|
-
### JBPrices
|
|
316
|
-
- `DIRECTORY` -- the directory contract
|
|
317
|
-
- `PERMISSIONS` -- the permissions contract
|
|
318
|
-
- `PROJECTS` -- the projects NFT contract
|
|
319
|
-
- Price feeds are immutable once set (cannot be replaced or removed)
|
|
320
|
-
|
|
321
|
-
### JBTokens
|
|
322
|
-
- `DIRECTORY` -- the directory contract
|
|
323
|
-
- `TOKEN` -- the JBERC20 implementation used for cloning
|
|
324
|
-
- Project token assignments are immutable once set (cannot be changed to a different token)
|
|
325
|
-
|
|
326
|
-
### JBRulesets
|
|
327
|
-
- `DIRECTORY` -- the directory contract
|
|
328
|
-
|
|
329
|
-
### JBSplits
|
|
330
|
-
- `DIRECTORY` -- the directory contract
|
|
331
|
-
|
|
332
|
-
### JBFundAccessLimits
|
|
333
|
-
- `DIRECTORY` -- the directory contract
|
|
334
|
-
|
|
335
|
-
### JBTerminalStore
|
|
336
|
-
- `DIRECTORY` -- the directory contract
|
|
337
|
-
- `PRICES` -- the prices contract
|
|
338
|
-
- `RULESETS` -- the rulesets contract
|
|
339
|
-
|
|
340
|
-
### JBPermissions
|
|
341
|
-
- Trusted forwarder for ERC-2771 meta-transactions
|
|
342
|
-
|
|
343
|
-
## Ruleset Flags That Gate Admin Actions
|
|
344
|
-
|
|
345
|
-
Several admin functions are further gated by boolean flags in the active ruleset's metadata. These flags are set when the ruleset is queued and cannot be changed until a new ruleset takes effect:
|
|
346
|
-
|
|
347
|
-
| Flag | What It Gates |
|
|
348
|
-
|------|--------------|
|
|
349
|
-
| `allowOwnerMinting` | Whether the project owner/operator can call `mintTokensOf`. Terminals and data hooks can always mint regardless. |
|
|
350
|
-
| `allowSetCustomToken` | Whether `setTokenFor` can be called. |
|
|
351
|
-
| `allowTerminalMigration` | Whether `migrateBalanceOf` / `recordTerminalMigration` can proceed. |
|
|
352
|
-
| `allowSetTerminals` | Whether `setTerminalsOf` can be called by non-controller callers. |
|
|
353
|
-
| `allowSetController` | Whether `setControllerOf` can be called (checked via `IJBDirectoryAccessControl`). |
|
|
354
|
-
| `allowAddAccountingContext` | Whether `addAccountingContextsFor` can add new token contexts. |
|
|
355
|
-
| `allowAddPriceFeed` | Whether `addPriceFeedFor` can add new price feeds. |
|
|
356
|
-
| `ownerMustSendPayouts` | Whether `sendPayoutsOf` requires SEND_PAYOUTS permission (otherwise anyone can call it). |
|
|
357
|
-
| `pausePay` | Whether payments are paused (checked in JBTerminalStore). |
|
|
358
|
-
| `pauseCreditTransfers` | Whether credit transfers are paused. |
|
|
359
|
-
| `holdFees` | Whether fees are held (deferred for 28 days) instead of being processed immediately. |
|
|
78
|
+
- Wrong immutable infra usually means a new controller, terminal, store, or price layer and then migration.
|
|
79
|
+
- Wrong project-local config can often be corrected if the current ruleset still permits the change.
|
|
80
|
+
- Wrong wildcard permissions are fixable only by updating the permission bitmap; they are dangerous mainly because of what can happen before revocation.
|
|
81
|
+
- Some fee-route and payout-route failures are recoverable in place because the core prefers restoring balance and preserving retry paths over trapping funds.
|
|
360
82
|
|
|
361
83
|
## Admin Boundaries
|
|
362
84
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
-
|
|
366
|
-
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
-
|
|
371
|
-
-
|
|
372
|
-
-
|
|
373
|
-
-
|
|
374
|
-
-
|
|
375
|
-
-
|
|
376
|
-
-
|
|
377
|
-
-
|
|
85
|
+
- Protocol owners cannot directly rewrite project economics without going through the contracts and ruleset constraints that enforce those changes.
|
|
86
|
+
- Project owners cannot bypass immutable constructor references or rewrite existing price-feed entries.
|
|
87
|
+
- Controllers and terminals only have the authority the directory and core contracts give them; they do not get arbitrary global power.
|
|
88
|
+
- Nobody can change the hardcoded fee beneficiary or retroactively patch immutable deployment mistakes in place.
|
|
89
|
+
|
|
90
|
+
## Source Map
|
|
91
|
+
|
|
92
|
+
- `src/JBDirectory.sol`
|
|
93
|
+
- `src/JBController.sol`
|
|
94
|
+
- `src/JBMultiTerminal.sol`
|
|
95
|
+
- `src/JBPermissions.sol`
|
|
96
|
+
- `src/JBPrices.sol`
|
|
97
|
+
- `src/JBFeelessAddresses.sol`
|
|
98
|
+
- `src/JBProjects.sol`
|
|
99
|
+
- `test/units/static/JBController/`
|
|
100
|
+
- `test/units/static/JBDirectory/`
|
|
101
|
+
- `test/units/static/JBMultiTerminal/`
|
|
102
|
+
- `test/units/static/JBPermissions/`
|
|
103
|
+
- `test/units/static/JBPrices/`
|