@bananapus/permission-ids-v6 0.0.15 → 0.0.16

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
@@ -2,6 +2,31 @@
2
2
 
3
3
  Admin privileges and their scope in nana-permission-ids-v6.
4
4
 
5
+ ## At A Glance
6
+
7
+ | Item | Details |
8
+ |------|---------|
9
+ | Scope | Reference library for the permission IDs consumed across the Juicebox V6 ecosystem. No contract in this repo has mutable runtime state. |
10
+ | Operators | Maintainers who change the constant list in source and downstream repos that consume those constants. |
11
+ | Highest-risk actions | Renumbering or repurposing a permission ID that downstream contracts already depend on. |
12
+ | Recovery posture | Runtime admin recovery does not apply here. If the constants are wrong, downstream code and docs have to be updated and redeployed against the corrected source. |
13
+
14
+ ## Routine Operations
15
+
16
+ - Treat `JBPermissionIds.sol` as a coordination artifact across repos, not a place for casual edits.
17
+ - When adding a new permission, update the source library and the dependent repo docs together so operator guidance does not drift from code.
18
+ - Re-check downstream permission assumptions after any change because multiple repos gate admin behavior through this single numbering scheme.
19
+
20
+ ## One-Way Or High-Risk Actions
21
+
22
+ - Changing an existing numeric assignment can silently invalidate permission checks in dependent repos.
23
+ - The library itself has no admin keys, but stale docs around it can mislead operators about real powers elsewhere in the ecosystem.
24
+
25
+ ## Recovery Notes
26
+
27
+ - If the permission map drifts from deployed contracts, the fix is coordinated source and documentation updates in the dependent repos, plus redeployment where the old numeric assumptions are already live.
28
+ - There is no on-chain migration knob in this repo because it only ships compile-time constants.
29
+
5
30
  ## Overview
6
31
 
7
32
  This repo defines permission ID constants. It contains no admin functions itself -- it is a reference library for the permission system used across the Juicebox V6 ecosystem. The constants in `JBPermissionIds` are consumed by contracts in nana-core-v6, nana-721-hook-v6, nana-buyback-hook-v6, nana-router-terminal-v6, and nana-suckers-v6 to gate privileged operations.
@@ -10,7 +35,7 @@ There are no ownable contracts, no upgrade mechanisms, and no mutable state. The
10
35
 
11
36
  ## Permission IDs
12
37
 
13
- All 34 defined permission IDs and what they control:
38
+ All 39 defined permission IDs and what they control:
14
39
 
15
40
  | ID | Constant | Used By | What It Controls |
16
41
  |----|----------|---------|-----------------|
@@ -48,8 +73,13 @@ All 34 defined permission IDs and what they control:
48
73
  | 32 | `DEPLOY_SUCKERS` | nana-suckers (`JBSuckerRegistry`) | `JBSuckerRegistry.deploySuckersFor` -- deploy sucker contracts for cross-chain bridging. |
49
74
  | 33 | `SUCKER_SAFETY` | nana-suckers (`JBSucker`) | `JBSucker.enableEmergencyHatchFor` -- enable the emergency hatch to recover stuck tokens. |
50
75
  | 34 | `SET_SUCKER_DEPRECATION` | nana-suckers (`JBSucker`) | `JBSucker.setDeprecation` -- set deprecation status (ENABLED, DEPRECATION_PENDING, SENDING_DISABLED, DEPRECATED). |
76
+ | 35 | `HIDE_TOKENS` | revnet-core (`REVHiddenTokens`) | `REVHiddenTokens.hideTokensOf` -- hide (burn) tokens on behalf of a holder. Checked against the **token holder**. |
77
+ | 36 | `OPEN_LOAN` | revnet-core (`REVLoans`) | `REVLoans.borrowFrom` -- open a loan on behalf of a token holder. Checked against the **token holder**. |
78
+ | 37 | `REALLOCATE_LOAN` | revnet-core (`REVLoans`) | `REVLoans.reallocateCollateralFromLoan` -- reallocate loan collateral on behalf of a loan NFT owner. Checked against the **loan NFT owner**. |
79
+ | 38 | `REPAY_LOAN` | revnet-core (`REVLoans`) | `REVLoans.repayLoan` -- repay a loan on behalf of a loan NFT owner. Checked against the **loan NFT owner**. |
80
+ | 39 | `REVEAL_TOKENS` | revnet-core (`REVHiddenTokens`) | `REVHiddenTokens.revealTokensOf` -- reveal (re-mint) hidden tokens on behalf of a holder. Checked against the **token holder**. |
51
81
 
52
- IDs 0 and 35-255 are unused. ID 0 is reserved and cannot be set. IDs 35-255 are available for future ecosystem extensions.
82
+ IDs 0 and 40-255 are unused. ID 0 is reserved and cannot be set. IDs 40-255 are available for future ecosystem extensions.
53
83
 
