@bananapus/permission-ids-v6 0.0.8 → 0.0.10

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
@@ -10,7 +10,7 @@ There are no ownable contracts, no upgrade mechanisms, and no mutable state. The
10
10
 
11
11
  ## Permission IDs
12
12
 
13
- All 32 defined permission IDs and what they control:
13
+ All 33 defined permission IDs and what they control:
14
14
 
15
15
  | ID | Constant | Used By | What It Controls |
16
16
  |----|----------|---------|-----------------|
@@ -32,22 +32,23 @@ All 32 defined permission IDs and what they control:
32
32
  | 16 | `SET_PRIMARY_TERMINAL` | nana-core | `JBDirectory.setPrimaryTerminalOf` -- set the primary terminal for a token. |
33
33
  | 17 | `USE_ALLOWANCE` | nana-core | `JBMultiTerminal.useAllowanceOf` -- spend surplus allowance to an arbitrary address. |
34
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. |
35
+ | 19 | `ADD_PRICE_FEED` | nana-core | `JBController.addPriceFeed` (which internally calls `JBPrices.addPriceFeedFor`) -- add a price feed for a project. |
36
36
  | 20 | `ADD_ACCOUNTING_CONTEXTS` | nana-core | `JBMultiTerminal.addAccountingContextsFor` -- add accepted tokens to a terminal. |
37
- | 21 | `ADJUST_721_TIERS` | nana-721-hook | `JB721TiersHook.adjustTiers` -- add or remove NFT tiers. |
38
- | 22 | `SET_721_METADATA` | nana-721-hook | `JB721TiersHook.setMetadata` -- set NFT metadata URIs. |
39
- | 23 | `MINT_721` | nana-721-hook | `JB721TiersHook.mintFor` -- manually mint NFTs to a beneficiary. |
40
- | 24 | `SET_721_DISCOUNT_PERCENT` | nana-721-hook | `JB721TiersHook.setDiscountPercentOf` -- set discount percent on NFT tiers. |
41
- | 25 | `SET_BUYBACK_TWAP` | nana-buyback-hook | `JBBuybackHook.setTwapWindowOf` -- configure the TWAP oracle window. |
42
- | 26 | `SET_BUYBACK_POOL` | nana-buyback-hook | `JBBuybackHook.setPoolFor` -- set the Uniswap pool for buybacks. |
43
- | 27 | `SET_BUYBACK_HOOK` | nana-buyback-hook | `JBBuybackHookRegistry.setHookFor` and `lockHookFor` -- configure and permanently lock the buyback hook. |
44
- | 28 | `SET_ROUTER_TERMINAL` | nana-router-terminal | `JBRouterTerminalRegistry.setTerminalFor` and `lockTerminalFor` -- configure and permanently lock the router terminal. |
45
- | 29 | `MAP_SUCKER_TOKEN` | nana-suckers | `JBSucker.mapToken` -- map an ERC-20 to its remote chain counterpart. Immutable once the outbox tree has entries. |
46
- | 30 | `DEPLOY_SUCKERS` | nana-suckers | `JBSuckerRegistry.deploySuckersFor` -- deploy sucker contracts for cross-chain bridging. |
47
- | 31 | `SUCKER_SAFETY` | nana-suckers | `JBSucker.enableEmergencyHatchFor` -- enable the emergency hatch to recover stuck tokens. |
48
- | 32 | `SET_SUCKER_DEPRECATION` | nana-suckers | `JBSucker.setDeprecation` -- set deprecation status (ENABLED, DEPRECATION_PENDING, SENDING_DISABLED, DEPRECATED). |
49
-
50
- IDs 0 and 33-255 are unused. ID 0 is reserved and cannot be set. IDs 33-255 are available for future ecosystem extensions.
37
+ | 21 | `SET_TOKEN_METADATA` | nana-core | `JBController.setTokenMetadataOf` -- 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). |
50
+
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.
51
52
 
52
53
  ## ROOT Permission
53
54
 
@@ -88,8 +89,8 @@ Some permissions warrant extra caution when granting:
88
89
  - **`ROOT` (1):** Full access to all gated functions for a project.
89
90
  - **`SET_TERMINALS` (15):** Can remove the primary terminal, breaking payments and cashouts.
90
91
  - **`USE_ALLOWANCE` (17):** Can send surplus funds to any address.
91
- - **`SET_BUYBACK_HOOK` (27):** Can permanently lock the buyback hook configuration.
92
- - **`SET_ROUTER_TERMINAL` (28):** Can permanently lock the router terminal configuration.
92
+ - **`SET_BUYBACK_HOOK` (28):** Can permanently lock the buyback hook configuration.
93
+ - **`SET_ROUTER_TERMINAL` (29):** Can permanently lock the router terminal configuration.
93
94
  - **`MINT_TOKENS` (10):** Can inflate token supply (subject to ruleset allowing owner minting).
94
95
 
95
96
  ## Holder vs. Owner Permissions
package/ARCHITECTURE.md CHANGED
@@ -33,20 +33,21 @@ src/
33
33
  | 16 | `SET_PRIMARY_TERMINAL` | nana-core | `JBDirectory.setPrimaryTerminalOf` |
34
34
  | 17 | `USE_ALLOWANCE` | nana-core | `JBMultiTerminal.useAllowanceOf` |
35
35
  | 18 | `SET_SPLIT_GROUPS` | nana-core | `JBController.setSplitGroupsOf` |
36
- | 19 | `ADD_PRICE_FEED` | nana-core | `JBPrices.addPriceFeedFor` |
36
+ | 19 | `ADD_PRICE_FEED` | nana-core | `JBController.addPriceFeed` |
37
37
  | 20 | `ADD_ACCOUNTING_CONTEXTS` | nana-core | `JBMultiTerminal.addAccountingContextsFor` |
38
- | 21 | `ADJUST_721_TIERS` | nana-721-hook | `JB721TiersHook.adjustTiers` |
39
- | 22 | `SET_721_METADATA` | nana-721-hook | `JB721TiersHook.setMetadata` |
40
- | 23 | `MINT_721` | nana-721-hook | `JB721TiersHook.mintFor` |
41
- | 24 | `SET_721_DISCOUNT_PERCENT` | nana-721-hook | `JB721TiersHook.setDiscountPercentOf` |
42
- | 25 | `SET_BUYBACK_TWAP` | nana-buyback-hook | `JBBuybackHook.setTwapWindowOf` |
43
- | 26 | `SET_BUYBACK_POOL` | nana-buyback-hook | `JBBuybackHook.setPoolFor` |
44
- | 27 | `SET_BUYBACK_HOOK` | nana-buyback-hook | `JBBuybackHookRegistry.setHookFor` + `lockHookFor` |
45
- | 28 | `SET_ROUTER_TERMINAL` | nana-router-terminal | `JBRouterTerminalRegistry.setTerminalFor` + `lockTerminalFor` |
46
- | 29 | `MAP_SUCKER_TOKEN` | nana-suckers | `JBSucker.mapToken` |
47
- | 30 | `DEPLOY_SUCKERS` | nana-suckers | `JBSuckerRegistry.deploySuckersFor` |
48
- | 31 | `SUCKER_SAFETY` | nana-suckers | `JBSucker.enableEmergencyHatchFor` |
49
- | 32 | `SET_SUCKER_DEPRECATION` | nana-suckers | `JBSucker.setDeprecation` |
38
+ | 21 | `SET_TOKEN_METADATA` | nana-core | `JBController.setTokenMetadataOf` |
39
+ | 22 | `ADJUST_721_TIERS` | nana-721-hook | `JB721TiersHook.adjustTiers` |
40
+ | 23 | `SET_721_METADATA` | nana-721-hook | `JB721TiersHook.setMetadata` |
41
+ | 24 | `MINT_721` | nana-721-hook | `JB721TiersHook.mintFor` |
42
+ | 25 | `SET_721_DISCOUNT_PERCENT` | nana-721-hook | `JB721TiersHook.setDiscountPercentOf` |
43
+ | 26 | `SET_BUYBACK_TWAP` | nana-buyback-hook | `JBBuybackHook.setTwapWindowOf` |
44
+ | 27 | `SET_BUYBACK_POOL` | nana-buyback-hook | `JBBuybackHook.setPoolFor` |
45
+ | 28 | `SET_BUYBACK_HOOK` | nana-buyback-hook | `JBBuybackHookRegistry.setHookFor` + `lockHookFor` |
46
+ | 29 | `SET_ROUTER_TERMINAL` | nana-router-terminal | `JBRouterTerminalRegistry.setTerminalFor` + `lockTerminalFor` |
47
+ | 30 | `MAP_SUCKER_TOKEN` | nana-suckers | `JBSucker.mapToken` |
48
+ | 31 | `DEPLOY_SUCKERS` | nana-suckers | `JBSuckerRegistry.deploySuckersFor` |
49
+ | 32 | `SUCKER_SAFETY` | nana-suckers | `JBSucker.enableEmergencyHatchFor` |
50
+ | 33 | `SET_SUCKER_DEPRECATION` | nana-suckers | `JBSucker.setDeprecation` |
50
51
 
