@bananapus/permission-ids-v6 0.0.9 → 0.0.11

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 CHANGED
@@ -14,39 +14,39 @@ All 33 defined permission IDs and what they control:
14
14
 
15
15
  | ID | Constant | Used By | What It Controls |
16
16
  |----|----------|---------|-----------------|
17
- | 1 | `ROOT` | All contracts | Grants every permission. See [ROOT Permission](#root-permission). |
18
- | 2 | `QUEUE_RULESETS` | nana-core | `JBController.queueRulesetsOf` -- queue new rulesets for a project. |
19
- | 3 | `LAUNCH_RULESETS` | nana-core | `JBController.launchRulesetsFor` -- launch a project's initial rulesets. Also requires `SET_TERMINALS` (ID 15). |
20
- | 4 | `CASH_OUT_TOKENS` | nana-core | `JBMultiTerminal.cashOutTokensOf` -- redeem tokens for surplus. Checked against the **token holder**, not the project owner. |
21
- | 5 | `SEND_PAYOUTS` | nana-core | `JBMultiTerminal.sendPayoutsOf` -- distribute payouts to splits. |
22
- | 6 | `MIGRATE_TERMINAL` | nana-core | `JBMultiTerminal.migrateBalanceOf` -- migrate a project's balance to another terminal. |
23
- | 7 | `SET_PROJECT_URI` | nana-core | `JBController.setUriOf` -- set project metadata URI. |
24
- | 8 | `DEPLOY_ERC20` | nana-core | `JBController.deployERC20For` -- deploy a new ERC-20 token for a project. |
25
- | 9 | `SET_TOKEN` | nana-core | `JBController.setTokenFor` -- set an existing ERC-20 token for a project. |
26
- | 10 | `MINT_TOKENS` | nana-core | `JBController.mintTokensOf` -- mint new project tokens. Only effective when the current ruleset allows owner minting. |
27
- | 11 | `BURN_TOKENS` | nana-core | `JBController.burnTokensOf` -- burn tokens. Checked against the **token holder**. |
28
- | 12 | `CLAIM_TOKENS` | nana-core | `JBController.claimTokensFor` -- claim internal credits as ERC-20. Checked against the **token holder**. |
29
- | 13 | `TRANSFER_CREDITS` | nana-core | `JBController.transferCreditsFrom` -- transfer internal credits. Checked against the **token holder**. |
30
- | 14 | `SET_CONTROLLER` | nana-core | `JBDirectory.setControllerOf` -- set a project's controller. |
31
- | 15 | `SET_TERMINALS` | nana-core | `JBDirectory.setTerminalsOf` -- set a project's terminals. **Warning:** can remove the primary terminal. |
32
- | 16 | `SET_PRIMARY_TERMINAL` | nana-core | `JBDirectory.setPrimaryTerminalOf` -- set the primary terminal for a token. |
33
- | 17 | `USE_ALLOWANCE` | nana-core | `JBMultiTerminal.useAllowanceOf` -- spend surplus allowance to an arbitrary address. |
34
- | 18 | `SET_SPLIT_GROUPS` | nana-core | `JBController.setSplitGroupsOf` -- configure payout and reserved token splits. |
35
- | 19 | `ADD_PRICE_FEED` | nana-core | `JBPrices.addPriceFeedFor` (via `JBController.addPriceFeed`) -- add a price feed for a project. |
36
- | 20 | `ADD_ACCOUNTING_CONTEXTS` | nana-core | `JBMultiTerminal.addAccountingContextsFor` -- add accepted tokens to a terminal. |
37
- | 21 | `SET_TOKEN_METADATA` | nana-core | `JBController.setMetadataOf` -- set a project token's name and symbol. |
38
- | 22 | `ADJUST_721_TIERS` | nana-721-hook | `JB721TiersHook.adjustTiers` -- add or remove NFT tiers. |
39
- | 23 | `SET_721_METADATA` | nana-721-hook | `JB721TiersHook.setMetadata` -- set NFT metadata URIs. |
40
- | 24 | `MINT_721` | nana-721-hook | `JB721TiersHook.mintFor` -- manually mint NFTs to a beneficiary. |
41
- | 25 | `SET_721_DISCOUNT_PERCENT` | nana-721-hook | `JB721TiersHook.setDiscountPercentOf` -- set discount percent on NFT tiers. |
42
- | 26 | `SET_BUYBACK_TWAP` | nana-buyback-hook | `JBBuybackHook.setTwapWindowOf` -- configure the TWAP oracle window. |
43
- | 27 | `SET_BUYBACK_POOL` | nana-buyback-hook | `JBBuybackHook.setPoolFor` -- set the Uniswap pool for buybacks. |
44
- | 28 | `SET_BUYBACK_HOOK` | nana-buyback-hook | `JBBuybackHookRegistry.setHookFor` and `lockHookFor` -- configure and permanently lock the buyback hook. |
45
- | 29 | `SET_ROUTER_TERMINAL` | nana-router-terminal | `JBRouterTerminalRegistry.setTerminalFor` and `lockTerminalFor` -- configure and permanently lock the router terminal. |
46
- | 30 | `MAP_SUCKER_TOKEN` | nana-suckers | `JBSucker.mapToken` -- map an ERC-20 to its remote chain counterpart. Immutable once the outbox tree has entries. |
47
- | 31 | `DEPLOY_SUCKERS` | nana-suckers | `JBSuckerRegistry.deploySuckersFor` -- deploy sucker contracts for cross-chain bridging. |
48
- | 32 | `SUCKER_SAFETY` | nana-suckers | `JBSucker.enableEmergencyHatchFor` -- enable the emergency hatch to recover stuck tokens. |
49
- | 33 | `SET_SUCKER_DEPRECATION` | nana-suckers | `JBSucker.setDeprecation` -- set deprecation status (ENABLED, DEPRECATION_PENDING, SENDING_DISABLED, DEPRECATED). |
17
+ | 1 | `ROOT` | All contracts (via `JBPermissions`) | Grants every permission. See [ROOT Permission](#root-permission). |
18
+ | 2 | `QUEUE_RULESETS` | nana-core (`JBController`) | `JBController.queueRulesetsOf` -- queue new rulesets for a project. |
19
+ | 3 | `LAUNCH_RULESETS` | nana-core (`JBController`) | `JBController.launchRulesetsFor` -- launch a project's initial rulesets. Also requires `SET_TERMINALS` (ID 15). |
20
+ | 4 | `CASH_OUT_TOKENS` | nana-core (`JBMultiTerminal`) | `JBMultiTerminal.cashOutTokensOf` -- redeem tokens for surplus. Checked against the **token holder**, not the project owner. |
21
+ | 5 | `SEND_PAYOUTS` | nana-core (`JBMultiTerminal`) | `JBMultiTerminal.sendPayoutsOf` -- distribute payouts to splits. |
22
+ | 6 | `MIGRATE_TERMINAL` | nana-core (`JBMultiTerminal`) | `JBMultiTerminal.migrateBalanceOf` -- migrate a project's balance to another terminal. |
23
+ | 7 | `SET_PROJECT_URI` | nana-core (`JBController`) | `JBController.setUriOf` -- set project metadata URI. |
24
+ | 8 | `DEPLOY_ERC20` | nana-core (`JBController`) | `JBController.deployERC20For` -- deploy a new ERC-20 token for a project. |
25
+ | 9 | `SET_TOKEN` | nana-core (`JBController`) | `JBController.setTokenFor` -- set an existing ERC-20 token for a project. |
26
+ | 10 | `MINT_TOKENS` | nana-core (`JBController`) | `JBController.mintTokensOf` -- mint new project tokens. Only effective when the current ruleset allows owner minting. |
27
+ | 11 | `BURN_TOKENS` | nana-core (`JBController`) | `JBController.burnTokensOf` -- burn tokens. Checked against the **token holder**. |
28
+ | 12 | `CLAIM_TOKENS` | nana-core (`JBController`) | `JBController.claimTokensFor` -- claim internal credits as ERC-20. Checked against the **token holder**. |
29
+ | 13 | `TRANSFER_CREDITS` | nana-core (`JBController`) | `JBController.transferCreditsFrom` -- transfer internal credits. Checked against the **token holder**. |
30
+ | 14 | `SET_CONTROLLER` | nana-core (`JBDirectory`) | `JBDirectory.setControllerOf` -- set a project's controller. |
31
+ | 15 | `SET_TERMINALS` | nana-core (`JBDirectory`) | `JBDirectory.setTerminalsOf` -- set a project's terminals. **Warning:** can remove the primary terminal. |
32
+ | 16 | `SET_PRIMARY_TERMINAL` | nana-core (`JBDirectory`) | `JBDirectory.setPrimaryTerminalOf` -- set the primary terminal for a token. |
33
+ | 17 | `USE_ALLOWANCE` | nana-core (`JBMultiTerminal`) | `JBMultiTerminal.useAllowanceOf` -- spend surplus allowance to an arbitrary address. |
34
+ | 18 | `SET_SPLIT_GROUPS` | nana-core (`JBController`) | `JBController.setSplitGroupsOf` -- configure payout and reserved token splits. |
35
+ | 19 | `ADD_PRICE_FEED` | nana-core (`JBController`) | `JBController.addPriceFeedFor` (which internally calls `JBPrices.addPriceFeedFor`) -- add a price feed for a project. |
36
+ | 20 | `ADD_ACCOUNTING_CONTEXTS` | nana-core (`JBMultiTerminal`) | `JBMultiTerminal.addAccountingContextsFor` -- add accepted tokens to a terminal. |
37
+ | 21 | `SET_TOKEN_METADATA` | nana-core (`JBController`) | `JBController.setTokenMetadataOf` -- set a project token's name and symbol. |
38
+ | 22 | `ADJUST_721_TIERS` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.adjustTiers` -- add or remove NFT tiers. |
39
+ | 23 | `SET_721_METADATA` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.setMetadata` -- set NFT metadata URIs. |
40
+ | 24 | `MINT_721` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.mintFor` -- manually mint NFTs to a beneficiary. |
41
+ | 25 | `SET_721_DISCOUNT_PERCENT` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.setDiscountPercentOf` -- set discount percent on NFT tiers. |
42
+ | 26 | `SET_BUYBACK_TWAP` | nana-buyback-hook (`JBBuybackHook`) | `JBBuybackHook.setTwapWindowOf` -- configure the TWAP oracle window. |
43
+ | 27 | `SET_BUYBACK_POOL` | nana-buyback-hook (`JBBuybackHook`) | `JBBuybackHook.setPoolFor` -- set the Uniswap pool for buybacks. |
44
+ | 28 | `SET_BUYBACK_HOOK` | nana-buyback-hook (`JBBuybackHookRegistry`) | `JBBuybackHookRegistry.setHookFor` and `lockHookFor` -- configure and permanently lock the buyback hook. |
45
+ | 29 | `SET_ROUTER_TERMINAL` | nana-router-terminal (`JBRouterTerminalRegistry`) | `JBRouterTerminalRegistry.setTerminalFor` and `lockTerminalFor` -- configure and permanently lock the router terminal. |
46
+ | 30 | `MAP_SUCKER_TOKEN` | nana-suckers (`JBSucker`) | `JBSucker.mapToken` -- map an ERC-20 to its remote chain counterpart. Immutable once the outbox tree has entries. |
47
+ | 31 | `DEPLOY_SUCKERS` | nana-suckers (`JBSuckerRegistry`) | `JBSuckerRegistry.deploySuckersFor` -- deploy sucker contracts for cross-chain bridging. |
48
+ | 32 | `SUCKER_SAFETY` | nana-suckers (`JBSucker`) | `JBSucker.enableEmergencyHatchFor` -- enable the emergency hatch to recover stuck tokens. |
49
+ | 33 | `SET_SUCKER_DEPRECATION` | nana-suckers (`JBSucker`) | `JBSucker.setDeprecation` -- set deprecation status (ENABLED, DEPRECATION_PENDING, SENDING_DISABLED, DEPRECATED). |
50
50
 
51
51
  IDs 0 and 34-255 are unused. ID 0 is reserved and cannot be set. IDs 34-255 are available for future ecosystem extensions.
52
52
 
@@ -74,11 +74,14 @@ Permissions are stored in `JBPermissions` as a 256-bit packed integer per (opera
74
74
  permissionsOf[operator][account][projectId] => uint256 (packed bits)
75
75
  ```
76
76
 
77
- Each bit position corresponds to a permission ID. When a contract checks whether an operator has a permission, it calls `JBPermissions.hasPermission(operator, account, projectId, permissionId)`, which:
77
+ Each bit position corresponds to a permission ID. When a contract checks whether an operator has a permission, it calls `JBPermissions.hasPermission(operator, account, projectId, permissionId, includeRoot, includeWildcardProjectId)`, which:
78
78
 
79
79
  1. Checks whether the operator has ROOT (bit 1) for the specific project -- if so, returns true.
80
- 2. Checks whether the specific permission bit is set for the project.
81
- 3. Falls back to checking the wildcard `projectId = 0` for both ROOT and the specific permission.
80
+ 2. If `includeWildcardProjectId`, checks whether the operator has ROOT (bit 1) for the wildcard project (`projectId = 0`) -- if so, returns true.
81
+ 3. Checks whether the specific permission bit is set for the specific project -- if so, returns true.
82
+ 4. If `includeWildcardProjectId`, checks whether the specific permission bit is set for the wildcard project (`projectId = 0`) -- if so, returns true.
83
+
84
+ Steps 1-2 are skipped if `includeRoot` is false. Steps 2 and 4 are skipped if `includeWildcardProjectId` is false.
82
85
 
83
86
  Contracts that use this system inherit from `JBPermissioned`, which provides the `_requirePermissionFrom(account, projectId, permissionId)` modifier. This modifier passes if the caller is the account itself or has the required permission via `JBPermissions`.
84
87
 
package/ARCHITECTURE.md CHANGED
@@ -4,6 +4,18 @@
4
4
 
5
5
  Constants library defining permission IDs used throughout the Juicebox V6 ecosystem. These IDs are used with `JBPermissions` to control access to protocol functions.
6
6
 
7
+ ## How Permissions Work
8
+
9
+ These IDs plug into `JBPermissions` in nana-core, which stores permissions as a 256-bit packed `uint256` — one bit per permission ID. Callers check access via `hasPermission(operator, account, projectId, permissionId)`. A project owner can grant any operator a set of permission IDs scoped to a specific project, or use `projectId = 0` as a wildcard to grant permissions across all projects.
10
+
11
+ ## Permission Guards
12
+
13
+ `JBPermissions.setPermissionsFor` enforces three guard rules:
14
+
15
+ - **Permission 0 is reserved.** Setting bit 0 always reverts (`JBPermissions_NoZeroPermission`). This prevents accidental misuse of an uninitialized permission ID.
16
+ - **Wildcard scope requires the account itself.** An operator with ROOT on a specific project cannot use `setPermissionsFor` with `projectId = 0` (wildcard). This prevents a single-project ROOT operator from escalating to all-project access. Reverts with `JBPermissions_Unauthorized`.
17
+ - **ROOT operators cannot grant ROOT to others.** Only the account itself can include `ROOT` (ID 1) in a `setPermissionsFor` call. A ROOT operator calling on behalf of the account will revert if the new permission set includes ROOT.
18
+
7
19
  ## Contract Map
8
20
 
9
21
  ```
@@ -33,9 +45,9 @@ src/
33
45
  | 16 | `SET_PRIMARY_TERMINAL` | nana-core | `JBDirectory.setPrimaryTerminalOf` |
34
46
  | 17 | `USE_ALLOWANCE` | nana-core | `JBMultiTerminal.useAllowanceOf` |
35
47
  | 18 | `SET_SPLIT_GROUPS` | nana-core | `JBController.setSplitGroupsOf` |
36
- | 19 | `ADD_PRICE_FEED` | nana-core | `JBPrices.addPriceFeedFor` |
48
+ | 19 | `ADD_PRICE_FEED` | nana-core | `JBController.addPriceFeedFor` |
37
49
  | 20 | `ADD_ACCOUNTING_CONTEXTS` | nana-core | `JBMultiTerminal.addAccountingContextsFor` |
38
- | 21 | `SET_TOKEN_METADATA` | nana-core | `JBController.setMetadataOf` |
50
+ | 21 | `SET_TOKEN_METADATA` | nana-core | `JBController.setTokenMetadataOf` |
39
51
  | 22 | `ADJUST_721_TIERS` | nana-721-hook | `JB721TiersHook.adjustTiers` |
40
52
  | 23 | `SET_721_METADATA` | nana-721-hook | `JB721TiersHook.setMetadata` |
41
53
  | 24 | `MINT_721` | nana-721-hook | `JB721TiersHook.mintFor` |
@@ -0,0 +1,183 @@
1
+ # Audit Instructions -- nana-permission-ids-v6
2
+
3
+ You are auditing a constants-only library that defines all permission IDs used across the Juicebox V6 ecosystem. The library has no state, no functions, no constructors, and no dependencies. The entire audit surface is the correctness and consistency of 33 `uint8` constants. Read [RISKS.md](./RISKS.md) first -- it documents all known risks and trust assumptions. Then come back here.
4
+
5
+ ## Quick Verification
6
+
7
+ Run this one-liner from the repo root to verify all 33 permission IDs are unique, sequential (1-33), and have no gaps or duplicates:
8
+
9
+ ```bash
10
+ grep 'constant.*=' src/JBPermissionIds.sol | sed 's/.*= \([0-9]*\).*/\1/' | sort -n | diff - <(seq 1 33) && echo "PASS: All 33 IDs are unique and sequential (1-33)" || echo "FAIL: ID mismatch detected"
11
+ ```
12
+
13
+ If `PASS` is printed, the constants are correctly assigned. If `FAIL` is printed, inspect the diff output to identify which IDs are missing, duplicated, or out of range.
14
+
15
+ ## Compiler and Version Info
16
+
17
+ From `foundry.toml`:
18
+
19
+ | Setting | Value |
20
+ |---------|-------|
21
+ | Solidity version | `0.8.28` |
22
+ | EVM target | `cancun` |
23
+ | Optimizer | Enabled, 200 runs |
24
+ | Pragma in source | `^0.8.0` (flexible, compiled with 0.8.28) |
25
+
26
+ Note: The library pragma is `^0.8.0` rather than a fixed version, since consuming contracts may compile it with their own Solidity version. The `foundry.toml` pins `0.8.28` for local builds.
27
+
28
+ ## Previous Audit Findings
29
+
30
+ A Nemesis audit (Feynman + State Inconsistency methodology) was conducted on 2026-03-17. Full results are in [`.audit/findings/nemesis-verified.md`](./.audit/findings/nemesis-verified.md).
31
+
32
+ **Result: 0 Critical | 0 High | 0 Medium | 2 Low (comment inaccuracies)**
33
+
34
+ | ID | Severity | Summary | Status |
35
+ |----|----------|---------|--------|
36
+ | NM-001 | LOW | `ADD_PRICE_FEED` comment misidentifies gated contract (`JBPrices.addPriceFeedFor` vs actual `JBController.addPriceFeedFor`) | Fixed |
37
+ | NM-002 | LOW | `SET_TOKEN_METADATA` comment uses wrong function name (`setMetadataOf` vs actual `setTokenMetadataOf`) | Fixed |
38
+
39
+ Both findings were comment-only inaccuracies with no security impact. All 5 invariants (uniqueness, completeness, type consistency, no ID 0, sequential assignment) passed. Cross-repo verification confirmed correct usage across 7 consuming repos.
40
+
41
+ ## Scope
42
+
43
+ **In scope:**
44
+ ```
45
+ src/JBPermissionIds.sol # Constants library (~67 lines, 33 permission IDs)
46
+ ```
47
+
48
+ **Out of scope:** All consuming contracts (nana-core, nana-721-hook, nana-buyback-hook, nana-router-terminal, nana-suckers, revnet-core, croptop-core). The constants library has no dependencies.
49
+
50
+ ## Architecture
51
+
52
+ `JBPermissionIds` is a Solidity library containing 33 `uint8 internal constant` values numbered 1 through 33. These IDs are used with `JBPermissions.setPermissionsFor()` to grant scoped access to protocol functions. The permission system stores permissions as a 256-bit packed integer (`uint256`), with each bit corresponding to a permission ID.
53
+
54
+ ### Permission System Overview
55
+
56
+ ```
57
+ permissionsOf[operator][account][projectId] => uint256 (one bit per permission ID)
58
+ ```
59
+
60
+ - **Bit 0 (ID 0):** Reserved, cannot be set. `JBPermissions` reverts if bit 0 is included.
61
+ - **Bit 1 (ID 1, ROOT):** Grants all permissions across all contracts. Cannot be granted for wildcard `projectId = 0`.
62
+ - **Bits 2-33:** Individual permissions, each gating a specific function (or set of functions) in the ecosystem.
63
+ - **Bits 34-255:** Unassigned, available for future extensions.
64
+
65
+ ### All Permission IDs
66
+
67
+ | ID | Constant | Gated Function(s) | Checked Against |
68
+ |----|----------|-------------------|-----------------|
69
+ | 1 | `ROOT` | All permissions (implicit) | Project owner |
70
+ | 2 | `QUEUE_RULESETS` | `JBController.queueRulesetsOf` | Project owner |
71
+ | 3 | `LAUNCH_RULESETS` | `JBController.launchRulesetsFor` (also needs SET_TERMINALS) | Project owner |
72
+ | 4 | `CASH_OUT_TOKENS` | `JBMultiTerminal.cashOutTokensOf` | **Token holder** |
73
+ | 5 | `SEND_PAYOUTS` | `JBMultiTerminal.sendPayoutsOf` | Project owner |
74
+ | 6 | `MIGRATE_TERMINAL` | `JBMultiTerminal.migrateBalanceOf` | Project owner |
75
+ | 7 | `SET_PROJECT_URI` | `JBController.setUriOf` | Project owner |
76
+ | 8 | `DEPLOY_ERC20` | `JBController.deployERC20For` | Project owner |
77
+ | 9 | `SET_TOKEN` | `JBController.setTokenFor` | Project owner |
78
+ | 10 | `MINT_TOKENS` | `JBController.mintTokensOf` | Project owner |
79
+ | 11 | `BURN_TOKENS` | `JBController.burnTokensOf` | **Token holder** |
80
+ | 12 | `CLAIM_TOKENS` | `JBController.claimTokensFor` | **Token holder** |
81
+ | 13 | `TRANSFER_CREDITS` | `JBController.transferCreditsFrom` | **Token holder** |
82
+ | 14 | `SET_CONTROLLER` | `JBDirectory.setControllerOf` | Project owner |
83
+ | 15 | `SET_TERMINALS` | `JBDirectory.setTerminalsOf` (WARNING: can remove primary terminal) | Project owner |
84
+ | 16 | `SET_PRIMARY_TERMINAL` | `JBDirectory.setPrimaryTerminalOf` | Project owner |
85
+ | 17 | `USE_ALLOWANCE` | `JBMultiTerminal.useAllowanceOf` | Project owner |
86
+ | 18 | `SET_SPLIT_GROUPS` | `JBController.setSplitGroupsOf` | Project owner |
87
+ | 19 | `ADD_PRICE_FEED` | `JBController.addPriceFeedFor` (not `JBPrices` directly) | Project owner |
88
+ | 20 | `ADD_ACCOUNTING_CONTEXTS` | `JBMultiTerminal.addAccountingContextsFor` | Project owner |
89
+ | 21 | `SET_TOKEN_METADATA` | `JBController.setTokenMetadataOf` | Project owner |
90
+ | 22 | `ADJUST_721_TIERS` | `JB721TiersHook.adjustTiers` | Hook owner |
91
+ | 23 | `SET_721_METADATA` | `JB721TiersHook.setMetadata` | Hook owner |
92
+ | 24 | `MINT_721` | `JB721TiersHook.mintFor` | Hook owner |
93
+ | 25 | `SET_721_DISCOUNT_PERCENT` | `JB721TiersHook.setDiscountPercentOf` | Hook owner |
94
+ | 26 | `SET_BUYBACK_TWAP` | `JBBuybackHook.setTwapWindowOf` | Project owner |
95
+ | 27 | `SET_BUYBACK_POOL` | `JBBuybackHook.setPoolFor` | Project owner |
96
+ | 28 | `SET_BUYBACK_HOOK` | `JBBuybackHookRegistry.setHookFor` + `lockHookFor` | Project owner |
97
+ | 29 | `SET_ROUTER_TERMINAL` | `JBRouterTerminalRegistry.setTerminalFor` + `lockTerminalFor` | Project owner |
98
+ | 30 | `MAP_SUCKER_TOKEN` | `JBSucker.mapToken` | Project owner |
99
+ | 31 | `DEPLOY_SUCKERS` | `JBSuckerRegistry.deploySuckersFor` | Project owner |
100
+ | 32 | `SUCKER_SAFETY` | `JBSucker.enableEmergencyHatchFor` | Project owner |
101
+ | 33 | `SET_SUCKER_DEPRECATION` | `JBSucker.setDeprecation` | Project owner |
102
+
103
+ ## Priority Audit Areas
104
+
105
+ ### 1. ID Uniqueness (Highest Priority)
106
+
107
+ Every permission ID must be unique. Two different constants with the same numeric value would cause one permission grant to silently authorize a different action. Verify:
108
+
109
+ - All 33 constants have distinct values.
110
+ - Values are sequential from 1 to 33 with no gaps and no duplicates.
111
+ - No other file in the ecosystem defines additional permission ID constants that could collide with these.
112
+
113
+ ### 2. ID-to-Function Mapping Correctness
114
+
115
+ Each constant's doc comment claims it gates a specific function. Verify against the actual source code of each consuming contract:
116
+
117
+ - **nana-core-v6**: IDs 2-21 should match the `_requirePermissionFrom` calls in `JBController`, `JBMultiTerminal`, and `JBDirectory`.
118
+ - **nana-721-hook-v6**: IDs 22-25 should match permission checks in `JB721TiersHook`.
119
+ - **nana-buyback-hook-v6**: IDs 26-28 should match permission checks in `JBBuybackHook` and `JBBuybackHookRegistry`.
120
+ - **nana-router-terminal-v6**: ID 29 should match permission checks in `JBRouterTerminalRegistry`.
121
+ - **nana-suckers-v6**: IDs 30-33 should match permission checks in `JBSucker` and `JBSuckerRegistry`.
122
+
123
+ ### 3. Holder-Scoped vs Owner-Scoped Permissions
124
+
125
+ Four permissions are checked against the **token holder**, not the project owner:
126
+
127
+ - `CASH_OUT_TOKENS` (4) -- holder authorizes cashout of their tokens
128
+ - `BURN_TOKENS` (11) -- holder authorizes burning their tokens
129
+ - `CLAIM_TOKENS` (12) -- holder authorizes claiming their credits as ERC-20
130
+ - `TRANSFER_CREDITS` (13) -- holder authorizes transferring their credit balance
131
+
132
+ Verify that no consuming contract incorrectly checks these against the project owner. A confused check would mean the project owner could burn or cash out any holder's tokens (massive vulnerability).
133
+
134
+ ### 4. Dual-Purpose Permission IDs
135
+
136
+ Two IDs intentionally gate both a "set" and a "lock" operation:
137
+
138
+ - **SET_BUYBACK_HOOK (28)**: Gates both `setHookFor` (configurable) and `lockHookFor` (permanent). An operator with this permission can permanently lock the hook configuration.
139
+ - **SET_ROUTER_TERMINAL (29)**: Gates both `setTerminalFor` (configurable) and `lockTerminalFor` (permanent). An operator with this permission can permanently lock the terminal configuration.
140
+
141
+ Verify that project owners are aware of the locking implication when granting these permissions. The source code includes `@dev` documentation, but this is a significant trust escalation.
142
+
143
+ ### 5. ROOT Permission Safety
144
+
145
+ ROOT (ID 1) is the superadmin permission. The `JBPermissions` contract implements critical safety rails:
146
+
147
+ - ROOT cannot be granted for wildcard `projectId = 0` (would grant root across all projects)
148
+ - A ROOT operator can call `setPermissionsFor` on behalf of the account but cannot grant ROOT to others
149
+ - ROOT cannot be included when setting wildcard project permissions
150
+
151
+ Verify these constraints are enforced in `JBPermissions`, not in this library (this library only defines the constant).
152
+
153
+ ### 6. SET_TERMINALS (ID 15) Risk
154
+
155
+ The source comment warns: "Be careful - `SET_TERMINALS` can be used to remove the primary terminal." Additionally, `LAUNCH_RULESETS` (ID 3) requires both ID 3 AND ID 15 because the launch function configures terminals. Verify:
156
+
157
+ - Granting `SET_TERMINALS` alone is sufficient to replace the entire terminal list, potentially breaking a project.
158
+ - Granting `LAUNCH_RULESETS` without also granting `SET_TERMINALS` will cause `launchRulesetsFor` to revert (dual permission check).
159
+
160
+ ## Invariants to Verify
161
+
162
+ 1. **Uniqueness**: All 33 constants have unique values in the range [1, 33].
163
+ 2. **Completeness**: Every `_requirePermissionFrom` call in the ecosystem uses one of these constants (no magic numbers).
164
+ 3. **Type consistency**: All constants are `uint8`, matching the parameter type of `JBPermissions.hasPermission`.
165
+ 4. **No ID 0**: No constant has value 0 (reserved and forbidden by `JBPermissions`).
166
+ 5. **Sequential assignment**: IDs are assigned 1 through 33 with no gaps.
167
+
168
+ ## Testing Setup
169
+
170
+ This is a constants-only library with no runtime behavior. There are no test files. Verification is done by cross-referencing the constants against consuming contracts.
171
+
172
+ ```bash
173
+ cd nana-permission-ids-v6
174
+ forge build # Ensures the library compiles
175
+ ```
176
+
177
+ To verify ID usage across the ecosystem:
178
+ ```bash
179
+ # Search for permission ID usage in consuming repos
180
+ grep -r "JBPermissionIds\." ../nana-core-v6/src/ ../nana-721-hook-v6/src/ ../nana-buyback-hook-v6/src/ ../nana-router-terminal-v6/src/ ../nana-suckers-v6/src/
181
+ ```
182
+
183
+ Go break it.
package/CHANGE_LOG.md ADDED
@@ -0,0 +1,155 @@
1
+ # nana-permission-ids-v6 Changelog (v5 → v6)
2
+
3
+ This document describes all changes between `nana-permission-ids` (v5) and `nana-permission-ids-v6` (v6).
4
+
5
+ ## Summary
6
+
7
+ - **All numeric IDs shifted** — the insertion of `LAUNCH_RULESETS` at ID 3 cascades through every subsequent permission. Any code using hardcoded numeric values will break.
8
+ - **Two permissions split**: `QUEUE_RULESETS` → `QUEUE_RULESETS` + `LAUNCH_RULESETS`; `SUCKER_SAFETY` → `SUCKER_SAFETY` + `SET_SUCKER_DEPRECATION`.
9
+ - **5 new permissions** added: `LAUNCH_RULESETS` (3), `SET_TOKEN_METADATA` (21), `SET_BUYBACK_HOOK` (28), `SET_ROUTER_TERMINAL` (29), `SET_SUCKER_DEPRECATION` (33).
10
+ - **2 swap terminal permissions removed**: `ADD_SWAP_TERMINAL_POOL` and `ADD_SWAP_TERMINAL_TWAP_PARAMS` (swap terminal replaced by router terminal).
11
+
12
+ > **⚠️ WARNING: All numeric permission IDs have shifted.** If your contracts, scripts, or frontends hardcode permission ID numbers (e.g., `permissions.setPermissionsFor(..., 3, ...)` for `CASH_OUT_TOKENS`), they MUST be updated. `CASH_OUT_TOKENS` moved from 3 → 4, `SEND_PAYOUTS` from 4 → 5, and so on. Always reference the named constants from `JBPermissionIds` rather than raw numbers.
13
+
14
+ ---
15
+
16
+ ## 1. Breaking Changes
17
+
18
+ ### All numeric IDs shifted
19
+
20
+ The insertion of `LAUNCH_RULESETS` at ID 3 pushed every subsequent permission ID up by one. Additional new permissions at the end of each section caused further shifts. **Any code that hardcodes numeric permission values will break.**
21
+
22
+ | Permission | v5 ID | v6 ID |
23
+ |---|---|---|
24
+ | `ROOT` | 1 | 1 |
25
+ | `QUEUE_RULESETS` | 2 | 2 |
26
+ | `CASH_OUT_TOKENS` | 3 | 4 |
27
+ | `SEND_PAYOUTS` | 4 | 5 |
28
+ | `MIGRATE_TERMINAL` | 5 | 6 |
29
+ | `SET_PROJECT_URI` | 6 | 7 |
30
+ | `DEPLOY_ERC20` | 7 | 8 |
31
+ | `SET_TOKEN` | 8 | 9 |
32
+ | `MINT_TOKENS` | 9 | 10 |
33
+ | `BURN_TOKENS` | 10 | 11 |
34
+ | `CLAIM_TOKENS` | 11 | 12 |
35
+ | `TRANSFER_CREDITS` | 12 | 13 |
36
+ | `SET_CONTROLLER` | 13 | 14 |
37
+ | `SET_TERMINALS` | 14 | 15 |
38
+ | `SET_PRIMARY_TERMINAL` | 15 | 16 |
39
+ | `USE_ALLOWANCE` | 16 | 17 |
40
+ | `SET_SPLIT_GROUPS` | 17 | 18 |
41
+ | `ADD_PRICE_FEED` | 18 | 19 |
42
+ | `ADD_ACCOUNTING_CONTEXTS` | 19 | 20 |
43
+ | `ADJUST_721_TIERS` | 20 | 22 |
44
+ | `SET_721_METADATA` | 21 | 23 |
45
+ | `MINT_721` | 22 | 24 |
46
+ | `SET_721_DISCOUNT_PERCENT` | 23 | 25 |
47
+ | `SET_BUYBACK_TWAP` | 24 | 26 |
48
+ | `SET_BUYBACK_POOL` | 25 | 27 |
49
+ | `MAP_SUCKER_TOKEN` | 28 | 30 |
50
+ | `DEPLOY_SUCKERS` | 29 | 31 |
51
+ | `SUCKER_SAFETY` | 30 | 32 |
52
+
53
+ ### `QUEUE_RULESETS` split into two permissions
54
+
55
+ In v5, `QUEUE_RULESETS` (2) granted permission to call both `JBController.queueRulesetsOf` and `JBController.launchRulesetsFor`. In v6, these are separate:
56
+
57
+ - `QUEUE_RULESETS` (2) -- only `JBController.queueRulesetsOf`
58
+ - `LAUNCH_RULESETS` (3) -- only `JBController.launchRulesetsFor`
59
+
60
+ > **Cross-repo impact**: `nana-core-v6` (`JBController.launchRulesetsFor`) now requires `LAUNCH_RULESETS` instead of `QUEUE_RULESETS`. `nana-omnichain-deployers-v6` and `revnet-core-v6` both use the new `LAUNCH_RULESETS` permission.
61
+
62
+ ### `SUCKER_SAFETY` split into two permissions
63
+
64
+ In v5, `SUCKER_SAFETY` (30) granted permission to call both `BPSucker.enableEmergencyHatchFor` and `BPSucker.setDeprecation`. In v6, these are separate:
65
+
66
+ - `SUCKER_SAFETY` (32) -- only `JBSucker.enableEmergencyHatchFor`
67
+ - `SET_SUCKER_DEPRECATION` (33) -- only `JBSucker.setDeprecation`
68
+
69
+ ### Swap terminal permissions removed
70
+
71
+ The following permissions from `nana-swap-terminal` no longer exist in v6:
72
+
73
+ | Removed | v5 ID | Notes |
74
+ |---|---|---|
75
+ | `ADD_SWAP_TERMINAL_POOL` | 26 | Was for `JBSwapTerminal.addDefaultPool` |
76
+ | `ADD_SWAP_TERMINAL_TWAP_PARAMS` | 27 | Was for `JBSwapTerminal.addTwapParamsFor` |
77
+
78
+ > **Cross-repo impact**: `nana-router-terminal-v6` (the replacement for swap terminal) uses the new `SET_ROUTER_TERMINAL` (29) permission instead.
79
+
80
+ ### Contract prefix rename (suckers)
81
+
82
+ Sucker contract references changed from `BP*` to `JB*`:
83
+
84
+ - `BPSucker` → `JBSucker`
85
+ - `BPSuckerRegistry` → `JBSuckerRegistry`
86
+
87
+ ### `SET_BUYBACK_TWAP` comment narrowed
88
+
89
+ In v5, the comment stated this gates both `JBBuybackHook.setTwapWindowOf` and `JBBuybackHook.setTwapSlippageToleranceOf`. In v6, the comment only mentions `JBBuybackHook.setTwapWindowOf`.
90
+
91
+ ---
92
+
93
+ ## 2. New Features
94
+
95
+ ### `LAUNCH_RULESETS` (3)
96
+
97
+ New permission split from `QUEUE_RULESETS`. Gates `JBController.launchRulesetsFor` independently.
98
+
99
+ ### `SET_TOKEN_METADATA` (21)
100
+
101
+ New core permission. Gates `JBController.setMetadataOf` for setting project token metadata.
102
+
103
+ ### `SET_BUYBACK_HOOK` (28)
104
+
105
+ New buyback hook permission. Gates both `JBBuybackHookRegistry.setHookFor` and `JBBuybackHookRegistry.lockHookFor`. Note: granting this permission allows the operator to permanently lock the hook configuration.
106
+
107
+ ### `SET_ROUTER_TERMINAL` (29)
108
+
109
+ New router terminal permission. Gates both `JBRouterTerminalRegistry.setTerminalFor` and `JBRouterTerminalRegistry.lockTerminalFor`. Note: granting this permission allows the operator to permanently lock the terminal configuration.
110
+
111
+ ### `SET_SUCKER_DEPRECATION` (33)
112
+
113
+ New permission split from `SUCKER_SAFETY`. Gates `JBSucker.setDeprecation` independently.
114
+
115
+ ---
116
+
117
+ ## 3. Migration Table
118
+
119
+ | v5 Name | v5 ID | v6 Name | v6 ID | Change |
120
+ |---|---|---|---|---|
121
+ | `ROOT` | 1 | `ROOT` | 1 | Unchanged |
122
+ | `QUEUE_RULESETS` | 2 | `QUEUE_RULESETS` | 2 | Narrowed (no longer includes launch) |
123
+ | -- | -- | `LAUNCH_RULESETS` | 3 | **New** (split from `QUEUE_RULESETS`) |
124
+ | `CASH_OUT_TOKENS` | 3 | `CASH_OUT_TOKENS` | 4 | ID changed |
125
+ | `SEND_PAYOUTS` | 4 | `SEND_PAYOUTS` | 5 | ID changed |
126
+ | `MIGRATE_TERMINAL` | 5 | `MIGRATE_TERMINAL` | 6 | ID changed |
127
+ | `SET_PROJECT_URI` | 6 | `SET_PROJECT_URI` | 7 | ID changed |
128
+ | `DEPLOY_ERC20` | 7 | `DEPLOY_ERC20` | 8 | ID changed |
129
+ | `SET_TOKEN` | 8 | `SET_TOKEN` | 9 | ID changed |
130
+ | `MINT_TOKENS` | 9 | `MINT_TOKENS` | 10 | ID changed |
131
+ | `BURN_TOKENS` | 10 | `BURN_TOKENS` | 11 | ID changed |
132
+ | `CLAIM_TOKENS` | 11 | `CLAIM_TOKENS` | 12 | ID changed |
133
+ | `TRANSFER_CREDITS` | 12 | `TRANSFER_CREDITS` | 13 | ID changed |
134
+ | `SET_CONTROLLER` | 13 | `SET_CONTROLLER` | 14 | ID changed |
135
+ | `SET_TERMINALS` | 14 | `SET_TERMINALS` | 15 | ID changed |
136
+ | `SET_PRIMARY_TERMINAL` | 15 | `SET_PRIMARY_TERMINAL` | 16 | ID changed |
137
+ | `USE_ALLOWANCE` | 16 | `USE_ALLOWANCE` | 17 | ID changed |
138
+ | `SET_SPLIT_GROUPS` | 17 | `SET_SPLIT_GROUPS` | 18 | ID changed |
139
+ | `ADD_PRICE_FEED` | 18 | `ADD_PRICE_FEED` | 19 | ID changed |
140
+ | `ADD_ACCOUNTING_CONTEXTS` | 19 | `ADD_ACCOUNTING_CONTEXTS` | 20 | ID changed |
141
+ | -- | -- | `SET_TOKEN_METADATA` | 21 | **New** |
142
+ | `ADJUST_721_TIERS` | 20 | `ADJUST_721_TIERS` | 22 | ID changed |
143
+ | `SET_721_METADATA` | 21 | `SET_721_METADATA` | 23 | ID changed |
144
+ | `MINT_721` | 22 | `MINT_721` | 24 | ID changed |
145
+ | `SET_721_DISCOUNT_PERCENT` | 23 | `SET_721_DISCOUNT_PERCENT` | 25 | ID changed |
146
+ | `SET_BUYBACK_TWAP` | 24 | `SET_BUYBACK_TWAP` | 26 | ID changed, comment narrowed |
147
+ | `SET_BUYBACK_POOL` | 25 | `SET_BUYBACK_POOL` | 27 | ID changed |
148
+ | `ADD_SWAP_TERMINAL_POOL` | 26 | -- | -- | **Removed** |
149
+ | `ADD_SWAP_TERMINAL_TWAP_PARAMS` | 27 | -- | -- | **Removed** |
150
+ | -- | -- | `SET_BUYBACK_HOOK` | 28 | **New** |
151
+ | -- | -- | `SET_ROUTER_TERMINAL` | 29 | **New** |
152
+ | `MAP_SUCKER_TOKEN` | 28 | `MAP_SUCKER_TOKEN` | 30 | ID changed, `BPSucker` → `JBSucker` |
153
+ | `DEPLOY_SUCKERS` | 29 | `DEPLOY_SUCKERS` | 31 | ID changed, `BPSuckerRegistry` → `JBSuckerRegistry` |
154
+ | `SUCKER_SAFETY` | 30 | `SUCKER_SAFETY` | 32 | ID changed, narrowed (no longer includes deprecation) |
155
+ | -- | -- | `SET_SUCKER_DEPRECATION` | 33 | **New** (split from `SUCKER_SAFETY`) |
package/README.md CHANGED
@@ -18,6 +18,15 @@ permissionsOf[operator][account][projectId] => uint256 (packed bits)
18
18
  |----------|-------------|
19
19
  | `JBPermissionIds` | Solidity library with 33 `uint8 internal constant` permission IDs (values 1--33). No state, no functions, no dependencies. Pragma `^0.8.0` for maximum compatibility. |
20
20
 
21
+ ## Repository Layout
22
+
23
+ ```
24
+ src/
25
+ └── JBPermissionIds.sol ── 33 uint8 constants (the only source file)
26
+ ```
27
+
28
+ No tests, interfaces, or deployment scripts -- this repo is a pure constant library.
29
+
21
30
  ## All permission IDs
22
31
 
23
32
  ### Global (ID 1)
@@ -47,9 +56,9 @@ permissionsOf[operator][account][projectId] => uint256 (packed bits)
47
56
  | 16 | `SET_PRIMARY_TERMINAL` | `JBDirectory.setPrimaryTerminalOf` | Set a project's primary terminal for a given token. |
48
57
  | 17 | `USE_ALLOWANCE` | `JBMultiTerminal.useAllowanceOf` | Use a project's surplus allowance to send funds to an arbitrary address. |
49
58
  | 18 | `SET_SPLIT_GROUPS` | `JBController.setSplitGroupsOf` | Set a project's split groups (how payouts and reserved tokens are distributed). |
50
- | 19 | `ADD_PRICE_FEED` | `JBController.addPriceFeed` | Add a price feed for a project. The controller checks this permission before calling `JBPrices.addPriceFeedFor`. |
59
+ | 19 | `ADD_PRICE_FEED` | `JBController.addPriceFeedFor` | Add a price feed for a project. The controller checks this permission before calling `JBPrices.addPriceFeedFor`. |
51
60
  | 20 | `ADD_ACCOUNTING_CONTEXTS` | `JBMultiTerminal.addAccountingContextsFor` | Add accounting contexts (accepted tokens) to a terminal for a project. |
52
- | 21 | `SET_TOKEN_METADATA` | `JBController.setMetadataOf` | Set a project token's name and symbol. Checked against the project owner. |
61
+ | 21 | `SET_TOKEN_METADATA` | `JBController.setTokenMetadataOf` | Set a project token's name and symbol. Checked against the project owner. |
53
62
 
54
63
  ### 721 Hook (IDs 22--25) -- [nana-721-hook-v6](https://github.com/Bananapus/nana-721-hook-v6)
55
64
 
@@ -65,8 +74,8 @@ permissionsOf[operator][account][projectId] => uint256 (packed bits)
65
74
  | ID | Name | Checked in | Description |
66
75
  |----|------|------------|-------------|
67
76
  | 26 | `SET_BUYBACK_TWAP` | `JBBuybackHook.setTwapWindowOf` | Set the TWAP (time-weighted average price) oracle window for a project's buyback hook. |
68
- | 27 | `SET_BUYBACK_POOL` | `JBBuybackHook.setPoolFor`, `JBBuybackHookRegistry.setHookFor`, `JBBuybackHookRegistry.lockHookFor` | Set the Uniswap pool for a project's buyback. Also guards setting and locking the hook in `JBBuybackHookRegistry`. |
69
- | 28 | `SET_BUYBACK_HOOK` | *Reserved / revnet-core-v6* | Defined in `JBPermissionIds` for `JBBuybackHookRegistry.setHookFor` and `lockHookFor`, but the registry currently checks `SET_BUYBACK_POOL` (ID 27) for those functions. Used by `REVDeployer` in revnet-core-v6 as an operator permission grant. |
77
+ | 27 | `SET_BUYBACK_POOL` | `JBBuybackHook.setPoolFor`, `JBBuybackHook.initializePoolFor`, `JBBuybackHookRegistry.setPoolFor`, `JBBuybackHookRegistry.initializePoolFor` | Set the Uniswap pool for a project's buyback hook. |
78
+ | 28 | `SET_BUYBACK_HOOK` | `JBBuybackHookRegistry.setHookFor`, `JBBuybackHookRegistry.lockHookFor` | Set or lock the buyback hook in the registry. Also used by `REVDeployer` as an operator permission grant. |
70
79
 
71
80
  ### Router Terminal (ID 29) -- [nana-router-terminal-v6](https://github.com/Bananapus/nana-router-terminal-v6)
72
81
 
package/RISKS.md CHANGED
@@ -1,21 +1,21 @@
1
- # nana-permission-ids-v6 — Risks
1
+ # RISKS.md -- nana-permission-ids-v6
2
2
 
3
- ## Trust Assumptions
3
+ Constants-only library defining permission ID values used throughout the Bananapus ecosystem. Contains no logic, no state, and no external calls.
4
4
 
5
- This is a constants-only library with no runtime behavior. The risk surface is limited to the correctness of the ID assignments.
5
+ ## 1. Known Risks
6
6
 
7
- ## Known Risks
7
+ - **ROOT permission (ID 1).** ROOT grants all permissions across every contract. Any address granted ROOT can perform any permissioned operation on any project. Should never be granted to untrusted addresses.
8
+ - **SET_BUYBACK_HOOK includes lock (ID 28).** Gates both `setHookFor` and `lockHookFor`. An operator with this permission can permanently lock the buyback hook configuration.
9
+ - **SET_ROUTER_TERMINAL includes lock (ID 29).** Gates both `setTerminalFor` and `lockTerminalFor`. An operator can permanently lock the router terminal.
10
+ - **ID collision risk.** Permission IDs are manually assigned sequential uint8 values. Adding new IDs requires coordination to avoid collision. Library is append-only.
11
+ - **No runtime enforcement.** This library only defines constants. Enforcement happens in consuming contracts. A mismatch between the ID used here and the ID checked in a consumer would silently fail.
12
+ - **High-impact permission IDs (fund-moving).** IDs that control fund flow should receive the most audit scrutiny: `ROOT` (1, grants everything), `CASH_OUT_TOKENS` (4, triggers withdrawals), `SEND_PAYOUTS` (5, triggers payout distribution), `MIGRATE_TERMINAL` (6, moves balances), `SET_TERMINALS` (15, redirects all fund flows), `USE_ALLOWANCE` (17, draws from surplus), `SET_SPLIT_GROUPS` (18, controls where payouts go). Of these, ROOT + SET_TERMINALS + MIGRATE_TERMINAL are the most dangerous — they can redirect all of a project's funds.
13
+ - **Wildcard `projectId=0` semantics.** When a permission is granted with `projectId=0`, it applies to ALL projects. This is used by system contracts (e.g., `REVLoans` gets `USE_ALLOWANCE` with `projectId=0`). A bug in a contract holding wildcard permissions affects every project in the ecosystem, not just one. Only system-level contracts should hold wildcard permissions.
8
14
 
9
- | Risk | Description | Mitigation |
10
- |------|-------------|------------|
11
- | ID collision | If two repos use the same ID for different permissions, access control breaks | IDs are centrally managed in this single file |
12
- | ROOT scope | ROOT (ID 1) grants ALL permissions across all contracts | Cannot be set for wildcard projectId=0; ROOT operators cannot grant ROOT |
13
- | SET_TERMINALS scope | Includes ability to remove the primary terminal | Documented warning in source |
14
- | SET_BUYBACK_HOOK / SET_ROUTER_TERMINAL scope | Each gates both setting AND locking (permanent) | Documented in source; granting means operator can lock |
15
+ ## 2. Design Notes
15
16
 
16
- ## Design Notes
17
-
18
- - Permission 0 is reserved and cannot be set
19
- - IDs are `uint8` (0-255), with 1-33 currently assigned
20
- - IDs 34-255 are available for future ecosystem extensions
21
- - This library has zero dependencies — it is the leaf of the dependency graph
17
+ - Permission 0 is reserved and cannot be set.
18
+ - IDs are `uint8` (0-255), with 1-33 currently assigned.
19
+ - IDs 34-255 are available for future ecosystem extensions.
20
+ - IDs 34-255 are available for ecosystem extensions. Third-party contracts can define their own permission IDs in this range, but must coordinate to avoid collisions. No on-chain registry exists for custom IDs — collision detection is purely social.
21
+ - This library has zero dependencies -- it is the leaf of the dependency graph.
package/SKILLS.md CHANGED
@@ -16,16 +16,7 @@ N/A -- this is a constants-only library with no callable functions.
16
16
 
17
17
  ## How permissions work
18
18
 
19
- Permissions are stored in `JBPermissions` as a 256-bit packed integer:
20
-
21
- ```
22
- permissionsOf[operator][account][projectId] => uint256 (one bit per permission ID)
23
- ```
24
-
25
- When a permissioned function is called, the contract checks whether the caller either **is** the account or **has** the required permission ID for that project. The check also considers:
26
-
27
- 1. **ROOT override** -- if the operator has ROOT (ID 1) for the project (or wildcard), all permission checks pass.
28
- 2. **Wildcard project ID** -- permissions granted with `projectId = 0` apply to all projects for that account.
19
+ Permissions are stored as 256-bit packed integers in `JBPermissions`, keyed by `[operator][account][projectId]`. ROOT (ID 1) passes all checks; `projectId = 0` grants cross-project access. See `nana-core-v6/SKILLS.md` for full permissions mechanics.
29
20
 
30
21
  ## All Permission IDs
31
22
 
@@ -56,9 +47,9 @@ When a permissioned function is called, the contract checks whether the caller e
56
47
  | 16 | `SET_PRIMARY_TERMINAL` | `JBDirectory.setPrimaryTerminalOf` | Set the primary terminal for a given token. Checked against project owner. |
57
48
  | 17 | `USE_ALLOWANCE` | `JBMultiTerminal.useAllowanceOf` | Use surplus allowance to send funds to an arbitrary address. Checked against project owner. |
58
49
  | 18 | `SET_SPLIT_GROUPS` | `JBController.setSplitGroupsOf` | Set how payouts and reserved tokens are distributed. Checked against project owner. |
59
- | 19 | `ADD_PRICE_FEED` | `JBController.addPriceFeed` | Add a price feed for a project. The controller checks this permission, then calls `JBPrices.addPriceFeedFor` internally. Checked against project owner. |
50
+ | 19 | `ADD_PRICE_FEED` | `JBController.addPriceFeedFor` | Add a price feed for a project. The controller checks this permission, then calls `JBPrices.addPriceFeedFor` internally. Checked against project owner. |
60
51
  | 20 | `ADD_ACCOUNTING_CONTEXTS` | `JBMultiTerminal.addAccountingContextsFor` | Add accepted token accounting contexts to a terminal. Checked against project owner. |
61
- | 21 | `SET_TOKEN_METADATA` | `JBController.setMetadataOf` | Set a project token's name and symbol. Checked against project owner. |
52
+ | 21 | `SET_TOKEN_METADATA` | `JBController.setTokenMetadataOf` | Set a project token's name and symbol. Checked against project owner. |
62
53
 
63
54
  ### nana-721-hook-v6
64
55
 
@@ -74,8 +65,8 @@ When a permissioned function is called, the contract checks whether the caller e
74
65
  | ID | Name | Checked in | Permission scope |
75
66
  |----|------|------------|-----------------|
76
67
  | 26 | `SET_BUYBACK_TWAP` | `JBBuybackHook.setTwapWindowOf` | Set the TWAP oracle window duration. Checked against project owner. |
77
- | 27 | `SET_BUYBACK_POOL` | `JBBuybackHook.setPoolFor`, `JBBuybackHookRegistry.setHookFor`, `JBBuybackHookRegistry.lockHookFor` | Set the Uniswap pool for a project's buyback. Also guards setting and locking the hook in `JBBuybackHookRegistry`. Checked against project owner. |
78
- | 28 | `SET_BUYBACK_HOOK` | *Currently unused in buyback hook code* | Defined for `JBBuybackHookRegistry.setHookFor` and `lockHookFor` per the source comment, but the registry actually checks `SET_BUYBACK_POOL` (ID 27) for those functions. Referenced by `REVDeployer` in revnet-core-v6 as an operator permission grant. |
68
+ | 27 | `SET_BUYBACK_POOL` | `JBBuybackHook.setPoolFor`, `JBBuybackHook.initializePoolFor`, `JBBuybackHookRegistry.initializePoolFor` | Set the Uniswap pool for a project's buyback. Checked against project owner. |
69
+ | 28 | `SET_BUYBACK_HOOK` | `JBBuybackHookRegistry.setHookFor`, `JBBuybackHookRegistry.lockHookFor` | Set or lock the buyback hook implementation for a project. Checked against project owner. Also granted by `REVDeployer` as an operator permission. |
79
70
 
80
71
  ### nana-router-terminal-v6
81
72
 
@@ -92,6 +83,20 @@ When a permissioned function is called, the contract checks whether the caller e
92
83
  | 32 | `SUCKER_SAFETY` | `JBSucker.enableEmergencyHatchFor` | Enable the emergency hatch to recover stuck tokens. Checked against project owner. |
93
84
  | 33 | `SET_SUCKER_DEPRECATION` | `JBSucker.setDeprecation` | Move a sucker through the deprecation lifecycle (ENABLED -> DEPRECATION_PENDING -> SENDING_DISABLED -> DEPRECATED). Checked against project owner. |
94
85
 
86
+ ## Common Permission Bundles
87
+
88
+ Typical combinations when granting operator access via `JBPermissions.setPermissionsFor`:
89
+
90
+ | Bundle | IDs | Use case |
91
+ |--------|-----|----------|
92
+ | **Deployer operator** | `QUEUE_RULESETS` (2), `SET_SPLIT_GROUPS` (18), `SET_FUND_ACCESS_LIMITS` (not in this library -- set via ruleset config) | Operator that manages project rulesets and split configuration on behalf of the owner. |
93
+ | **Token manager** | `MINT_TOKENS` (10), `BURN_TOKENS` (11), `SET_TOKEN_METADATA` (21) | Operator that manages token supply and metadata. |
94
+ | **Treasury manager** | `SEND_PAYOUTS` (5), `USE_ALLOWANCE` (17), `ADD_ACCOUNTING_CONTEXTS` (20) | Operator that manages outflows from the project treasury. |
95
+ | **Project admin** | `SET_PROJECT_URI` (7), `DEPLOY_ERC20` (8), `SET_CONTROLLER` (14), `SET_TERMINALS` (15), `SET_PRIMARY_TERMINAL` (16) | Broad administrative access without ROOT. |
96
+ | **NFT manager** | `ADJUST_721_TIERS` (22), `SET_721_METADATA` (23), `MINT_721` (24), `SET_721_DISCOUNT_PERCENT` (25) | Full control over 721 tier configuration. |
97
+ | **Cross-chain operator** | `DEPLOY_SUCKERS` (31), `MAP_SUCKER_TOKEN` (30), `SET_SUCKER_DEPRECATION` (33) | Manages cross-chain bridging lifecycle. |
98
+ | **Launch bundle** | `LAUNCH_RULESETS` (3), `SET_TERMINALS` (15) | Both are required for `launchRulesetsFor` -- ID 3 alone is insufficient. |
99
+
95
100
  ## Integration Points
96
101
 
97
102
  | Dependency | Import | Used For |
@@ -125,7 +130,7 @@ N/A -- no structs or enums. All values are `uint8 internal constant`.
125
130
  - **SET_TERMINALS (ID 15) can break a project.** Replacing the terminal list without including the current primary terminal will remove it, breaking payments and cashouts until a new primary is set.
126
131
  - **LAUNCH_RULESETS (ID 3) requires both IDs 3 and 15.** The function enforces two separate permission checks because it configures terminals in addition to launching rulesets.
127
132
  - **Holder-scoped permissions.** IDs 4 (`CASH_OUT_TOKENS`), 11 (`BURN_TOKENS`), 12 (`CLAIM_TOKENS`), and 13 (`TRANSFER_CREDITS`) are checked against the **token holder**, not the project owner. This means a holder grants an operator permission to act on the holder's own tokens.
128
- - **SET_BUYBACK_HOOK (ID 27) mismatch.** The source comment says it guards `JBBuybackHookRegistry.setHookFor` and `lockHookFor`, but those functions actually check `SET_BUYBACK_POOL` (ID 26). The ID is still granted by `REVDeployer` as an operator permission.
133
+ - **SET_BUYBACK_POOL (ID 27) vs SET_BUYBACK_HOOK (ID 28) different scopes.** ID 27 guards pool configuration (`setPoolFor`, `initializePoolFor`). ID 28 guards hook selection (`setHookFor`, `lockHookFor`). `setTwapWindowOf` uses ID 26 (`SET_BUYBACK_TWAP`). Grant all three if the operator needs full buyback management.
129
134
  - **ADD_PRICE_FEED (ID 19) is checked on JBController, not JBPrices.** The permission gate is on `JBController.addPriceFeed`, which then calls `JBPrices.addPriceFeedFor` internally.
130
135
  - **uint8 range.** IDs are `uint8` (0--255) but the packed storage is `uint256`, so the system supports up to 256 permission bits. Currently 33 are defined (1--33).
131
136
 
package/STYLE_GUIDE.md CHANGED
@@ -21,7 +21,7 @@ One contract/interface/struct/enum per file. Name the file after the type it con
21
21
 
22
22
  ```solidity
23
23
  // Contracts — pin to exact version
24
- pragma solidity 0.8.26;
24
+ pragma solidity 0.8.28;
25
25
 
26
26
  // Interfaces, structs, enums — caret for forward compatibility
27
27
  pragma solidity ^0.8.0;
@@ -313,7 +313,7 @@ Standard config across all repos:
313
313
 
314
314
  ```toml
315
315
  [profile.default]
316
- solc = '0.8.26'
316
+ solc = '0.8.28'
317
317
  evm_version = 'cancun'
318
318
  optimizer_runs = 200
319
319
  libs = ["node_modules", "lib"]
@@ -0,0 +1,300 @@
1
+ # User Journeys -- nana-permission-ids-v6
2
+
3
+ Since this is a constants-only library with no runtime behavior, these journeys describe how the permission IDs are used by actors across the ecosystem. Each journey shows the constant's role in a concrete access control scenario. All events referenced below are emitted by `JBPermissions` (in nana-core-v6), not by this library.
4
+
5
+ ---
6
+
7
+ ## Journey 1: Grant an Operator Permission to Queue Rulesets
8
+
9
+ **Entry point**: `JBPermissions.setPermissionsFor(address account, JBPermissionsData calldata permissionsData)`
10
+
11
+ **Who can call**: The `account` itself, or an existing operator that holds `ROOT` for the same `(account, projectId)` -- provided the new permissions do not include `ROOT` and the `projectId` is not the wildcard (`0`).
12
+
13
+ **Parameters**:
14
+ - `account` -- The address granting permissions (the project owner in this scenario)
15
+ - `permissionsData.operator` -- The address receiving permissions (the trusted operator)
16
+ - `permissionsData.projectId` -- The project ID the permissions are scoped to (e.g. `5`)
17
+ - `permissionsData.permissionIds` -- Array of `uint8` permission IDs to grant (e.g. `[JBPermissionIds.QUEUE_RULESETS]` which is ID 2)
18
+
19
+ ### Steps
20
+
21
+ 1. **Project owner calls `JBPermissions.setPermissionsFor`**
22
+
23
+ ```solidity
24
+ uint8[] memory ids = new uint8[](1);
25
+ ids[0] = JBPermissionIds.QUEUE_RULESETS; // ID 2
26
+ permissions.setPermissionsFor(
27
+ projectOwner,
28
+ JBPermissionsData({operator: operatorAddress, projectId: 5, permissionIds: ids})
29
+ );
30
+ ```
31
+
32
+ 2. **Operator calls `JBController.queueRulesetsOf(5, ...)`**
33
+
34
+ - Controller calls `_requirePermissionFrom(projectOwner, 5, JBPermissionIds.QUEUE_RULESETS)`
35
+ - `JBPermissions.hasPermission` checks: does `operatorAddress` have bit 2 set for `(projectOwner, projectId=5)`? Yes.
36
+ - Operation proceeds.
37
+
38
+ **State changes**:
39
+ 1. `JBPermissions.permissionsOf[operatorAddress][projectOwner][5]` -- bit 2 set to 1 (packed uint256 bitmap)
40
+
41
+ **Events**: `OperatorPermissionsSet(operator, account, projectId, permissionIds, packed, caller)` -- emitted by `JBPermissions`, not this library.
42
+
43
+ **Edge cases**:
44
+ - The operator can ONLY queue rulesets. They cannot send payouts, set terminals, or perform any other operation unless additional IDs are granted.
45
+ - Granting `QUEUE_RULESETS` with `projectId = 0` (wildcard) would allow the operator to queue rulesets for ALL projects the owner controls.
46
+ - `JBPermissions_NoZeroPermission()` -- reverts if permission ID 0 is included in the array.
47
+ - `JBPermissions_PermissionIdOutOfBounds(permissionId)` -- reverts if any permission ID exceeds 255.
48
+
49
+ ---
50
+
51
+ ## Journey 2: ROOT Permission Grants Universal Access
52
+
53
+ **Entry point**: `JBPermissions.setPermissionsFor(address account, JBPermissionsData calldata permissionsData)`
54
+
55
+ **Who can call**: Only the `account` itself can grant `ROOT`. An existing ROOT operator cannot grant ROOT to others (the function enforces this restriction explicitly).
56
+
57
+ **Parameters**:
58
+ - `account` -- The address granting ROOT (must be the caller)
59
+ - `permissionsData.operator` -- The address receiving ROOT (e.g. a trusted multisig)
60
+ - `permissionsData.projectId` -- Must be a specific project ID (not `0`)
61
+ - `permissionsData.permissionIds` -- `[JBPermissionIds.ROOT]` (ID 1)
62
+
63
+ ### Steps
64
+
65
+ 1. **Project owner calls `JBPermissions.setPermissionsFor`**
66
+
67
+ ```solidity
68
+ uint8[] memory ids = new uint8[](1);
69
+ ids[0] = JBPermissionIds.ROOT; // ID 1
70
+ permissions.setPermissionsFor(
71
+ projectOwner,
72
+ JBPermissionsData({operator: multisigAddress, projectId: 5, permissionIds: ids})
73
+ );
74
+ ```
75
+
76
+ 2. **Multisig calls any permissioned function for project 5**
77
+
78
+ - Every `_requirePermissionFrom` check includes `includeRoot: true`
79
+ - ROOT (bit 1) satisfies any permission check for `(projectOwner, projectId=5)`
80
+ - The multisig can queue rulesets, send payouts, set terminals, mint tokens, etc.
81
+
82
+ **State changes**:
83
+ 1. `JBPermissions.permissionsOf[multisigAddress][projectOwner][5]` -- bit 1 set to 1
84
+
85
+ **Events**: `OperatorPermissionsSet(operator, account, projectId, permissionIds, packed, caller)` -- emitted by `JBPermissions`, not this library.
86
+
87
+ **Edge cases**:
88
+ - `JBPermissions_CantSetRootPermissionForWildcardProject()` -- reverts if ROOT is granted with `projectId = 0`.
89
+ - `JBPermissions_Unauthorized(account, operator, projectId, permissionId)` -- reverts if a non-account caller (even a ROOT operator) tries to grant ROOT to another operator, or tries to set wildcard permissions.
90
+ - ROOT is per-project. Having ROOT for project 5 does not grant access to project 6.
91
+ - A ROOT operator can call `setPermissionsFor` on behalf of the account for non-ROOT, non-wildcard grants only. This prevents permission escalation.
92
+
93
+ ---
94
+
95
+ ## Journey 3: Token Holder Delegates Cashout Authority
96
+
97
+ **Entry point**: `JBPermissions.setPermissionsFor(address account, JBPermissionsData calldata permissionsData)`
98
+
99
+ **Who can call**: The token holder (the `account`), or an existing ROOT operator for the holder on the relevant project.
100
+
101
+ **Parameters**:
102
+ - `account` -- The token holder granting permission (NOT the project owner)
103
+ - `permissionsData.operator` -- The bot or delegate receiving cashout permission
104
+ - `permissionsData.projectId` -- The project ID the tokens belong to (e.g. `5`)
105
+ - `permissionsData.permissionIds` -- `[JBPermissionIds.CASH_OUT_TOKENS]` (ID 4)
106
+
107
+ ### Steps
108
+
109
+ 1. **Token holder calls `JBPermissions.setPermissionsFor`**
110
+
111
+ ```solidity
112
+ uint8[] memory ids = new uint8[](1);
113
+ ids[0] = JBPermissionIds.CASH_OUT_TOKENS; // ID 4
114
+ permissions.setPermissionsFor(
115
+ tokenHolder,
116
+ JBPermissionsData({operator: botAddress, projectId: 5, permissionIds: ids})
117
+ );
118
+ ```
119
+
120
+ - Note: the `account` is the **token holder**, not the project owner
121
+
122
+ 2. **Bot calls `JBMultiTerminal.cashOutTokensOf(tokenHolder, 5, ...)`**
123
+
124
+ - Terminal calls `_requirePermissionFrom(tokenHolder, 5, JBPermissionIds.CASH_OUT_TOKENS)`
125
+ - Permission check passes for `botAddress` because it has `CASH_OUT_TOKENS` for `(tokenHolder, 5)`
126
+
127
+ **State changes**:
128
+ 1. `JBPermissions.permissionsOf[botAddress][tokenHolder][5]` -- bit 4 set to 1
129
+
130
+ **Events**: `OperatorPermissionsSet(operator, account, projectId, permissionIds, packed, caller)` -- emitted by `JBPermissions`, not this library.
131
+
132
+ **Edge cases**:
133
+ - `CASH_OUT_TOKENS` (ID 4) is checked against the token holder, not the project owner. This is by design -- only the holder (or their delegates) can cash out the holder's tokens.
134
+ - The project owner CANNOT cash out another holder's tokens (unless the holder explicitly grants them `CASH_OUT_TOKENS`).
135
+ - The same holder-scoped pattern applies to `BURN_TOKENS` (11), `CLAIM_TOKENS` (12), and `TRANSFER_CREDITS` (13).
136
+
137
+ ---
138
+
139
+ ## Journey 4: SET_TERMINALS Can Break a Project
140
+
141
+ **Entry point**: `JBDirectory.setTerminalsOf(uint256 projectId, IJBTerminal[] calldata terminals)`
142
+
143
+ **Who can call**: The project owner, or an address with the owner's `SET_TERMINALS` (ID 15) permission for that project.
144
+
145
+ **Parameters**:
146
+ - `projectId` -- The project whose terminals are being updated
147
+ - `terminals` -- The new complete list of terminals (replaces the entire existing list)
148
+
149
+ ### Steps
150
+
151
+ 1. **Operator calls `JBDirectory.setTerminalsOf(5, newTerminals)`**
152
+
153
+ - Permission check: `_requirePermissionFrom(projectOwner, 5, JBPermissionIds.SET_TERMINALS)` (ID 15)
154
+ - The `newTerminals` array replaces the ENTIRE terminal list
155
+
156
+ 2. **If the new list omits the current primary terminal:**
157
+
158
+ - The primary terminal is removed from the project
159
+ - All payments to the project via `pay()` will fail (no terminal to receive them)
160
+ - All cashouts via `cashOutTokensOf()` will fail
161
+ - All payouts via `sendPayoutsOf()` will fail
162
+ - The project is effectively frozen until a new primary terminal is set
163
+
164
+ **State changes**:
165
+ 1. `JBDirectory._terminalsOf[projectId]` -- replaced with the new terminals array
166
+ 2. `JBDirectory._primaryTerminalOf[projectId][token]` -- may be implicitly cleared if the primary terminal is not in the new list
167
+
168
+ **Events**: `SetTerminals(projectId, terminals, caller)` -- emitted by `JBDirectory` (in nana-core-v6), not this library.
169
+
170
+ **Edge cases**:
171
+ - Granting `SET_TERMINALS` to an untrusted operator is dangerous. The operator can remove all terminals, bricking the project.
172
+ - `LAUNCH_RULESETS` (ID 3) also requires `SET_TERMINALS` (ID 15) because the launch function configures terminals. Granting only ID 3 without ID 15 will cause the launch to revert.
173
+ - There is no undo mechanism. Once terminals are set, another `setTerminalsOf` call is needed to restore them.
174
+
175
+ ---
176
+
177
+ ## Journey 5: Locking a Buyback Hook or Router Terminal (Permanent Action)
178
+
179
+ **Entry point (buyback hook)**:
180
+ - `JBBuybackHookRegistry.setHookFor(uint256 projectId, IJBRulesetDataHook hook)` -- configures the hook
181
+ - `JBBuybackHookRegistry.lockHookFor(uint256 projectId, IJBRulesetDataHook expectedHook)` -- permanently locks the configuration
182
+
183
+ **Who can call**: The project owner, or an address with the owner's `SET_BUYBACK_HOOK` (ID 28) permission for that project. A single permission ID gates both operations.
184
+
185
+ **Parameters**:
186
+ - `projectId` -- The project whose buyback hook is being configured or locked
187
+ - `hook` -- The buyback hook contract address (for `setHookFor` only)
188
+
189
+ ### Steps (SET_BUYBACK_HOOK example)
190
+
191
+ 1. **Operator with SET_BUYBACK_HOOK (ID 28) calls `JBBuybackHookRegistry.setHookFor(5, hookAddress)`**
192
+
193
+ - Configures the buyback hook for project 5
194
+ - This is a reversible operation (can be called again with a different hook)
195
+
196
+ 2. **Same operator calls `JBBuybackHookRegistry.lockHookFor(5, hookAddress)`**
197
+
198
+ - The `expectedHook` parameter is a race-condition guard: the call reverts with `JBBuybackHookRegistry_HookMismatch` if the on-chain hook differs from `expectedHook` at execution time
199
+ - Permanently locks the hook configuration for project 5
200
+ - No one can change the hook after locking -- not even the project owner
201
+
202
+ **State changes**:
203
+ 1. `JBBuybackHookRegistry._hookOf[projectId]` -- set to the hook address (step 1)
204
+ 2. `JBBuybackHookRegistry.hasLockedHook[projectId]` -- set to `true` (step 2, irreversible)
205
+
206
+ **Events**: Events are emitted by `JBBuybackHookRegistry` (in nana-buyback-hook-v6), not this library.
207
+
208
+ **Edge cases**:
209
+ - A single permission ID (28 or 29) gates BOTH the "set" and "lock" operations. Granting the permission implicitly trusts the operator to potentially lock the configuration.
210
+ - The locking is permanent (no unlock mechanism in the registry).
211
+ - Project owners should only grant SET_BUYBACK_HOOK (28) or SET_ROUTER_TERMINAL (29) to operators they trust not to lock prematurely.
212
+
213
+ ---
214
+
215
+ ## Journey 6: Cross-Repo Permission Usage (nana-suckers)
216
+
217
+ **Entry point**: Multiple functions across `JBSuckerRegistry` and `JBSucker`, each gated by a separate permission ID.
218
+
219
+ **Who can call**: The project owner, or an address with the corresponding permission for that project. Each sucker permission is independent.
220
+
221
+ **Parameters** (vary by operation):
222
+ - `projectId` -- The project managing cross-chain infrastructure
223
+ - `configurations` -- Sucker deployment configurations (for `deploySuckersFor`)
224
+ - `map` -- A `JBTokenMapping` struct (for `mapToken`)
225
+ - `tokens` -- Token addresses (`address[]`) for emergency recovery (for `enableEmergencyHatchFor`)
226
+ - `timestamp` -- The timestamp after which the sucker is deprecated (for `setDeprecation`)
227
+
228
+ ### Steps
229
+
230
+ 1. **Deploy suckers: `JBSuckerRegistry.deploySuckersFor(5, salt, configurations)`**
231
+ - Permission: `DEPLOY_SUCKERS` (ID 31)
232
+ - Creates sucker contracts for cross-chain bridging
233
+
234
+ 2. **Map tokens: `JBSucker.mapToken(map)`** where `map` is a `JBTokenMapping` struct
235
+ - Permission: `MAP_SUCKER_TOKEN` (ID 30)
236
+ - Maps a local ERC-20 to its remote chain counterpart
237
+ - CAUTION: once the outbox merkle tree has entries, the mapping is immutable (can only be disabled, not remapped)
238
+
239
+ 3. **Enable emergency hatch: `JBSucker.enableEmergencyHatchFor(tokens)`**
240
+ - Permission: `SUCKER_SAFETY` (ID 32)
241
+ - Allows recovery of stuck tokens via the emergency hatch
242
+
243
+ 4. **Deprecate sucker: `JBSucker.setDeprecation(timestamp)`**
244
+ - Permission: `SET_SUCKER_DEPRECATION` (ID 33)
245
+ - The timestamp after which the sucker is deprecated.
246
+
247
+ **State changes** (per step):
248
+ 1. `JBSuckerRegistry` -- deploys new sucker contracts, registers them for the project
249
+ 2. `JBSucker._remoteTokenFor[localToken]` -- set to the remote token mapping (immutable once outbox tree populated)
250
+ 3. `JBSucker._remoteTokenFor[token].enabled` -- set to `false` (bridging disabled for this token)
251
+ 4. `JBSucker._remoteTokenFor[token].emergencyHatch` -- set to `true`
252
+ 5. `JBSucker.deprecatedAfter` -- set to `timestamp` (the time after which the sucker is deprecated, or `0` to cancel a pending deprecation)
253
+
254
+ **Events**: Events are emitted by `JBSuckerRegistry` and `JBSucker` (in nana-suckers-v6), not this library.
255
+
256
+ **Edge cases**:
257
+ - Each sucker permission is independent. Having `DEPLOY_SUCKERS` does not grant `MAP_SUCKER_TOKEN` or `SUCKER_SAFETY`.
258
+ - `MAP_SUCKER_TOKEN` is especially sensitive because token mappings become immutable once the outbox tree has entries.
259
+ - `SUCKER_SAFETY` should be granted sparingly -- the emergency hatch is a last-resort recovery mechanism.
260
+ - All four sucker permissions are checked against the project owner, not a token holder.
261
+
262
+ ---
263
+
264
+ ## Permission ID Reference
265
+
266
+ | ID | Constant | Gated function(s) | Scope |
267
+ |----|----------|-------------------|-------|
268
+ | 1 | `ROOT` | All permissioned functions | Project owner |
269
+ | 2 | `QUEUE_RULESETS` | `JBController.queueRulesetsOf` | Project owner |
270
+ | 3 | `LAUNCH_RULESETS` | `JBController.launchRulesetsFor` | Project owner |
271
+ | 4 | `CASH_OUT_TOKENS` | `JBMultiTerminal.cashOutTokensOf` | Token holder |
272
+ | 5 | `SEND_PAYOUTS` | `JBMultiTerminal.sendPayoutsOf` | Project owner |
273
+ | 6 | `MIGRATE_TERMINAL` | `JBMultiTerminal.migrateBalanceOf` | Project owner |
274
+ | 7 | `SET_PROJECT_URI` | `JBController.setUriOf` | Project owner |
275
+ | 8 | `DEPLOY_ERC20` | `JBController.deployERC20For` | Project owner |
276
+ | 9 | `SET_TOKEN` | `JBController.setTokenFor` | Project owner |
277
+ | 10 | `MINT_TOKENS` | `JBController.mintTokensOf` | Project owner |
278
+ | 11 | `BURN_TOKENS` | `JBController.burnTokensOf` | Token holder |
279
+ | 12 | `CLAIM_TOKENS` | `JBController.claimTokensFor` | Token holder |
280
+ | 13 | `TRANSFER_CREDITS` | `JBController.transferCreditsFrom` | Token holder |
281
+ | 14 | `SET_CONTROLLER` | `JBDirectory.setControllerOf` | Project owner |
282
+ | 15 | `SET_TERMINALS` | `JBDirectory.setTerminalsOf` | Project owner |
283
+ | 16 | `SET_PRIMARY_TERMINAL` | `JBDirectory.setPrimaryTerminalOf` | Project owner |
284
+ | 17 | `USE_ALLOWANCE` | `JBMultiTerminal.useAllowanceOf` | Project owner |
285
+ | 18 | `SET_SPLIT_GROUPS` | `JBController.setSplitGroupsOf` | Project owner |
286
+ | 19 | `ADD_PRICE_FEED` | `JBController.addPriceFeedFor` | Project owner |
287
+ | 20 | `ADD_ACCOUNTING_CONTEXTS` | `JBMultiTerminal.addAccountingContextsFor` | Project owner |
288
+ | 21 | `SET_TOKEN_METADATA` | `JBController.setTokenMetadataOf` | Project owner |
289
+ | 22 | `ADJUST_721_TIERS` | `JB721TiersHook.adjustTiers` | Project owner |
290
+ | 23 | `SET_721_METADATA` | `JB721TiersHook.setMetadata` | Project owner |
291
+ | 24 | `MINT_721` | `JB721TiersHook.mintFor` | Project owner |
292
+ | 25 | `SET_721_DISCOUNT_PERCENT` | `JB721TiersHook.setDiscountPercentOf` | Project owner |
293
+ | 26 | `SET_BUYBACK_TWAP` | `JBBuybackHook.setTwapWindowOf` | Project owner |
294
+ | 27 | `SET_BUYBACK_POOL` | `JBBuybackHook.setPoolFor` | Project owner |
295
+ | 28 | `SET_BUYBACK_HOOK` | `JBBuybackHookRegistry.setHookFor` + `lockHookFor` | Project owner |
296
+ | 29 | `SET_ROUTER_TERMINAL` | `JBRouterTerminalRegistry.setTerminalFor` + `lockTerminalFor` | Project owner |
297
+ | 30 | `MAP_SUCKER_TOKEN` | `JBSucker.mapToken` | Project owner |
298
+ | 31 | `DEPLOY_SUCKERS` | `JBSuckerRegistry.deploySuckersFor` | Project owner |
299
+ | 32 | `SUCKER_SAFETY` | `JBSucker.enableEmergencyHatchFor` | Project owner |
300
+ | 33 | `SET_SUCKER_DEPRECATION` | `JBSucker.setDeprecation` | Project owner |
package/foundry.toml CHANGED
@@ -1,5 +1,5 @@
1
1
  [profile.default]
2
- solc = '0.8.26'
2
+ solc = '0.8.28'
3
3
  evm_version = 'cancun'
4
4
  optimizer_runs = 200
5
5
  libs = ["node_modules", "lib"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananapus/permission-ids-v6",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,11 +28,11 @@ library JBPermissionIds {
28
28
  uint8 internal constant SET_PRIMARY_TERMINAL = 16; // Permission to call `JBDirectory.setPrimaryTerminalOf`.
29
29
  uint8 internal constant USE_ALLOWANCE = 17; // Permission to call `JBMultiTerminal.useAllowanceOf`.
30
30
  uint8 internal constant SET_SPLIT_GROUPS = 18; // Permission to call `JBController.setSplitGroupsOf`.
31
- uint8 internal constant ADD_PRICE_FEED = 19; // Permission to call `JBPrices.addPriceFeedFor`.
31
+ uint8 internal constant ADD_PRICE_FEED = 19; // Permission to call `JBController.addPriceFeedFor`.
32
32
  uint8 internal constant ADD_ACCOUNTING_CONTEXTS = 20; // Permission to call
33
33
  // `JBMultiTerminal.addAccountingContextsFor`.
34
34
  uint8 internal constant SET_TOKEN_METADATA = 21; // Permission to call
35
- // `JBController.setMetadataOf`.
35
+ // `JBController.setTokenMetadataOf`.
36
36
 
37
37
  /* Used by `nana-721-hook`: https://github.com/Bananapus/nana-721-hook */
38
38
  uint8 internal constant ADJUST_721_TIERS = 22; // Permission to call `JB721TiersHook.adjustTiers`.