54
84
  ## ROOT Permission
55
85
 
@@ -99,7 +129,7 @@ Some permissions warrant extra caution when granting:
99
129
 
100
130
  ## Holder vs. Owner Permissions
101
131
 
102
- Most permissions are checked against the **project owner** (the account that owns the project NFT). Four permissions are instead checked against the **token holder**:
132
+ Most permissions are checked against the **project owner** (the account that owns the project NFT). Several permissions are instead checked against the **token holder** or **loan NFT owner**:
103
133
 
104
134
  | Permission | Checked Against |
105
135
  |-----------|----------------|
@@ -107,5 +137,10 @@ Most permissions are checked against the **project owner** (the account that own
107
137
  | `BURN_TOKENS` (11) | Token holder |
108
138
  | `CLAIM_TOKENS` (12) | Token holder |
109
139
  | `TRANSFER_CREDITS` (13) | Token holder |
140
+ | `HIDE_TOKENS` (35) | Token holder |
141
+ | `OPEN_LOAN` (36) | Token holder |
142
+ | `REALLOCATE_LOAN` (37) | Loan NFT owner |
143
+ | `REPAY_LOAN` (38) | Loan NFT owner |
144
+ | `REVEAL_TOKENS` (39) | Token holder |
110
145
 
111
- This means a token holder can grant an operator permission to cash out, burn, claim, or transfer their own tokens -- independent of the project owner's permissions.
146
+ This means a token holder can grant an operator permission to cash out, burn, claim, transfer, hide, reveal, or borrow against their own tokens -- independent of the project owner's permissions. Loan NFT owners can similarly grant operators permission to repay or reallocate their loans.
package/ARCHITECTURE.md CHANGED
@@ -1,67 +1,42 @@
1
- # nana-permission-ids-v6 — Architecture
1
+ # Architecture
2
2
 
3
3
  ## Purpose
4
4
 
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
-
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
-
19
- ## Contract Map
20
-
21
- ```
22
- src/
23
- └── JBPermissionIds.sol — Library of uint8 permission ID constants
24
- ```
25
-
26
- ## Permission ID Registry
27
-
28
- | ID | Name | Used By | Gated Function |
29
- |----|------|---------|----------------|
30
- | 1 | `ROOT` | nana-core | All permissions (dangerous) |
31
- | 2 | `QUEUE_RULESETS` | nana-core | `JBController.queueRulesetsOf` |
32
- | 3 | `LAUNCH_RULESETS` | nana-core | `JBController.launchRulesetsFor` |
33
- | 4 | `CASH_OUT_TOKENS` | nana-core | `JBMultiTerminal.cashOutTokensOf` |
34
- | 5 | `SEND_PAYOUTS` | nana-core | `JBMultiTerminal.sendPayoutsOf` |
35
- | 6 | `MIGRATE_TERMINAL` | nana-core | `JBMultiTerminal.migrateBalanceOf` |
36
- | 7 | `SET_PROJECT_URI` | nana-core | `JBController.setUriOf` |
37
- | 8 | `DEPLOY_ERC20` | nana-core | `JBController.deployERC20For` |
38
- | 9 | `SET_TOKEN` | nana-core | `JBController.setTokenFor` |
39
- | 10 | `MINT_TOKENS` | nana-core | `JBController.mintTokensOf` |
40
- | 11 | `BURN_TOKENS` | nana-core | `JBController.burnTokensOf` |
41
- | 12 | `CLAIM_TOKENS` | nana-core | `JBController.claimTokensFor` |
42
- | 13 | `TRANSFER_CREDITS` | nana-core | `JBController.transferCreditsFrom` |
43
- | 14 | `SET_CONTROLLER` | nana-core | `JBDirectory.setControllerOf` |
44
- | 15 | `SET_TERMINALS` | nana-core | `JBDirectory.setTerminalsOf` |
45
- | 16 | `ADD_TERMINALS` | nana-core | `JBDirectory.setPrimaryTerminalOf` (implicit add) |
46
- | 17 | `SET_PRIMARY_TERMINAL` | nana-core | `JBDirectory.setPrimaryTerminalOf` |
47
- | 18 | `USE_ALLOWANCE` | nana-core | `JBMultiTerminal.useAllowanceOf` |
48
- | 19 | `SET_SPLIT_GROUPS` | nana-core | `JBController.setSplitGroupsOf` |
49
- | 20 | `ADD_PRICE_FEED` | nana-core | `JBController.addPriceFeedFor` |
50
- | 21 | `ADD_ACCOUNTING_CONTEXTS` | nana-core | `JBMultiTerminal.addAccountingContextsFor` |
51
- | 22 | `SET_TOKEN_METADATA` | nana-core | `JBController.setTokenMetadataOf` |
52
- | 23 | `ADJUST_721_TIERS` | nana-721-hook | `JB721TiersHook.adjustTiers` |
53
- | 24 | `SET_721_METADATA` | nana-721-hook | `JB721TiersHook.setMetadata` |
54
- | 25 | `MINT_721` | nana-721-hook | `JB721TiersHook.mintFor` |
55
- | 26 | `SET_721_DISCOUNT_PERCENT` | nana-721-hook | `JB721TiersHook.setDiscountPercentOf` |
56
- | 27 | `SET_BUYBACK_TWAP` | nana-buyback-hook | `JBBuybackHook.setTwapWindowOf` |
57
- | 28 | `SET_BUYBACK_POOL` | nana-buyback-hook | `JBBuybackHook.setPoolFor` |
58
- | 29 | `SET_BUYBACK_HOOK` | nana-buyback-hook | `JBBuybackHookRegistry.setHookFor` + `lockHookFor` |
59
- | 30 | `SET_ROUTER_TERMINAL` | nana-router-terminal | `JBRouterTerminalRegistry.setTerminalFor` + `lockTerminalFor` |
60
- | 31 | `MAP_SUCKER_TOKEN` | nana-suckers | `JBSucker.mapToken` |
61
- | 32 | `DEPLOY_SUCKERS` | nana-suckers | `JBSuckerRegistry.deploySuckersFor` |
62
- | 33 | `SUCKER_SAFETY` | nana-suckers | `JBSucker.enableEmergencyHatchFor` |
63
- | 34 | `SET_SUCKER_DEPRECATION` | nana-suckers | `JBSucker.setDeprecation` |
5
+ `nana-permission-ids-v6` is the shared permission namespace for the ecosystem. It exists so every repo can agree on what permission bit means what.
6
+
7
+ ## Boundaries
8
+
9
+ - This repo intentionally contains almost no logic.
10
+ - Its value is stability, not sophistication.
11
+ - The constants here are coupled to checks spread across many sibling repos.
12
+
13
+ ## Main Components
14
+
15
+ | Component | Responsibility |
16
+ | --- | --- |
17
+ | `JBPermissionIds` | Defines the canonical `uint8` IDs used with `JBPermissions` |
18
+
19
+ ## Runtime Model
20
+
21
+ There is no runtime state. Other repos import this library and compare permission bits against these constants.
22
+
23
+ ## Critical Invariants
24
+
25
+ - Existing IDs must remain stable once consumed by deployed contracts and integrations.
26
+ - New IDs should only be appended intentionally; repurposing an old ID is ecosystem-breaking.
27
+ - `ROOT` stays special and must remain consistent with `JBPermissions` expectations.
28
+
29
+ ## Where Complexity Lives
30
+
31
+ - The code is trivial; the coordination burden is not.
32
+ - Mistakes here look like harmless renames until they land in downstream permission checks.
64
33
 
65
34
  ## Dependencies
66
35
 
67
- None this is a leaf dependency with no imports.
36
+ - Semantically coupled to `nana-core-v6` and every repo that performs permission checks
37
+
38
+ ## Safe Change Guide
39
+
40
+ - Treat every ID change as a cross-repo protocol change.
41
+ - When adding a permission, update the docs and downstream repos in the same change set.
42
+ - Do not add convenience aliases that obscure the one-to-one mapping between bit position and meaning.
@@ -1,184 +1,34 @@
1
- # Audit Instructions -- nana-permission-ids-v6
1
+ # Audit Instructions
2
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 34 `uint8` constants. Read [RISKS.md](./RISKS.md) first -- it documents all known risks and trust assumptions. Then come back here.
3
+ This repo is only permission ID constants, but the constants are security-critical because many repos key access control off them.
4
4
 
5
- ## Quick Verification
5
+ ## Objective
6
6
 
7
- Run this one-liner from the repo root to verify all 34 permission IDs are unique, sequential (1-34), 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 34) && echo "PASS: All 34 IDs are unique and sequential (1-34)" || 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.
7
+ Find issues that:
8
+ - assign duplicate IDs to different semantic permissions
9
+ - mismatch IDs that downstream repos assume are canonical
10
+ - create ordering or collision hazards for future permission additions
40
11
 