51
52
  ## Dependencies
52
53
 
@@ -0,0 +1,149 @@
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
+ ## Scope
6
+
7
+ **In scope:**
8
+ ```
9
+ src/JBPermissionIds.sol # Constants library (~67 lines, 33 permission IDs)
10
+ ```
11
+
12
+ **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.
13
+
14
+ ## Architecture
15
+
16
+ `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.
17
+
18
+ ### Permission System Overview
19
+
20
+ ```
21
+ permissionsOf[operator][account][projectId] => uint256 (one bit per permission ID)
22
+ ```
23
+
24
+ - **Bit 0 (ID 0):** Reserved, cannot be set. `JBPermissions` reverts if bit 0 is included.
25
+ - **Bit 1 (ID 1, ROOT):** Grants all permissions across all contracts. Cannot be granted for wildcard `projectId = 0`.
26
+ - **Bits 2-33:** Individual permissions, each gating a specific function (or set of functions) in the ecosystem.
27
+ - **Bits 34-255:** Unassigned, available for future extensions.
28
+
29
+ ### All Permission IDs
30
+
31
+ | ID | Constant | Gated Function(s) | Checked Against |
32
+ |----|----------|-------------------|-----------------|
33
+ | 1 | `ROOT` | All permissions (implicit) | Project owner |
34
+ | 2 | `QUEUE_RULESETS` | `JBController.queueRulesetsOf` | Project owner |
35
+ | 3 | `LAUNCH_RULESETS` | `JBController.launchRulesetsFor` (also needs SET_TERMINALS) | Project owner |
36
+ | 4 | `CASH_OUT_TOKENS` | `JBMultiTerminal.cashOutTokensOf` | **Token holder** |
37
+ | 5 | `SEND_PAYOUTS` | `JBMultiTerminal.sendPayoutsOf` | Project owner |
38
+ | 6 | `MIGRATE_TERMINAL` | `JBMultiTerminal.migrateBalanceOf` | Project owner |
39
+ | 7 | `SET_PROJECT_URI` | `JBController.setUriOf` | Project owner |
40
+ | 8 | `DEPLOY_ERC20` | `JBController.deployERC20For` | Project owner |
41
+ | 9 | `SET_TOKEN` | `JBController.setTokenFor` | Project owner |
42
+ | 10 | `MINT_TOKENS` | `JBController.mintTokensOf` | Project owner |
43
+ | 11 | `BURN_TOKENS` | `JBController.burnTokensOf` | **Token holder** |
44
+ | 12 | `CLAIM_TOKENS` | `JBController.claimTokensFor` | **Token holder** |
45
+ | 13 | `TRANSFER_CREDITS` | `JBController.transferCreditsFrom` | **Token holder** |
46
+ | 14 | `SET_CONTROLLER` | `JBDirectory.setControllerOf` | Project owner |
47
+ | 15 | `SET_TERMINALS` | `JBDirectory.setTerminalsOf` (WARNING: can remove primary terminal) | Project owner |
48
+ | 16 | `SET_PRIMARY_TERMINAL` | `JBDirectory.setPrimaryTerminalOf` | Project owner |
49
+ | 17 | `USE_ALLOWANCE` | `JBMultiTerminal.useAllowanceOf` | Project owner |
50
+ | 18 | `SET_SPLIT_GROUPS` | `JBController.setSplitGroupsOf` | Project owner |
51
+ | 19 | `ADD_PRICE_FEED` | `JBController.addPriceFeed` (not `JBPrices` directly) | Project owner |
52
+ | 20 | `ADD_ACCOUNTING_CONTEXTS` | `JBMultiTerminal.addAccountingContextsFor` | Project owner |
53
+ | 21 | `SET_TOKEN_METADATA` | `JBController.setTokenMetadataOf` | Project owner |
54
+ | 22 | `ADJUST_721_TIERS` | `JB721TiersHook.adjustTiers` | Hook owner |
55
+ | 23 | `SET_721_METADATA` | `JB721TiersHook.setMetadata` | Hook owner |
56
+ | 24 | `MINT_721` | `JB721TiersHook.mintFor` | Hook owner |
57
+ | 25 | `SET_721_DISCOUNT_PERCENT` | `JB721TiersHook.setDiscountPercentOf` | Hook owner |
58
+ | 26 | `SET_BUYBACK_TWAP` | `JBBuybackHook.setTwapWindowOf` | Project owner |
59
+ | 27 | `SET_BUYBACK_POOL` | `JBBuybackHook.setPoolFor` | Project owner |
60
+ | 28 | `SET_BUYBACK_HOOK` | `JBBuybackHookRegistry.setHookFor` + `lockHookFor` | Project owner |
61
+ | 29 | `SET_ROUTER_TERMINAL` | `JBRouterTerminalRegistry.setTerminalFor` + `lockTerminalFor` | Project owner |
62
+ | 30 | `MAP_SUCKER_TOKEN` | `JBSucker.mapToken` | Project owner |
63
+ | 31 | `DEPLOY_SUCKERS` | `JBSuckerRegistry.deploySuckersFor` | Project owner |
64
+ | 32 | `SUCKER_SAFETY` | `JBSucker.enableEmergencyHatchFor` | Project owner |
65
+ | 33 | `SET_SUCKER_DEPRECATION` | `JBSucker.setDeprecation` | Project owner |
66
+
67
+ ## Priority Audit Areas
68
+
69
+ ### 1. ID Uniqueness (Highest Priority)
70
+
71
+ 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:
72
+
73
+ - All 33 constants have distinct values.
74
+ - Values are sequential from 1 to 33 with no gaps and no duplicates.
75
+ - No other file in the ecosystem defines additional permission ID constants that could collide with these.
76
+
77
+ ### 2. ID-to-Function Mapping Correctness
78
+
79
+ Each constant's doc comment claims it gates a specific function. Verify against the actual source code of each consuming contract:
80
+
81
+ - **nana-core-v6**: IDs 2-21 should match the `_requirePermissionFrom` calls in `JBController`, `JBMultiTerminal`, and `JBDirectory`.
82
+ - **nana-721-hook-v6**: IDs 22-25 should match permission checks in `JB721TiersHook`.
83
+ - **nana-buyback-hook-v6**: IDs 26-28 should match permission checks in `JBBuybackHook` and `JBBuybackHookRegistry`.
84
+ - **nana-router-terminal-v6**: ID 29 should match permission checks in `JBRouterTerminalRegistry`.
85
+ - **nana-suckers-v6**: IDs 30-33 should match permission checks in `JBSucker` and `JBSuckerRegistry`.
86
+
87
+ Known discrepancy to investigate: **SET_BUYBACK_HOOK (ID 28)** -- the source comment says it gates `JBBuybackHookRegistry.setHookFor` and `lockHookFor`, but those functions may actually check `SET_BUYBACK_POOL` (ID 27) instead. Verify which ID is actually checked in the registry code and whether this mismatch causes any practical issue.
88
+
89
+ ### 3. Holder-Scoped vs Owner-Scoped Permissions
90
+
91
+ Four permissions are checked against the **token holder**, not the project owner:
92
+
93
+ - `CASH_OUT_TOKENS` (4) -- holder authorizes cashout of their tokens
94
+ - `BURN_TOKENS` (11) -- holder authorizes burning their tokens
95
+ - `CLAIM_TOKENS` (12) -- holder authorizes claiming their credits as ERC-20
96
+ - `TRANSFER_CREDITS` (13) -- holder authorizes transferring their credit balance
97
+
98
+ 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).
99
+
100
+ ### 4. Dual-Purpose Permission IDs
101
+
102
+ Two IDs intentionally gate both a "set" and a "lock" operation:
103
+
104
+ - **SET_BUYBACK_HOOK (28)**: Gates both `setHookFor` (configurable) and `lockHookFor` (permanent). An operator with this permission can permanently lock the hook configuration.
105
+ - **SET_ROUTER_TERMINAL (29)**: Gates both `setTerminalFor` (configurable) and `lockTerminalFor` (permanent). An operator with this permission can permanently lock the terminal configuration.
106
+
107
+ 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.
108
+
109
+ ### 5. ROOT Permission Safety
110
+
111
+ ROOT (ID 1) is the superadmin permission. The `JBPermissions` contract implements critical safety rails:
112
+
113
+ - ROOT cannot be granted for wildcard `projectId = 0` (would grant root across all projects)
114
+ - A ROOT operator can call `setPermissionsFor` on behalf of the account but cannot grant ROOT to others
115
+ - ROOT cannot be included when setting wildcard project permissions
116
+
117
+ Verify these constraints are enforced in `JBPermissions`, not in this library (this library only defines the constant).
118
+
119
+ ### 6. SET_TERMINALS (ID 15) Risk
120
+
121
+ 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:
122
+
123
+ - Granting `SET_TERMINALS` alone is sufficient to replace the entire terminal list, potentially breaking a project.
124
+ - Granting `LAUNCH_RULESETS` without also granting `SET_TERMINALS` will cause `launchRulesetsFor` to revert (dual permission check).
125
+
126
+ ## Invariants to Verify
127
+
128
+ 1. **Uniqueness**: All 33 constants have unique values in the range [1, 33].
129
+ 2. **Completeness**: Every `_requirePermissionFrom` call in the ecosystem uses one of these constants (no magic numbers).
130
+ 3. **Type consistency**: All constants are `uint8`, matching the parameter type of `JBPermissions.hasPermission`.
131
+ 4. **No ID 0**: No constant has value 0 (reserved and forbidden by `JBPermissions`).
132
+ 5. **Sequential assignment**: IDs are assigned 1 through 33 with no gaps.
133
+
134
+ ## Testing Setup
135
+
136
+ 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.
137
+
138
+ ```bash
139
+ cd nana-permission-ids-v6
140
+ forge build # Ensures the library compiles
141
+ ```
142
+
143
+ To verify ID usage across the ecosystem:
144
+ ```bash
145
+ # Search for permission ID usage in consuming repos
146
+ 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/
147
+ ```
148
+
149
+ Go break it.
package/CHANGE_LOG.md ADDED
@@ -0,0 +1,142 @@
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
+ ---
6
+
7
+ ## 1. Breaking Changes
8
+
9
+ ### All numeric IDs shifted
10
+
11
+ 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.**
12
+
13
+ | Permission | v5 ID | v6 ID |
14
+ |---|---|---|
15
+ | `ROOT` | 1 | 1 |
16
+ | `QUEUE_RULESETS` | 2 | 2 |
17
+ | `CASH_OUT_TOKENS` | 3 | 4 |
18
+ | `SEND_PAYOUTS` | 4 | 5 |
19
+ | `MIGRATE_TERMINAL` | 5 | 6 |
20
+ | `SET_PROJECT_URI` | 6 | 7 |
21
+ | `DEPLOY_ERC20` | 7 | 8 |
22
+ | `SET_TOKEN` | 8 | 9 |
23
+ | `MINT_TOKENS` | 9 | 10 |
24
+ | `BURN_TOKENS` | 10 | 11 |
25
+ | `CLAIM_TOKENS` | 11 | 12 |
26
+ | `TRANSFER_CREDITS` | 12 | 13 |
27
+ | `SET_CONTROLLER` | 13 | 14 |
28
+ | `SET_TERMINALS` | 14 | 15 |
29
+ | `SET_PRIMARY_TERMINAL` | 15 | 16 |
30
+ | `USE_ALLOWANCE` | 16 | 17 |
31
+ | `SET_SPLIT_GROUPS` | 17 | 18 |
32
+ | `ADD_PRICE_FEED` | 18 | 19 |
33
+ | `ADD_ACCOUNTING_CONTEXTS` | 19 | 20 |
34
+ | `ADJUST_721_TIERS` | 20 | 22 |
35
+ | `SET_721_METADATA` | 21 | 23 |
36
+ | `MINT_721` | 22 | 24 |
37
+ | `SET_721_DISCOUNT_PERCENT` | 23 | 25 |
38
+ | `SET_BUYBACK_TWAP` | 24 | 26 |
39
+ | `SET_BUYBACK_POOL` | 25 | 27 |
40
+ | `MAP_SUCKER_TOKEN` | 28 | 30 |
41
+ | `DEPLOY_SUCKERS` | 29 | 31 |
42
+ | `SUCKER_SAFETY` | 30 | 32 |
43
+
44
+ ### `QUEUE_RULESETS` split into two permissions
45
+
46
+ In v5, `QUEUE_RULESETS` (2) granted permission to call both `JBController.queueRulesetsOf` and `JBController.launchRulesetsFor`. In v6, these are separate:
47
+
48
+ - `QUEUE_RULESETS` (2) -- only `JBController.queueRulesetsOf`
49
+ - `LAUNCH_RULESETS` (3) -- only `JBController.launchRulesetsFor`
50
+
51
+ ### `SUCKER_SAFETY` split into two permissions
52
+
53
+ In v5, `SUCKER_SAFETY` (30) granted permission to call both `BPSucker.enableEmergencyHatchFor` and `BPSucker.setDeprecation`. In v6, these are separate:
54
+
55
+ - `SUCKER_SAFETY` (32) -- only `JBSucker.enableEmergencyHatchFor`
56
+ - `SET_SUCKER_DEPRECATION` (33) -- only `JBSucker.setDeprecation`
57
+
58
+ ### Swap terminal permissions removed
59
+
60
+ The following permissions from `nana-swap-terminal` no longer exist in v6:
61
+
62
+ | Removed | v5 ID | Notes |
63
+ |---|---|---|
64
+ | `ADD_SWAP_TERMINAL_POOL` | 26 | Was for `JBSwapTerminal.addDefaultPool` |
65
+ | `ADD_SWAP_TERMINAL_TWAP_PARAMS` | 27 | Was for `JBSwapTerminal.addTwapParamsFor` |
66
+
67
+ ### Contract prefix rename (suckers)
68
+
69
+ Sucker contract references changed from `BP*` to `JB*`:
70
+
71
+ - `BPSucker` → `JBSucker`
72
+ - `BPSuckerRegistry` → `JBSuckerRegistry`
73
+
74
+ ### `SET_BUYBACK_TWAP` comment narrowed
75
+
76
+ In v5, the comment stated this gates both `JBBuybackHook.setTwapWindowOf` and `JBBuybackHook.setTwapSlippageToleranceOf`. In v6, the comment only mentions `JBBuybackHook.setTwapWindowOf`.
77
+
78
+ ---
79
+
80
+ ## 2. New Features
81
+
82
+ ### `LAUNCH_RULESETS` (3)
83
+
84
+ New permission split from `QUEUE_RULESETS`. Gates `JBController.launchRulesetsFor` independently.
85
+
86
+ ### `SET_TOKEN_METADATA` (21)
87
+
88
+ New core permission. Gates `JBController.setMetadataOf` for setting project token metadata.
89
+
90
+ ### `SET_BUYBACK_HOOK` (28)
91
+
92
+ New buyback hook permission. Gates both `JBBuybackHookRegistry.setHookFor` and `JBBuybackHookRegistry.lockHookFor`. Note: granting this permission allows the operator to permanently lock the hook configuration.
93
+
94
+ ### `SET_ROUTER_TERMINAL` (29)
95
+
96
+ New router terminal permission. Gates both `JBRouterTerminalRegistry.setTerminalFor` and `JBRouterTerminalRegistry.lockTerminalFor`. Note: granting this permission allows the operator to permanently lock the terminal configuration.
97
+
98
+ ### `SET_SUCKER_DEPRECATION` (33)
99
+
100
+ New permission split from `SUCKER_SAFETY`. Gates `JBSucker.setDeprecation` independently.
101
+
102
+ ---
103
+
104
+ ## 3. Migration Table
105
+
106
+ | v5 Name | v5 ID | v6 Name | v6 ID | Change |
107
+ |---|---|---|---|---|
108
+ | `ROOT` | 1 | `ROOT` | 1 | Unchanged |
109
+ | `QUEUE_RULESETS` | 2 | `QUEUE_RULESETS` | 2 | Narrowed (no longer includes launch) |
110
+ | -- | -- | `LAUNCH_RULESETS` | 3 | **New** (split from `QUEUE_RULESETS`) |
111
+ | `CASH_OUT_TOKENS` | 3 | `CASH_OUT_TOKENS` | 4 | ID changed |
112
+ | `SEND_PAYOUTS` | 4 | `SEND_PAYOUTS` | 5 | ID changed |
113
+ | `MIGRATE_TERMINAL` | 5 | `MIGRATE_TERMINAL` | 6 | ID changed |
114
+ | `SET_PROJECT_URI` | 6 | `SET_PROJECT_URI` | 7 | ID changed |
115
+ | `DEPLOY_ERC20` | 7 | `DEPLOY_ERC20` | 8 | ID changed |
116
+ | `SET_TOKEN` | 8 | `SET_TOKEN` | 9 | ID changed |
117
+ | `MINT_TOKENS` | 9 | `MINT_TOKENS` | 10 | ID changed |
118
+ | `BURN_TOKENS` | 10 | `BURN_TOKENS` | 11 | ID changed |
119
+ | `CLAIM_TOKENS` | 11 | `CLAIM_TOKENS` | 12 | ID changed |
120
+ | `TRANSFER_CREDITS` | 12 | `TRANSFER_CREDITS` | 13 | ID changed |
121
+ | `SET_CONTROLLER` | 13 | `SET_CONTROLLER` | 14 | ID changed |
122
+ | `SET_TERMINALS` | 14 | `SET_TERMINALS` | 15 | ID changed |
123
+ | `SET_PRIMARY_TERMINAL` | 15 | `SET_PRIMARY_TERMINAL` | 16 | ID changed |
124
+ | `USE_ALLOWANCE` | 16 | `USE_ALLOWANCE` | 17 | ID changed |
125
+ | `SET_SPLIT_GROUPS` | 17 | `SET_SPLIT_GROUPS` | 18 | ID changed |
126
+ | `ADD_PRICE_FEED` | 18 | `ADD_PRICE_FEED` | 19 | ID changed |
127
+ | `ADD_ACCOUNTING_CONTEXTS` | 19 | `ADD_ACCOUNTING_CONTEXTS` | 20 | ID changed |
128
+ | -- | -- | `SET_TOKEN_METADATA` | 21 | **New** |
129
+ | `ADJUST_721_TIERS` | 20 | `ADJUST_721_TIERS` | 22 | ID changed |
130
+ | `SET_721_METADATA` | 21 | `SET_721_METADATA` | 23 | ID changed |
131
+ | `MINT_721` | 22 | `MINT_721` | 24 | ID changed |
132
+ | `SET_721_DISCOUNT_PERCENT` | 23 | `SET_721_DISCOUNT_PERCENT` | 25 | ID changed |
133
+ | `SET_BUYBACK_TWAP` | 24 | `SET_BUYBACK_TWAP` | 26 | ID changed, comment narrowed |
134
+ | `SET_BUYBACK_POOL` | 25 | `SET_BUYBACK_POOL` | 27 | ID changed |
135
+ | `ADD_SWAP_TERMINAL_POOL` | 26 | -- | -- | **Removed** |
136
+ | `ADD_SWAP_TERMINAL_TWAP_PARAMS` | 27 | -- | -- | **Removed** |
137
+ | -- | -- | `SET_BUYBACK_HOOK` | 28 | **New** |
138
+ | -- | -- | `SET_ROUTER_TERMINAL` | 29 | **New** |
139
+ | `MAP_SUCKER_TOKEN` | 28 | `MAP_SUCKER_TOKEN` | 30 | ID changed, `BPSucker` → `JBSucker` |
140
+ | `DEPLOY_SUCKERS` | 29 | `DEPLOY_SUCKERS` | 31 | ID changed, `BPSuckerRegistry` → `JBSuckerRegistry` |
141
+ | `SUCKER_SAFETY` | 30 | `SUCKER_SAFETY` | 32 | ID changed, narrowed (no longer includes deprecation) |
142
+ | -- | -- | `SET_SUCKER_DEPRECATION` | 33 | **New** (split from `SUCKER_SAFETY`) |
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Juicebox Permission IDs
2
2
 
3
- The single source of truth for access control across the Juicebox V6 ecosystem. This library defines 32 `uint8` constants -- one for each permission ID used with [`JBPermissions`](https://github.com/Bananapus/nana-core-v6/blob/main/src/JBPermissions.sol) -- ensuring every contract references the same IDs.
3
+ The single source of truth for access control across the Juicebox V6 ecosystem. This library defines 33 `uint8` constants -- one for each permission ID used with [`JBPermissions`](https://github.com/Bananapus/nana-core-v6/blob/main/src/JBPermissions.sol) -- ensuring every contract references the same IDs.
4
4
 
5
5
  ## How permissions work
6
6
 
@@ -16,7 +16,7 @@ permissionsOf[operator][account][projectId] => uint256 (packed bits)
16
16
 
17
17
  | Contract | Description |
18
18
  |----------|-------------|
19
- | `JBPermissionIds` | Solidity library with 32 `uint8 internal constant` permission IDs (values 1--32). No state, no functions, no dependencies. Pragma `^0.8.0` for maximum compatibility. |
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
21
  ## All permission IDs
22
22
 
@@ -26,7 +26,7 @@ permissionsOf[operator][account][projectId] => uint256 (packed bits)
26
26
  |----|------|-------------|
27
27
  | 1 | `ROOT` | Grants **all** permissions across every contract. An operator with ROOT can call any permissioned function on behalf of the account. Must be granted with extreme care. See [Gotchas](#gotchas) for restrictions. |
28
28
 
29
- ### Core (IDs 2--20) -- [nana-core-v6](https://github.com/Bananapus/nana-core-v6)
29
+ ### Core (IDs 2--21) -- [nana-core-v6](https://github.com/Bananapus/nana-core-v6)
30
30
 
31
31
  | ID | Name | Checked in | Description |
32
32
  |----|------|------------|-------------|
@@ -49,38 +49,39 @@ permissionsOf[operator][account][projectId] => uint256 (packed bits)
49
49
  | 18 | `SET_SPLIT_GROUPS` | `JBController.setSplitGroupsOf` | Set a project's split groups (how payouts and reserved tokens are distributed). |
50
50
  | 19 | `ADD_PRICE_FEED` | `JBController.addPriceFeed` | Add a price feed for a project. The controller checks this permission before calling `JBPrices.addPriceFeedFor`. |
51
51
  | 20 | `ADD_ACCOUNTING_CONTEXTS` | `JBMultiTerminal.addAccountingContextsFor` | Add accounting contexts (accepted tokens) to a terminal for a project. |
52
+ | 21 | `SET_TOKEN_METADATA` | `JBController.setTokenMetadataOf` | Set a project token's name and symbol. Checked against the project owner. |
52
53
 
53
- ### 721 Hook (IDs 21--24) -- [nana-721-hook-v6](https://github.com/Bananapus/nana-721-hook-v6)
54
+ ### 721 Hook (IDs 22--25) -- [nana-721-hook-v6](https://github.com/Bananapus/nana-721-hook-v6)
54
55
 
55
56
  | ID | Name | Checked in | Description |
56
57
  |----|------|------------|-------------|
57
- | 21 | `ADJUST_721_TIERS` | `JB721TiersHook.adjustTiers` | Add or remove NFT tiers. Also used by `CTPublisher` and `CTProjectOwner` in croptop-core-v6. |
58
- | 22 | `SET_721_METADATA` | `JB721TiersHook.setMetadata` | Set the metadata (base URI, contract URI, token URI resolver) for a 721 hook. |
59
- | 23 | `MINT_721` | `JB721TiersHook.mintFor` | Manually mint NFTs from specific tiers to a beneficiary. |
60
- | 24 | `SET_721_DISCOUNT_PERCENT` | `JB721TiersHook.setDiscountPercentOf` | Set the discount percent for one or more NFT tiers. |
58
+ | 22 | `ADJUST_721_TIERS` | `JB721TiersHook.adjustTiers` | Add or remove NFT tiers. Also used by `CTPublisher` and `CTProjectOwner` in croptop-core-v6. |
59
+ | 23 | `SET_721_METADATA` | `JB721TiersHook.setMetadata` | Set the metadata (base URI, contract URI, token URI resolver) for a 721 hook. |
60
+ | 24 | `MINT_721` | `JB721TiersHook.mintFor` | Manually mint NFTs from specific tiers to a beneficiary. |
61
+ | 25 | `SET_721_DISCOUNT_PERCENT` | `JB721TiersHook.setDiscountPercentOf` | Set the discount percent for one or more NFT tiers. |
61
62
 
62
- ### Buyback Hook (IDs 25--27) -- [nana-buyback-hook-v6](https://github.com/Bananapus/nana-buyback-hook-v6)
63
+ ### Buyback Hook (IDs 26--28) -- [nana-buyback-hook-v6](https://github.com/Bananapus/nana-buyback-hook-v6)
63
64
 
64
65
  | ID | Name | Checked in | Description |
65
66
  |----|------|------------|-------------|
66
- | 25 | `SET_BUYBACK_TWAP` | `JBBuybackHook.setTwapWindowOf` | Set the TWAP (time-weighted average price) oracle window for a project's buyback hook. |
67
- | 26 | `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`. |
68
- | 27 | `SET_BUYBACK_HOOK` | *Reserved / revnet-core-v6* | Defined in `JBPermissionIds` for `JBBuybackHookRegistry.setHookFor` and `lockHookFor`, but the registry currently checks `SET_BUYBACK_POOL` (ID 26) for those functions. Used by `REVDeployer` in revnet-core-v6 as an operator permission grant. |
67
+ | 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. |
69
70
 
70
- ### Router Terminal (ID 28) -- [nana-router-terminal-v6](https://github.com/Bananapus/nana-router-terminal-v6)
71
+ ### Router Terminal (ID 29) -- [nana-router-terminal-v6](https://github.com/Bananapus/nana-router-terminal-v6)
71
72
 
72
73
  | ID | Name | Checked in | Description |
73
74
  |----|------|------------|-------------|
74
- | 28 | `SET_ROUTER_TERMINAL` | `JBRouterTerminalRegistry.setTerminalFor`, `JBRouterTerminalRegistry.lockTerminalFor` | Set or lock the router terminal for a project. |
75
+ | 29 | `SET_ROUTER_TERMINAL` | `JBRouterTerminalRegistry.setTerminalFor`, `JBRouterTerminalRegistry.lockTerminalFor` | Set or lock the router terminal for a project. |
75
76
 
76
- ### Suckers / Omnichain (IDs 29--32) -- [nana-suckers-v6](https://github.com/Bananapus/nana-suckers-v6)
77
+ ### Suckers / Omnichain (IDs 30--33) -- [nana-suckers-v6](https://github.com/Bananapus/nana-suckers-v6)
77
78
 
78
79
  | ID | Name | Checked in | Description |
79
80
  |----|------|------------|-------------|
80
- | 29 | `MAP_SUCKER_TOKEN` | `JBSucker.mapToken` | Map an ERC-20 token to its remote chain counterpart in a sucker. Mapping is immutable once the outbox tree has entries. |
81
- | 30 | `DEPLOY_SUCKERS` | `JBSuckerRegistry.deploySuckersFor` | Deploy new sucker contracts for a project. Also checked by `JBOmnichainDeployer` and `CTDeployer`. |
82
- | 31 | `SUCKER_SAFETY` | `JBSucker.enableEmergencyHatchFor` | Enable the emergency hatch for a sucker, allowing the project owner to recover stuck tokens. |
83
- | 32 | `SET_SUCKER_DEPRECATION` | `JBSucker.setDeprecation` | Set the deprecation status of a sucker (ENABLED, DEPRECATION_PENDING, SENDING_DISABLED, DEPRECATED). |
81
+ | 30 | `MAP_SUCKER_TOKEN` | `JBSucker.mapToken` | Map an ERC-20 token to its remote chain counterpart in a sucker. Mapping is immutable once the outbox tree has entries. |
82
+ | 31 | `DEPLOY_SUCKERS` | `JBSuckerRegistry.deploySuckersFor` | Deploy new sucker contracts for a project. Also checked by `JBOmnichainDeployer` and `CTDeployer`. |
83
+ | 32 | `SUCKER_SAFETY` | `JBSucker.enableEmergencyHatchFor` | Enable the emergency hatch for a sucker, allowing the project owner to recover stuck tokens. |
84
+ | 33 | `SET_SUCKER_DEPRECATION` | `JBSucker.setDeprecation` | Set the deprecation status of a sucker (ENABLED, DEPRECATION_PENDING, SENDING_DISABLED, DEPRECATED). |
84
85
 
85
86
  ## Gotchas
86
87
 
@@ -92,7 +93,7 @@ permissionsOf[operator][account][projectId] => uint256 (packed bits)
92
93
  - **SET_TERMINALS can remove the primary terminal.** The source code warns about this. Replacing the terminal list can drop the primary terminal, breaking payments and cashouts.
93
94
  - **LAUNCH_RULESETS requires SET_TERMINALS.** `launchRulesetsFor` enforces both `LAUNCH_RULESETS` and `SET_TERMINALS` because it configures terminals as part of the launch.
94
95
  - **Holder vs. owner permissions.** Most permissions are checked against the project owner, but `CASH_OUT_TOKENS`, `BURN_TOKENS`, `CLAIM_TOKENS`, and `TRANSFER_CREDITS` are checked against the **token holder**. This means a holder can grant an operator permission to cash out or burn their own tokens.
95
- - **The uint8 type limits IDs to 0--255.** Currently 32 are defined (1--32), leaving room for future extensions.
96
+ - **The uint8 type limits IDs to 0--255.** Currently 33 are defined (1--33), leaving room for future extensions.
96
97
 
97
98
  ## Install
98
99
 
package/RISKS.md CHANGED
@@ -1,21 +1,18 @@
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.
8
12
 
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 |
13
+ ## 2. Design Notes
15
14
 
16
- ## Design Notes
17
-
18
- - Permission 0 is reserved and cannot be set
19
- - IDs are `uint8` (0-255), with 1-32 currently assigned
20
- - IDs 33-255 are available for future ecosystem extensions
21
- - This library has zero dependencies — it is the leaf of the dependency graph
15
+ - Permission 0 is reserved and cannot be set.
16
+ - IDs are `uint8` (0-255), with 1-33 currently assigned.
17
+ - IDs 34-255 are available for future ecosystem extensions.
18
+ - This library has zero dependencies -- it is the leaf of the dependency graph.
package/SKILLS.md CHANGED
@@ -8,7 +8,7 @@ Defines all `uint8` permission ID constants used across the Juicebox V6 ecosyste
8
8
 
9
9
  | Contract | Role |
10
10
  |----------|------|
11
- | `JBPermissionIds` | Constants-only library. 32 `uint8 internal constant` values (1--32). Pragma `^0.8.0` for maximum compatibility across all Juicebox contracts. |
11
+ | `JBPermissionIds` | Constants-only library. 33 `uint8 internal constant` values (1--33). Pragma `^0.8.0` for maximum compatibility across all Juicebox contracts. |
12
12
 
13
13
  ## Key Functions
14
14
 
@@ -58,38 +58,39 @@ When a permissioned function is called, the contract checks whether the caller e
58
58
  | 18 | `SET_SPLIT_GROUPS` | `JBController.setSplitGroupsOf` | Set how payouts and reserved tokens are distributed. Checked against project owner. |
59
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. |
60
60
  | 20 | `ADD_ACCOUNTING_CONTEXTS` | `JBMultiTerminal.addAccountingContextsFor` | Add accepted token accounting contexts to a terminal. Checked against project owner. |
61
+ | 21 | `SET_TOKEN_METADATA` | `JBController.setTokenMetadataOf` | Set a project token's name and symbol. Checked against project owner. |
61
62
 
62
63
  ### nana-721-hook-v6
63
64
 
64
65
  | ID | Name | Checked in | Permission scope |
65
66
  |----|------|------------|-----------------|
66
- | 21 | `ADJUST_721_TIERS` | `JB721TiersHook.adjustTiers` | Add or remove NFT tiers. Checked against `owner()` (the project's controller). Also used by `CTPublisher`, `CTProjectOwner`, and `REVDeployer`. |
67
- | 22 | `SET_721_METADATA` | `JB721TiersHook.setMetadata` | Set base URI, contract URI, or token URI resolver. Checked against `owner()`. |
68
- | 23 | `MINT_721` | `JB721TiersHook.mintFor` | Manually mint NFTs from specific tiers. Checked against `owner()`. |
69
- | 24 | `SET_721_DISCOUNT_PERCENT` | `JB721TiersHook.setDiscountPercentOf` | Set the discount percent for NFT tiers. Checked against `owner()`. Called twice in the function for two separate code paths. |
67
+ | 22 | `ADJUST_721_TIERS` | `JB721TiersHook.adjustTiers` | Add or remove NFT tiers. Checked against `owner()` (the project's controller). Also used by `CTPublisher`, `CTProjectOwner`, and `REVDeployer`. |
68
+ | 23 | `SET_721_METADATA` | `JB721TiersHook.setMetadata` | Set base URI, contract URI, or token URI resolver. Checked against `owner()`. |
69
+ | 24 | `MINT_721` | `JB721TiersHook.mintFor` | Manually mint NFTs from specific tiers. Checked against `owner()`. |
70
+ | 25 | `SET_721_DISCOUNT_PERCENT` | `JB721TiersHook.setDiscountPercentOf` | Set the discount percent for NFT tiers. Checked against `owner()`. Called twice in the function for two separate code paths. |
70
71
 
71
72
  ### nana-buyback-hook-v6
72
73
 
73
74
  | ID | Name | Checked in | Permission scope |
74
75
  |----|------|------------|-----------------|
75
- | 25 | `SET_BUYBACK_TWAP` | `JBBuybackHook.setTwapWindowOf` | Set the TWAP oracle window duration. Checked against project owner. |
76
- | 26 | `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. |
77
- | 27 | `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 26) for those functions. Referenced by `REVDeployer` in revnet-core-v6 as an operator permission grant. |
76
+ | 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. |
78
79
 
79
80
  ### nana-router-terminal-v6
80
81
 
81
82
  | ID | Name | Checked in | Permission scope |
82
83
  |----|------|------------|-----------------|
83
- | 28 | `SET_ROUTER_TERMINAL` | `JBRouterTerminalRegistry.setTerminalFor`, `JBRouterTerminalRegistry.lockTerminalFor` | Set or lock the router terminal for a project. Checked against project owner. |
84
+ | 29 | `SET_ROUTER_TERMINAL` | `JBRouterTerminalRegistry.setTerminalFor`, `JBRouterTerminalRegistry.lockTerminalFor` | Set or lock the router terminal for a project. Checked against project owner. |
84
85
 
85
86
  ### nana-suckers-v6
86
87
 
87
88
  | ID | Name | Checked in | Permission scope |
88
89
  |----|------|------------|-----------------|
89
- | 29 | `MAP_SUCKER_TOKEN` | `JBSucker.mapToken` | Map an ERC-20 token to its remote chain counterpart. Immutable once the outbox merkle tree has entries. Checked against project owner. |
90
- | 30 | `DEPLOY_SUCKERS` | `JBSuckerRegistry.deploySuckersFor` | Deploy sucker contracts for cross-chain bridging. Checked against project owner. Also checked by `JBOmnichainDeployer` and `CTDeployer`. |
91
- | 31 | `SUCKER_SAFETY` | `JBSucker.enableEmergencyHatchFor` | Enable the emergency hatch to recover stuck tokens. Checked against project owner. |
92
- | 32 | `SET_SUCKER_DEPRECATION` | `JBSucker.setDeprecation` | Move a sucker through the deprecation lifecycle (ENABLED -> DEPRECATION_PENDING -> SENDING_DISABLED -> DEPRECATED). Checked against project owner. |
90
+ | 30 | `MAP_SUCKER_TOKEN` | `JBSucker.mapToken` | Map an ERC-20 token to its remote chain counterpart. Immutable once the outbox merkle tree has entries. Checked against project owner. |
91
+ | 31 | `DEPLOY_SUCKERS` | `JBSuckerRegistry.deploySuckersFor` | Deploy sucker contracts for cross-chain bridging. Checked against project owner. Also checked by `JBOmnichainDeployer` and `CTDeployer`. |
92
+ | 32 | `SUCKER_SAFETY` | `JBSucker.enableEmergencyHatchFor` | Enable the emergency hatch to recover stuck tokens. Checked against project owner. |
93
+ | 33 | `SET_SUCKER_DEPRECATION` | `JBSucker.setDeprecation` | Move a sucker through the deprecation lifecycle (ENABLED -> DEPRECATION_PENDING -> SENDING_DISABLED -> DEPRECATED). Checked against project owner. |
93
94
 
94
95
  ## Integration Points
95
96
 
@@ -124,9 +125,9 @@ N/A -- no structs or enums. All values are `uint8 internal constant`.
124
125
  - **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.
125
126
  - **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.
126
127
  - **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.
127
- - **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.
128
+ - **SET_BUYBACK_HOOK (ID 28) mismatch.** The source comment says it guards `JBBuybackHookRegistry.setHookFor` and `lockHookFor`, but those functions actually check `SET_BUYBACK_POOL` (ID 27). The ID is still granted by `REVDeployer` as an operator permission.
128
129
  - **ADD_PRICE_FEED (ID 19) is checked on JBController, not JBPrices.** The permission gate is on `JBController.addPriceFeed`, which then calls `JBPrices.addPriceFeedFor` internally.
129
- - **uint8 range.** IDs are `uint8` (0--255) but the packed storage is `uint256`, so the system supports up to 256 permission bits. Currently 32 are defined (1--32).
130
+ - **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).
130
131
 
131
132
  ## Example Integration
132
133
 
@@ -0,0 +1,187 @@
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.
4
+
5
+ ## Journey 1: Grant an Operator Permission to Queue Rulesets
6
+
7
+ **Actor:** Project owner granting delegated access to a trusted operator.
8
+ **Goal:** Allow an operator to queue new rulesets for a project without transferring project ownership.
9
+
10
+ ### Steps
11
+
12
+ 1. **Project owner calls `JBPermissions.setPermissionsFor`**
13
+
14
+ ```solidity
15
+ uint8[] memory ids = new uint8[](1);
16
+ ids[0] = JBPermissionIds.QUEUE_RULESETS; // ID 2
17
+ permissions.setPermissionsFor(
18
+ projectOwner,
19
+ JBPermissionsData({operator: operatorAddress, projectId: 5, permissionIds: ids})
20
+ );
21
+ ```
22
+
23
+ - Sets bit 2 in `permissionsOf[operatorAddress][projectOwner][5]`
24
+
25
+ 2. **Operator calls `JBController.queueRulesetsOf(5, ...)`**
26
+
27
+ - Controller calls `_requirePermissionFrom(projectOwner, 5, JBPermissionIds.QUEUE_RULESETS)`
28
+ - `JBPermissions.hasPermission` checks: does `operatorAddress` have bit 2 set for `(projectOwner, projectId=5)`? Yes.
29
+ - Operation proceeds.
30
+
31
+ ### What to verify
32
+
33
+ - The operator can ONLY queue rulesets. They cannot send payouts, set terminals, or perform any other operation unless additional IDs are granted.
34
+ - Granting `QUEUE_RULESETS` with `projectId = 0` (wildcard) would allow the operator to queue rulesets for ALL projects the owner controls.
35
+
36
+ ---
37
+
38
+ ## Journey 2: ROOT Permission Grants Universal Access
39
+
40
+ **Actor:** Project owner granting ROOT to a highly trusted multisig.
41
+ **Goal:** Give a single operator full control over all project operations.
42
+
43
+ ### Steps
44
+
45
+ 1. **Project owner calls `JBPermissions.setPermissionsFor`**
46
+
47
+ ```solidity
48
+ uint8[] memory ids = new uint8[](1);
49
+ ids[0] = JBPermissionIds.ROOT; // ID 1
50
+ permissions.setPermissionsFor(
51
+ projectOwner,
52
+ JBPermissionsData({operator: multisigAddress, projectId: 5, permissionIds: ids})
53
+ );
54
+ ```
55
+
56
+ - Sets bit 1 in `permissionsOf[multisigAddress][projectOwner][5]`
57
+
58
+ 2. **Multisig calls any permissioned function for project 5**
59
+
60
+ - Every `_requirePermissionFrom` check includes `includeRoot: true`
61
+ - ROOT (bit 1) satisfies any permission check for `(projectOwner, projectId=5)`
62
+ - The multisig can queue rulesets, send payouts, set terminals, mint tokens, etc.
63
+
64
+ ### What to verify
65
+
66
+ - ROOT cannot be granted with `projectId = 0`. `JBPermissions` reverts with `JBPermissions_CantSetRootPermissionForWildcardProject()`.
67
+ - A ROOT operator can call `setPermissionsFor` on behalf of the account, but cannot grant ROOT to other operators or set wildcard permissions. This prevents permission escalation.
68
+ - ROOT is per-project. Having ROOT for project 5 does not grant access to project 6.
69
+
70
+ ---
71
+
72
+ ## Journey 3: Token Holder Delegates Cashout Authority
73
+
74
+ **Actor:** Token holder (not project owner) granting a bot permission to cash out tokens on their behalf.
75
+ **Goal:** Allow automated cashout execution without exposing the holder's private key.
76
+
77
+ ### Steps
78
+
79
+ 1. **Token holder calls `JBPermissions.setPermissionsFor`**
80
+
81
+ ```solidity
82
+ uint8[] memory ids = new uint8[](1);
83
+ ids[0] = JBPermissionIds.CASH_OUT_TOKENS; // ID 4
84
+ permissions.setPermissionsFor(
85
+ tokenHolder,
86
+ JBPermissionsData({operator: botAddress, projectId: 5, permissionIds: ids})
87
+ );
88
+ ```
89
+
90
+ - Note: the `account` is the **token holder**, not the project owner
91
+
92
+ 2. **Bot calls `JBMultiTerminal.cashOutTokensOf(tokenHolder, 5, ...)`**
93
+
94
+ - Terminal calls `_requirePermissionFrom(tokenHolder, 5, JBPermissionIds.CASH_OUT_TOKENS)`
95
+ - Permission check passes for `botAddress` because it has `CASH_OUT_TOKENS` for `(tokenHolder, 5)`
96
+
97
+ ### What to verify
98
+
99
+ - `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.
100
+ - The project owner CANNOT cash out another holder's tokens (unless the holder explicitly grants them `CASH_OUT_TOKENS`).
101
+ - The same holder-scoped pattern applies to `BURN_TOKENS` (11), `CLAIM_TOKENS` (12), and `TRANSFER_CREDITS` (13).
102
+
103
+ ---
104
+
105
+ ## Journey 4: SET_TERMINALS Can Break a Project
106
+
107
+ **Actor:** Project owner (or delegate with SET_TERMINALS permission).
108
+ **Goal:** Update the list of terminals for a project -- illustrating the risk documented in the source.
109
+
110
+ ### Steps
111
+
112
+ 1. **Operator calls `JBDirectory.setTerminalsOf(5, newTerminals)`**
113
+
114
+ - Permission check: `_requirePermissionFrom(projectOwner, 5, JBPermissionIds.SET_TERMINALS)` (ID 15)
115
+ - The `newTerminals` array replaces the ENTIRE terminal list
116
+
117
+ 2. **If the new list omits the current primary terminal:**
118
+
119
+ - The primary terminal is removed from the project
120
+ - All payments to the project via `pay()` will fail (no terminal to receive them)
121
+ - All cashouts via `cashOutTokensOf()` will fail
122
+ - All payouts via `sendPayoutsOf()` will fail
123
+ - The project is effectively frozen until a new primary terminal is set
124
+
125
+ ### What to verify
126
+
127
+ - Granting `SET_TERMINALS` to an untrusted operator is dangerous. The operator can remove all terminals, bricking the project.
128
+ - `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.
129
+ - There is no undo mechanism. Once terminals are set, another `setTerminalsOf` call is needed to restore them.
130
+
131
+ ---
132
+
133
+ ## Journey 5: Locking a Buyback Hook or Router Terminal (Permanent Action)
134
+
135
+ **Actor:** Project owner or delegate with SET_BUYBACK_HOOK or SET_ROUTER_TERMINAL permission.
136
+ **Goal:** Illustrate the irreversible locking behavior gated by dual-purpose permission IDs.
137
+
138
+ ### Steps (SET_BUYBACK_HOOK example)
139
+
140
+ 1. **Operator with SET_BUYBACK_HOOK (ID 28) calls `JBBuybackHookRegistry.setHookFor(5, hookAddress)`**
141
+
142
+ - Configures the buyback hook for project 5
143
+ - This is a reversible operation (can be called again with a different hook)
144
+
145
+ 2. **Same operator calls `JBBuybackHookRegistry.lockHookFor(5)`**
146
+
147
+ - Permanently locks the hook configuration for project 5
148
+ - No one can change the hook after locking -- not even the project owner
149
+
150
+ ### What to verify
151
+
152
+ - 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.
153
+ - The locking is permanent (no unlock mechanism in the registry).
154
+ - Project owners should only grant SET_BUYBACK_HOOK (28) or SET_ROUTER_TERMINAL (29) to operators they trust not to lock prematurely.
155
+
156
+ ---
157
+
158
+ ## Journey 6: Cross-Repo Permission Usage (nana-suckers)
159
+
160
+ **Actor:** Project owner managing cross-chain infrastructure.
161
+ **Goal:** Deploy suckers and manage their lifecycle using permission IDs 30-33.
162
+
163
+ ### Steps
164
+
165
+ 1. **Deploy suckers: `JBSuckerRegistry.deploySuckersFor(5, configs)`**
166
+ - Permission: `DEPLOY_SUCKERS` (ID 31)
167
+ - Creates sucker contracts for cross-chain bridging
168
+
169
+ 2. **Map tokens: `JBSucker.mapToken(localToken, remoteToken)`**
170
+ - Permission: `MAP_SUCKER_TOKEN` (ID 30)
171
+ - Maps a local ERC-20 to its remote chain counterpart
172
+ - CAUTION: once the outbox merkle tree has entries, the mapping is immutable (can only be disabled, not remapped)
173
+
174
+ 3. **Enable emergency hatch: `JBSucker.enableEmergencyHatchFor(token)`**
175
+ - Permission: `SUCKER_SAFETY` (ID 32)
176
+ - Allows recovery of stuck tokens via the emergency hatch
177
+
178
+ 4. **Deprecate sucker: `JBSucker.setDeprecation(newState)`**
179
+ - Permission: `SET_SUCKER_DEPRECATION` (ID 33)
180
+ - Moves the sucker through its lifecycle: ENABLED -> DEPRECATION_PENDING -> SENDING_DISABLED -> DEPRECATED
181
+
182
+ ### What to verify
183
+
184
+ - Each sucker permission is independent. Having `DEPLOY_SUCKERS` does not grant `MAP_SUCKER_TOKEN` or `SUCKER_SAFETY`.
185
+ - `MAP_SUCKER_TOKEN` is especially sensitive because token mappings become immutable once the outbox tree has entries.
186
+ - `SUCKER_SAFETY` should be granted sparingly -- the emergency hatch is a last-resort recovery mechanism.
187
+ - All four sucker permissions are checked against the project owner, not a token holder.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananapus/permission-ids-v6",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,24 +28,26 @@ 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.addPriceFeed`.
32
32
  uint8 internal constant ADD_ACCOUNTING_CONTEXTS = 20; // Permission to call