41
12
  ## Scope
42
13
 
43
- **In scope:**
44
- ```
45
- src/JBPermissionIds.sol # Constants library (~69 lines, 34 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 34 `uint8 internal constant` values numbered 1 through 34. 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-34:** Individual permissions, each gating a specific function (or set of functions) in the ecosystem.
63
- - **Bits 35-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 | `ADD_TERMINALS` | `JBDirectory.setPrimaryTerminalOf` (implicit add) | Project owner |
85
- | 17 | `SET_PRIMARY_TERMINAL` | `JBDirectory.setPrimaryTerminalOf` | Project owner |
86
- | 18 | `USE_ALLOWANCE` | `JBMultiTerminal.useAllowanceOf` | Project owner |
87
- | 19 | `SET_SPLIT_GROUPS` | `JBController.setSplitGroupsOf` | Project owner |
88
- | 20 | `ADD_PRICE_FEED` | `JBController.addPriceFeedFor` (not `JBPrices` directly) | Project owner |
89
- | 21 | `ADD_ACCOUNTING_CONTEXTS` | `JBMultiTerminal.addAccountingContextsFor` | Project owner |
90
- | 22 | `SET_TOKEN_METADATA` | `JBController.setTokenMetadataOf` | Project owner |
91
- | 23 | `ADJUST_721_TIERS` | `JB721TiersHook.adjustTiers` | Hook owner |
92
- | 24 | `SET_721_METADATA` | `JB721TiersHook.setMetadata` | Hook owner |
93
- | 25 | `MINT_721` | `JB721TiersHook.mintFor` | Hook owner |
94
- | 26 | `SET_721_DISCOUNT_PERCENT` | `JB721TiersHook.setDiscountPercentOf` | Hook owner |
95
- | 27 | `SET_BUYBACK_TWAP` | `JBBuybackHook.setTwapWindowOf` | Project owner |
96
- | 28 | `SET_BUYBACK_POOL` | `JBBuybackHook.setPoolFor` | Project owner |
97
- | 29 | `SET_BUYBACK_HOOK` | `JBBuybackHookRegistry.setHookFor` + `lockHookFor` | Project owner |
98
- | 30 | `SET_ROUTER_TERMINAL` | `JBRouterTerminalRegistry.setTerminalFor` + `lockTerminalFor` | Project owner |
99
- | 31 | `MAP_SUCKER_TOKEN` | `JBSucker.mapToken` | Project owner |
100
- | 32 | `DEPLOY_SUCKERS` | `JBSuckerRegistry.deploySuckersFor` | Project owner |
101
- | 33 | `SUCKER_SAFETY` | `JBSucker.enableEmergencyHatchFor` | Project owner |
102
- | 34 | `SET_SUCKER_DEPRECATION` | `JBSucker.setDeprecation` | Project owner |
103
-
104
- ## Priority Audit Areas
105
-
106
- ### 1. ID Uniqueness (Highest Priority)
107
-
108
- 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:
109
-
110
- - All 34 constants have distinct values.
111
- - Values are sequential from 1 to 34 with no gaps and no duplicates.
112
- - No other file in the ecosystem defines additional permission ID constants that could collide with these.
113
-
114
- ### 2. ID-to-Function Mapping Correctness
115
-
116
- Each constant's doc comment claims it gates a specific function. Verify against the actual source code of each consuming contract:
117
-
118
- - **nana-core-v6**: IDs 2-22 should match the `_requirePermissionFrom` calls in `JBController`, `JBMultiTerminal`, and `JBDirectory`.
119
- - **nana-721-hook-v6**: IDs 23-26 should match permission checks in `JB721TiersHook`.
120
- - **nana-buyback-hook-v6**: IDs 27-29 should match permission checks in `JBBuybackHook` and `JBBuybackHookRegistry`.
121
- - **nana-router-terminal-v6**: ID 30 should match permission checks in `JBRouterTerminalRegistry`.
122
- - **nana-suckers-v6**: IDs 31-34 should match permission checks in `JBSucker` and `JBSuckerRegistry`.
123
-
124
- ### 3. Holder-Scoped vs Owner-Scoped Permissions
125
-
126
- Four permissions are checked against the **token holder**, not the project owner:
127
-
128
- - `CASH_OUT_TOKENS` (4) -- holder authorizes cashout of their tokens
129
- - `BURN_TOKENS` (11) -- holder authorizes burning their tokens
130
- - `CLAIM_TOKENS` (12) -- holder authorizes claiming their credits as ERC-20
131
- - `TRANSFER_CREDITS` (13) -- holder authorizes transferring their credit balance
132
-
133
- 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).
134
-
135
- ### 4. Dual-Purpose Permission IDs
136
-
137
- Two IDs intentionally gate both a "set" and a "lock" operation:
138
-
139
- - **SET_BUYBACK_HOOK (29)**: Gates both `setHookFor` (configurable) and `lockHookFor` (permanent). An operator with this permission can permanently lock the hook configuration.
140
- - **SET_ROUTER_TERMINAL (30)**: Gates both `setTerminalFor` (configurable) and `lockTerminalFor` (permanent). An operator with this permission can permanently lock the terminal configuration.
141
-
142
- 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.
143
-
144
- ### 5. ROOT Permission Safety
145
-
146
- ROOT (ID 1) is the superadmin permission. The `JBPermissions` contract implements critical safety rails:
147
-
148
- - ROOT cannot be granted for wildcard `projectId = 0` (would grant root across all projects)
149
- - A ROOT operator can call `setPermissionsFor` on behalf of the account but cannot grant ROOT to others
150
- - ROOT cannot be included when setting wildcard project permissions
151
-
152
- Verify these constraints are enforced in `JBPermissions`, not in this library (this library only defines the constant).
153
-
154
- ### 6. SET_TERMINALS (ID 15) Risk
155
-
156
- 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:
157
-
158
- - Granting `SET_TERMINALS` alone is sufficient to replace the entire terminal list, potentially breaking a project.
159
- - Granting `LAUNCH_RULESETS` without also granting `SET_TERMINALS` will cause `launchRulesetsFor` to revert (dual permission check).
14
+ In scope:
15
+ - `src/JBPermissionIds.sol`
160
16
 
161
- ## Invariants to Verify
17
+ ## Critical Invariants
162
18
 
163
- 1. **Uniqueness**: All 34 constants have unique values in the range [1, 34].
164
- 2. **Completeness**: Every `_requirePermissionFrom` call in the ecosystem uses one of these constants (no magic numbers).
165
- 3. **Type consistency**: All constants are `uint8`, matching the parameter type of `JBPermissions.hasPermission`.
166
- 4. **No ID 0**: No constant has value 0 (reserved and forbidden by `JBPermissions`).
167
- 5. **Sequential assignment**: IDs are assigned 1 through 34 with no gaps.
19
+ 1. Each permission semantic has one stable numeric ID.
20
+ 2. No two distinct permissions share an ID.
21
+ 3. IDs match the expectations of all dependent repos in this workspace.
22
+ 4. IDs 35-39 (revnet-core delegation: `HIDE_TOKENS`, `OPEN_LOAN`, `REALLOCATE_LOAN`, `REPAY_LOAN`, `REVEAL_TOKENS`) are consumed by `revnet-core-v6` — verify they match the values used in `REVHiddenTokens` and `REVLoans`.
168
23
 
169
- ## Testing Setup
24
+ ## Threat Model
170
25
 
171
- 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.
26
+ Prioritize stale or inconsistent constants, especially where wildcard grants or deployer permissions depend on a specific numeric value.
172
27
 
173
- ```bash
174
- cd nana-permission-ids-v6
175
- forge build # Ensures the library compiles
176
- ```
28
+ ## Build And Verification
177
29
 
178
- To verify ID usage across the ecosystem:
179
- ```bash
180
- # Search for permission ID usage in consuming repos
181
- 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/
182
- ```
30
+ Standard workflow:
31
+ - `npm install`
32
+ - `forge build`
183
33
 
184
- Go break it.
34
+ A meaningful finding here should show a real downstream permission check becoming broader, narrower, or mismatched because of the constant set.
package/CHANGELOG.md ADDED
@@ -0,0 +1,49 @@
1
+ # Changelog
2
+
3
+ ## Scope
4
+
5
+ This file describes the verified change from `nana-permission-ids-v5` to the current `nana-permission-ids-v6` repo.
6
+
7
+ ## Current v6 surface
8
+
9
+ - `JBPermissionIds`
10
+
11
+ ## Summary
12
+
13
+ - The numeric permission map shifted. `LAUNCH_RULESETS` was inserted near the top of the sequence and every downstream numeric value moved with it.
14
+ - v6 adds permissions for capabilities that did not exist in the old map, including `LAUNCH_RULESETS`, `ADD_TERMINALS`, `SET_TOKEN_METADATA`, `SET_BUYBACK_HOOK`, `SET_ROUTER_TERMINAL`, and `SET_SUCKER_DEPRECATION`.
15
+ - The old swap-terminal-specific permissions are gone because the deployed ecosystem no longer centers on `nana-swap-terminal-v5`.
16
+ - `SUCKER_SAFETY` no longer covers every safety action by itself. `SET_SUCKER_DEPRECATION` is its own permission in v6.
17
+
18
+ ## v6 additions: revnet-core delegation (IDs 35–39)
19
+
20
+ - `HIDE_TOKENS` (35) — hide tokens on behalf of a holder via `REVHiddenTokens.hideTokensOf`. Checked against the token holder.
21
+ - `OPEN_LOAN` (36) — open a loan on behalf of a token holder via `REVLoans.borrowFrom`. Checked against the token holder.
22
+ - `REALLOCATE_LOAN` (37) — reallocate loan collateral on behalf of a loan NFT owner via `REVLoans.reallocateCollateralFromLoan`. Checked against the loan NFT owner.
23
+ - `REPAY_LOAN` (38) — repay a loan on behalf of a loan NFT owner via `REVLoans.repayLoan`. Checked against the loan NFT owner.
24
+ - `REVEAL_TOKENS` (39) — reveal hidden tokens on behalf of a holder via `REVHiddenTokens.revealTokensOf`. Checked against the token holder.
25
+
26
+ These are consumed by `revnet-core-v6` and checked via `JBPermissioned._requirePermissionFrom` (for `REVHiddenTokens`) or inline `PERMISSIONS.hasPermission` calls (for `REVLoans`).
27
+
28
+ ## Verified deltas
29
+
30
+ - `QUEUE_RULESETS` no longer also covers `launchRulesetsFor`; `LAUNCH_RULESETS` is its own constant.
31
+ - `ADD_TERMINALS` was inserted between `SET_TERMINALS` and `SET_PRIMARY_TERMINAL`.
32
+ - `SET_TOKEN_METADATA`, `SET_BUYBACK_HOOK`, `SET_ROUTER_TERMINAL`, and `SET_SUCKER_DEPRECATION` are new constants.
33
+ - `ADD_SWAP_TERMINAL_POOL` and `ADD_SWAP_TERMINAL_TWAP_PARAMS` were removed.
34
+
35
+ ## Breaking ABI changes
36
+
37
+ - There is no runtime contract ABI to port here.
38
+ - The breaking surface is compile-time and application-logic-level: constant names, meanings, and numeric values changed.
39
+
40
+ ## Indexer impact
41
+
42
+ - None directly from this repo.
43
+ - Indirectly, any off-chain access-control model keyed to raw numeric IDs must be updated.
44
+
45
+ ## Migration notes
46
+
47
+ - Hardcoded numeric permission IDs from v5 are stale and unsafe.
48
+ - Rebuild every permission check from the named v6 constants.
49
+ - Treat this repo as application-logic-critical even though it is not a large runtime surface.
package/README.md CHANGED
@@ -1,119 +1,59 @@
1
1
  # Juicebox Permission IDs
2
2
 
3
- The single source of truth for access control across the Juicebox V6 ecosystem. This library defines 34 `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
+ `@bananapus/permission-ids-v6` is the shared constant library for Juicebox V6 operator permissions. It gives every repo in the ecosystem the same numeric meaning for the same permission name.
4
4
 
5
- ## How permissions work
5
+ Architecture: [ARCHITECTURE.md](./ARCHITECTURE.md)
6
6
 
7
- Juicebox V6 access control is built on a simple model: an **account** (typically a project owner) grants an **operator** (any address) a set of permission IDs scoped to a specific **project ID**. When a permissioned function is called, the contract checks that the caller either *is* the account or *has* the required permission ID for that project.
7
+ ## Overview
8
8
 
9
- Permissions are stored as a 256-bit packed integer in `JBPermissions`, where each bit position corresponds to a permission ID. This library provides human-readable names for those bit positions.
9
+ The library is intentionally simple: one Solidity file, no storage, no deployment, and no runtime logic. Its value comes from consistency.
10
10
 
11
- ```
12
- permissionsOf[operator][account][projectId] => uint256 (packed bits)
13
- ```
11
+ `JBPermissions` stores operator permissions as packed bits. This package names the bit positions so integrations do not drift across repos.
14
12
 
15
- ## Architecture
13
+ Use this repo as the single source of truth for permission numbers. Do not redefine permission IDs locally in downstream repos.
16
14
 
17
- | Contract | Description |
18
- |----------|-------------|
19
- | `JBPermissionIds` | Solidity library with 34 `uint8 internal constant` permission IDs (values 1--34). No state, no functions, no dependencies. Pragma `^0.8.0` for maximum compatibility. |
15
+ If the question is "who can do this action?" you will still need `JBPermissions` in `nana-core-v6`. This repo only tells you what the numeric labels mean.
20
16
 