33
33
  // `JBMultiTerminal.addAccountingContextsFor`.
34
+ uint8 internal constant SET_TOKEN_METADATA = 21; // Permission to call
35
+ // `JBController.setTokenMetadataOf`.
34
36
 
35
37
  /* Used by `nana-721-hook`: https://github.com/Bananapus/nana-721-hook */
36
- uint8 internal constant ADJUST_721_TIERS = 21; // Permission to call `JB721TiersHook.adjustTiers`.
37
- uint8 internal constant SET_721_METADATA = 22; // Permission to call `JB721TiersHook.setMetadata`.
38
- uint8 internal constant MINT_721 = 23; // Permission to call `JB721TiersHook.mintFor`.
39
- uint8 internal constant SET_721_DISCOUNT_PERCENT = 24; // Permission to call `JB721TiersHook.setDiscountPercentOf`.
38
+ uint8 internal constant ADJUST_721_TIERS = 22; // Permission to call `JB721TiersHook.adjustTiers`.
39
+ uint8 internal constant SET_721_METADATA = 23; // Permission to call `JB721TiersHook.setMetadata`.
40
+ uint8 internal constant MINT_721 = 24; // Permission to call `JB721TiersHook.mintFor`.
41
+ uint8 internal constant SET_721_DISCOUNT_PERCENT = 25; // Permission to call `JB721TiersHook.setDiscountPercentOf`.
40
42
 