21
- ## Repository Layout
17
+ ## Current Permission Ranges
22
18
 
23
- ```
24
- src/
25
- └── JBPermissionIds.sol ── 34 uint8 constants (the only source file)
26
- ```
19
+ | Range | Area |
20
+ | --- | --- |
21
+ | `1` | global `ROOT` permission |
22
+ | `2-22` | core protocol permissions |
23
+ | `23-26` | 721 hook permissions |
24
+ | `27-29` | buyback hook permissions |
25
+ | `30` | router terminal permission |
26
+ | `31-34` | sucker and omnichain permissions |
27
+ | `35-39` | revnet-core permissions (hidden tokens, loans) |
28
+
29
+ The exact constants live in `src/JBPermissionIds.sol`.
27
30
 
28
- No tests, interfaces, or deployment scripts -- this repo is a pure constant library.
29
-
30
- ## All permission IDs
31
-
32
- ### Global (ID 1)
33
-
34
- | ID | Name | Description |
35
- |----|------|-------------|
36
- | 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. |
37
-
38
- ### Core (IDs 2--22) -- [nana-core-v6](https://github.com/Bananapus/nana-core-v6)
39
-
40
- | ID | Name | Checked in | Description |
41
- |----|------|------------|-------------|
42
- | 2 | `QUEUE_RULESETS` | `JBController.queueRulesetsOf` | Queue new rulesets for a project. Also required by `JB721TiersHookProjectDeployer` and `JBOmnichainDeployer`. |
43
- | 3 | `LAUNCH_RULESETS` | `JBController.launchRulesetsFor` | Launch a project's initial rulesets and terminals. Note: the caller also needs `SET_TERMINALS` (ID 15) since this function configures terminals. |
44
- | 4 | `CASH_OUT_TOKENS` | `JBMultiTerminal.cashOutTokensOf` | Cash out (redeem) a holder's tokens for a share of the project's surplus. Checked against the **token holder**, not the project owner. |
45
- | 5 | `SEND_PAYOUTS` | `JBMultiTerminal.sendPayoutsOf` | Send payouts to a project's splits up to its payout limit. |
46
- | 6 | `MIGRATE_TERMINAL` | `JBMultiTerminal.migrateBalanceOf` | Migrate a project's balance from one terminal to another. |
47
- | 7 | `SET_PROJECT_URI` | `JBController.setUriOf` | Set a project's metadata URI. |
48
- | 8 | `DEPLOY_ERC20` | `JBController.deployERC20For` | Deploy a new ERC-20 token for a project. |
49
- | 9 | `SET_TOKEN` | `JBController.setTokenFor` | Set an existing ERC-20 token for a project. |
50
- | 10 | `MINT_TOKENS` | `JBController.mintTokensOf` | Mint new project tokens. Only works if the current ruleset allows owner minting. |
51
- | 11 | `BURN_TOKENS` | `JBController.burnTokensOf` | Burn a holder's project tokens. Checked against the **token holder**, not the project owner. |
52
- | 12 | `CLAIM_TOKENS` | `JBController.claimTokensFor` | Claim a holder's internal credit balance as ERC-20 tokens. Checked against the **token holder**. |
53
- | 13 | `TRANSFER_CREDITS` | `JBController.transferCreditsFrom` | Transfer a holder's internal credit balance to another address. Checked against the **token holder**. |
54
- | 14 | `SET_CONTROLLER` | `JBDirectory.setControllerOf` | Set a project's controller in the directory. |
55
- | 15 | `SET_TERMINALS` | `JBDirectory.setTerminalsOf` | Set a project's terminals. **Warning:** can remove the primary terminal. Also required by `LAUNCH_RULESETS` (ID 3). |
56
- | 16 | `ADD_TERMINALS` | `JBDirectory.setPrimaryTerminalOf` | Add a new terminal to a project when `setPrimaryTerminalOf` implicitly adds it. |
57
- | 17 | `SET_PRIMARY_TERMINAL` | `JBDirectory.setPrimaryTerminalOf` | Set a project's primary terminal for a given token. |
58
- | 18 | `USE_ALLOWANCE` | `JBMultiTerminal.useAllowanceOf` | Use a project's surplus allowance to send funds to an arbitrary address. |
59
- | 19 | `SET_SPLIT_GROUPS` | `JBController.setSplitGroupsOf` | Set a project's split groups (how payouts and reserved tokens are distributed). |
60
- | 20 | `ADD_PRICE_FEED` | `JBController.addPriceFeedFor` | Add a price feed for a project. The controller checks this permission before calling `JBPrices.addPriceFeedFor`. |
61
- | 21 | `ADD_ACCOUNTING_CONTEXTS` | `JBMultiTerminal.addAccountingContextsFor` | Add accounting contexts (accepted tokens) to a terminal for a project. |
62
- | 22 | `SET_TOKEN_METADATA` | `JBController.setTokenMetadataOf` | Set a project token's name and symbol. Checked against the project owner. |
63
-
64
- ### 721 Hook (IDs 23--26) -- [nana-721-hook-v6](https://github.com/Bananapus/nana-721-hook-v6)
65
-
66
- | ID | Name | Checked in | Description |
67
- |----|------|------------|-------------|
68
- | 23 | `ADJUST_721_TIERS` | `JB721TiersHook.adjustTiers` | Add or remove NFT tiers. Also used by `CTPublisher` and `CTProjectOwner` in croptop-core-v6. |
69
- | 24 | `SET_721_METADATA` | `JB721TiersHook.setMetadata` | Set the metadata (base URI, contract URI, token URI resolver) for a 721 hook. |
70
- | 25 | `MINT_721` | `JB721TiersHook.mintFor` | Manually mint NFTs from specific tiers to a beneficiary. |
71
- | 26 | `SET_721_DISCOUNT_PERCENT` | `JB721TiersHook.setDiscountPercentOf` | Set the discount percent for one or more NFT tiers. |
72
-
73
- ### Buyback Hook (IDs 27--29) -- [nana-buyback-hook-v6](https://github.com/Bananapus/nana-buyback-hook-v6)
74
-
75
- | ID | Name | Checked in | Description |
76
- |----|------|------------|-------------|
77
- | 27 | `SET_BUYBACK_TWAP` | `JBBuybackHook.setTwapWindowOf` | Set the TWAP (time-weighted average price) oracle window for a project's buyback hook. |
78
- | 28 | `SET_BUYBACK_POOL` | `JBBuybackHook.setPoolFor`, `JBBuybackHook.initializePoolFor`, `JBBuybackHookRegistry.setPoolFor`, `JBBuybackHookRegistry.initializePoolFor` | Set the Uniswap pool for a project's buyback hook. |
79
- | 29 | `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. |
80
-
81
- ### Router Terminal (ID 30) -- [nana-router-terminal-v6](https://github.com/Bananapus/nana-router-terminal-v6)
82
-
83
- | ID | Name | Checked in | Description |
84
- |----|------|------------|-------------|
85
- | 30 | `SET_ROUTER_TERMINAL` | `JBRouterTerminalRegistry.setTerminalFor`, `JBRouterTerminalRegistry.lockTerminalFor` | Set or lock the router terminal for a project. |
86
-
87
- ### Suckers / Omnichain (IDs 31--34) -- [nana-suckers-v6](https://github.com/Bananapus/nana-suckers-v6)
88
-
89
- | ID | Name | Checked in | Description |
90
- |----|------|------------|-------------|
91
- | 31 | `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. |
92
- | 32 | `DEPLOY_SUCKERS` | `JBSuckerRegistry.deploySuckersFor` | Deploy new sucker contracts for a project. Also checked by `JBOmnichainDeployer` and `CTDeployer`. |
93
- | 33 | `SUCKER_SAFETY` | `JBSucker.enableEmergencyHatchFor` | Enable the emergency hatch for a sucker, allowing the project owner to recover stuck tokens. |
94
- | 34 | `SET_SUCKER_DEPRECATION` | `JBSucker.setDeprecation` | Set the deprecation status of a sucker (ENABLED, DEPRECATION_PENDING, SENDING_DISABLED, DEPRECATED). |
95
-
96
- ## Gotchas
97
-
98
- - **ROOT is dangerous.** It grants every permission on every contract. An operator with ROOT for project 5 can queue rulesets, send payouts, migrate terminals, mint tokens, etc. -- all on behalf of the granting account for that project.
99
- - **ROOT cannot be granted for the wildcard project ID.** `JBPermissions` reverts with `JBPermissions_CantSetRootPermissionForWildcardProject()` if you try to set ROOT with `projectId = 0`. This prevents a single operator from controlling all of an account's projects.
100
- - **ROOT operators can set permissions for others, but cannot grant ROOT.** A ROOT operator can call `setPermissionsFor` on behalf of the account, but only if the new permission set does NOT include ROOT and is NOT for the wildcard project ID.
101
- - **Permission ID 0 is reserved.** `JBPermissions` reverts with `JBPermissions_NoZeroPermission()` if bit 0 is set in any packed permission value. IDs start at 1.
102
- - **Wildcard project ID (0) applies to all projects.** Granting a permission with `projectId = 0` means the operator has that permission for every project owned by the account. Use with caution.
103
- - **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.
104
- - **LAUNCH_RULESETS requires SET_TERMINALS.** `launchRulesetsFor` enforces both `LAUNCH_RULESETS` and `SET_TERMINALS` because it configures terminals as part of the launch.
105
- - **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.
106
- - **ADD_TERMINALS (16) vs SET_TERMINALS (15).** `SET_TERMINALS` replaces the entire terminal list and can remove the primary terminal. `ADD_TERMINALS` is a narrower permission checked when `setPrimaryTerminalOf` implicitly adds a new terminal that is not already in the project's terminal list.
107
- - **The uint8 type limits IDs to 0--255.** Currently 34 are defined (1--34), leaving room for future extensions.
31
+ ## Mental Model
32
+
33
+ This repo is a coordination artifact, not a behavior repo. Its value is that every other package can import the same names and mean the same thing.
108
34
 
109
35
  ## Install
110
36
 
37
+ ```bash
38
+ npm install @bananapus/permission-ids-v6
39
+ ```
40
+
41
+ ## Development
42
+
111
43
  ```bash
112
44
  npm install
45
+ forge build
46
+ ```
47
+
48
+ ## Repository Layout
49
+
50
+ ```text
51
+ src/
52
+ JBPermissionIds.sol
113
53
  ```
114
54
 
115
- ## Develop
55
+ ## Risks And Notes
116
56
 
117
- | Command | Description |
118
- |---------|-------------|
119
- | `forge build` | Compile contracts |
57
+ - `ROOT` is intentionally powerful and should be granted sparingly
58
+ - wildcard project scope is convenient but easy to misuse operationally
59
+ - any change to this file has ecosystem-wide consequences because other repos assume the values are stable