41
43
  /* Used by `nana-buyback-hook`: https://github.com/Bananapus/nana-buyback-hook */
42
- uint8 internal constant SET_BUYBACK_TWAP = 25; // Permission to call `JBBuybackHook.setTwapWindowOf`.
43
- uint8 internal constant SET_BUYBACK_POOL = 26; // Permission to call `JBBuybackHook.setPoolFor`.
44
+ uint8 internal constant SET_BUYBACK_TWAP = 26; // Permission to call `JBBuybackHook.setTwapWindowOf`.
45
+ uint8 internal constant SET_BUYBACK_POOL = 27; // Permission to call `JBBuybackHook.setPoolFor`.
44
46
  /// @dev This single ID intentionally gates both setting and locking the buyback hook as a simplification.
45
47
  /// Granting this permission allows the operator to call both `JBBuybackHookRegistry.setHookFor` (to configure the
46
48
  /// hook) and `JBBuybackHookRegistry.lockHookFor` (to permanently lock the hook configuration). Project owners
47
49
  /// should be aware that an operator with this permission can lock the hook, preventing future changes.
48
- uint8 internal constant SET_BUYBACK_HOOK = 27; // Permission to call `JBBuybackHookRegistry.setHookFor` and
50
+ uint8 internal constant SET_BUYBACK_HOOK = 28; // Permission to call `JBBuybackHookRegistry.setHookFor` and
49
51
  // `JBBuybackHookRegistry.lockHookFor`.
50
52
 
51
53
  /* Used by `nana-router-terminal`: https://github.com/Bananapus/nana-router-terminal-v6 */
@@ -54,12 +56,12 @@ library JBPermissionIds {
54
56
  /// configure the terminal) and `JBRouterTerminalRegistry.lockTerminalFor` (to permanently lock the terminal
55
57
  /// configuration). Project owners should be aware that an operator with this permission can lock the terminal,
56
58
  /// preventing future changes.
57
- uint8 internal constant SET_ROUTER_TERMINAL = 28; // Permission to call
59
+ uint8 internal constant SET_ROUTER_TERMINAL = 29; // Permission to call
58
60
  // `JBRouterTerminalRegistry.setTerminalFor` and `JBRouterTerminalRegistry.lockTerminalFor`.
59
61
 
60
62
  /* Used by `nana-suckers`: https://github.com/Bananapus/nana-suckers */
61
- uint8 internal constant MAP_SUCKER_TOKEN = 29; // Permission to call `JBSucker.mapToken`.
62
- uint8 internal constant DEPLOY_SUCKERS = 30; // Permission to call `JBSuckerRegistry.deploySuckersFor`.
63
- uint8 internal constant SUCKER_SAFETY = 31; // Permission to call `JBSucker.enableEmergencyHatchFor`.
64
- uint8 internal constant SET_SUCKER_DEPRECATION = 32; // Permission to call `JBSucker.setDeprecation`.
63
+ uint8 internal constant MAP_SUCKER_TOKEN = 30; // Permission to call `JBSucker.mapToken`.
64
+ uint8 internal constant DEPLOY_SUCKERS = 31; // Permission to call `JBSuckerRegistry.deploySuckersFor`.
65
+ uint8 internal constant SUCKER_SAFETY = 32; // Permission to call `JBSucker.enableEmergencyHatchFor`.
66
+ uint8 internal constant SET_SUCKER_DEPRECATION = 33; // Permission to call `JBSucker.setDeprecation`.
65
67
  }