@bananapus/permission-ids-v6 0.0.15 → 0.0.17

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 40 defined permission IDs and what they control:
14
39
 
15
40
  | ID | Constant | Used By | What It Controls |
16
41
  |----|----------|---------|-----------------|
@@ -36,20 +61,26 @@ All 34 defined permission IDs and what they control:
36
61
  | 20 | `ADD_PRICE_FEED` | nana-core (`JBController`) | `JBController.addPriceFeedFor` (which internally calls `JBPrices.addPriceFeedFor`) -- add a price feed for a project. |
37
62
  | 21 | `ADD_ACCOUNTING_CONTEXTS` | nana-core (`JBMultiTerminal`) | `JBMultiTerminal.addAccountingContextsFor` -- add accepted tokens to a terminal. |
38
63
  | 22 | `SET_TOKEN_METADATA` | nana-core (`JBController`) | `JBController.setTokenMetadataOf` -- set a project token's name and symbol. |
39
- | 23 | `ADJUST_721_TIERS` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.adjustTiers` -- add or remove NFT tiers. |
40
- | 24 | `SET_721_METADATA` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.setMetadata` -- set NFT metadata URIs. |
41
- | 25 | `MINT_721` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.mintFor` -- manually mint NFTs to a beneficiary. |
42
- | 26 | `SET_721_DISCOUNT_PERCENT` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.setDiscountPercentOf` -- set discount percent on NFT tiers. |
43
- | 27 | `SET_BUYBACK_TWAP` | nana-buyback-hook (`JBBuybackHook`) | `JBBuybackHook.setTwapWindowOf` -- configure the TWAP oracle window. |
44
- | 28 | `SET_BUYBACK_POOL` | nana-buyback-hook (`JBBuybackHook`) | `JBBuybackHook.setPoolFor` -- set the Uniswap pool for buybacks. |
45
- | 29 | `SET_BUYBACK_HOOK` | nana-buyback-hook (`JBBuybackHookRegistry`) | `JBBuybackHookRegistry.setHookFor` and `lockHookFor` -- configure and permanently lock the buyback hook. |
46
- | 30 | `SET_ROUTER_TERMINAL` | nana-router-terminal (`JBRouterTerminalRegistry`) | `JBRouterTerminalRegistry.setTerminalFor` and `lockTerminalFor` -- configure and permanently lock the router terminal. |
47
- | 31 | `MAP_SUCKER_TOKEN` | nana-suckers (`JBSucker`) | `JBSucker.mapToken` -- map an ERC-20 to its remote chain counterpart. Immutable once the outbox tree has entries. |
48
- | 32 | `DEPLOY_SUCKERS` | nana-suckers (`JBSuckerRegistry`) | `JBSuckerRegistry.deploySuckersFor` -- deploy sucker contracts for cross-chain bridging. |
49
- | 33 | `SUCKER_SAFETY` | nana-suckers (`JBSucker`) | `JBSucker.enableEmergencyHatchFor` -- enable the emergency hatch to recover stuck tokens. |
50
- | 34 | `SET_SUCKER_DEPRECATION` | nana-suckers (`JBSucker`) | `JBSucker.setDeprecation` -- set deprecation status (ENABLED, DEPRECATION_PENDING, SENDING_DISABLED, DEPRECATED). |
51
-
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.
64
+ | 23 | `SIGN_FOR_ERC20` | nana-core (`JBERC20`) | Sign messages on behalf of a project's ERC-20 token via ERC-1271. Used for Etherscan contract verification and other off-chain signature validation. |
65
+ | 24 | `ADJUST_721_TIERS` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.adjustTiers` -- add or remove NFT tiers. |
66
+ | 25 | `SET_721_METADATA` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.setMetadata` -- set NFT metadata URIs. |
67
+ | 26 | `MINT_721` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.mintFor` -- manually mint NFTs to a beneficiary. |
68
+ | 27 | `SET_721_DISCOUNT_PERCENT` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.setDiscountPercentOf` -- set discount percent on NFT tiers. |
69
+ | 28 | `SET_BUYBACK_TWAP` | nana-buyback-hook (`JBBuybackHook`) | `JBBuybackHook.setTwapWindowOf` -- configure the TWAP oracle window. |
70
+ | 29 | `SET_BUYBACK_POOL` | nana-buyback-hook (`JBBuybackHook`) | `JBBuybackHook.setPoolFor` -- set the Uniswap pool for buybacks. |
71
+ | 30 | `SET_BUYBACK_HOOK` | nana-buyback-hook (`JBBuybackHookRegistry`) | `JBBuybackHookRegistry.setHookFor` and `lockHookFor` -- configure and permanently lock the buyback hook. |
72
+ | 31 | `SET_ROUTER_TERMINAL` | nana-router-terminal (`JBRouterTerminalRegistry`) | `JBRouterTerminalRegistry.setTerminalFor` and `lockTerminalFor` -- configure and permanently lock the router terminal. |
73
+ | 32 | `MAP_SUCKER_TOKEN` | nana-suckers (`JBSucker`) | `JBSucker.mapToken` -- map an ERC-20 to its remote chain counterpart. Immutable once the outbox tree has entries. |
74
+ | 33 | `DEPLOY_SUCKERS` | nana-suckers (`JBSuckerRegistry`) | `JBSuckerRegistry.deploySuckersFor` -- deploy sucker contracts for cross-chain bridging. |
75
+ | 34 | `SUCKER_SAFETY` | nana-suckers (`JBSucker`) | `JBSucker.enableEmergencyHatchFor` -- enable the emergency hatch to recover stuck tokens. |
76
+ | 35 | `SET_SUCKER_DEPRECATION` | nana-suckers (`JBSucker`) | `JBSucker.setDeprecation` -- set deprecation status (ENABLED, DEPRECATION_PENDING, SENDING_DISABLED, DEPRECATED). |
77
+ | 36 | `HIDE_TOKENS` | revnet-core (`REVHiddenTokens`) | `REVHiddenTokens.hideTokensOf` -- hide (burn) tokens on behalf of a holder. Checked against the **token holder**. |
78
+ | 37 | `OPEN_LOAN` | revnet-core (`REVLoans`) | `REVLoans.borrowFrom` -- open a loan on behalf of a token holder. Checked against the **token holder**. |
79
+ | 38 | `REALLOCATE_LOAN` | revnet-core (`REVLoans`) | `REVLoans.reallocateCollateralFromLoan` -- reallocate loan collateral on behalf of a loan NFT owner. Checked against the **loan NFT owner**. |
80
+ | 39 | `REPAY_LOAN` | revnet-core (`REVLoans`) | `REVLoans.repayLoan` -- repay a loan on behalf of a loan NFT owner. Checked against the **loan NFT owner**. |
81
+ | 40 | `REVEAL_TOKENS` | revnet-core (`REVHiddenTokens`) | `REVHiddenTokens.revealTokensOf` -- reveal (re-mint) hidden tokens on behalf of a holder. Checked against the **token holder**. |
82
+
83
+ IDs 0 and 41-255 are unused. ID 0 is reserved and cannot be set. IDs 41-255 are available for future ecosystem extensions.
53
84
 
54
85
  ## ROOT Permission
55
86
 
@@ -93,13 +124,13 @@ Some permissions warrant extra caution when granting:
93
124
  - **`ROOT` (1):** Full access to all gated functions for a project.
94
125
  - **`SET_TERMINALS` (15):** Can remove the primary terminal, breaking payments and cashouts.
95
126
  - **`USE_ALLOWANCE` (18):** Can send surplus funds to any address.
96
- - **`SET_BUYBACK_HOOK` (29):** Can permanently lock the buyback hook configuration.
97
- - **`SET_ROUTER_TERMINAL` (30):** Can permanently lock the router terminal configuration.
127
+ - **`SET_BUYBACK_HOOK` (30):** Can permanently lock the buyback hook configuration.
128
+ - **`SET_ROUTER_TERMINAL` (31):** Can permanently lock the router terminal configuration.
98
129
  - **`MINT_TOKENS` (10):** Can inflate token supply (subject to ruleset allowing owner minting).
99
130
 
100
131
  ## Holder vs. Owner Permissions
101
132
 
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**:
133
+ 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
134
 
104
135
  | Permission | Checked Against |
105
136
  |-----------|----------------|
@@ -107,5 +138,10 @@ Most permissions are checked against the **project owner** (the account that own
107
138
  | `BURN_TOKENS` (11) | Token holder |
108
139
  | `CLAIM_TOKENS` (12) | Token holder |
109
140
  | `TRANSFER_CREDITS` (13) | Token holder |
141
+ | `HIDE_TOKENS` (36) | Token holder |
142
+ | `OPEN_LOAN` (37) | Token holder |
143
+ | `REALLOCATE_LOAN` (38) | Loan NFT owner |
144
+ | `REPAY_LOAN` (39) | Loan NFT owner |
145
+ | `REVEAL_TOKENS` (40) | Token holder |
110
146
 
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.
147
+ 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,35 @@
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. ID 23 (`SIGN_FOR_ERC20`) is consumed by `nana-core-v6` (`JBERC20`) verify it matches the value used for ERC-1271 signature delegation.
23
+ 5. IDs 36-40 (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
24
 
169
- ## Testing Setup
25
+ ## Threat Model
170
26
 
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.
27
+ Prioritize stale or inconsistent constants, especially where wildcard grants or deployer permissions depend on a specific numeric value.
172
28
 
173
- ```bash
174
- cd nana-permission-ids-v6
175
- forge build # Ensures the library compiles
176
- ```
29
+ ## Build And Verification
177
30
 
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
- ```
31
+ Standard workflow:
32
+ - `npm install`
33
+ - `forge build`
183
34
 
184
- Go break it.
35
+ 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,53 @@
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: nana-core ERC-1271 delegation (ID 23)
19
+
20
+ - `SIGN_FOR_ERC20` (23) — sign messages on behalf of a project's ERC-20 token via ERC-1271. Used for Etherscan contract verification and other off-chain signature validation.
21
+
22
+ ## v6 additions: revnet-core delegation (IDs 36–40)
23
+
24
+ - `HIDE_TOKENS` (36) — hide tokens on behalf of a holder via `REVHiddenTokens.hideTokensOf`. Checked against the token holder.
25
+ - `OPEN_LOAN` (37) — open a loan on behalf of a token holder via `REVLoans.borrowFrom`. Checked against the token holder.
26
+ - `REALLOCATE_LOAN` (38) — reallocate loan collateral on behalf of a loan NFT owner via `REVLoans.reallocateCollateralFromLoan`. Checked against the loan NFT owner.
27
+ - `REPAY_LOAN` (39) — repay a loan on behalf of a loan NFT owner via `REVLoans.repayLoan`. Checked against the loan NFT owner.
28
+ - `REVEAL_TOKENS` (40) — reveal hidden tokens on behalf of a holder via `REVHiddenTokens.revealTokensOf`. Checked against the token holder.
29
+
30
+ These are consumed by `revnet-core-v6` and checked via `JBPermissioned._requirePermissionFrom` (for `REVHiddenTokens`) or inline `PERMISSIONS.hasPermission` calls (for `REVLoans`).
31
+
32
+ ## Verified deltas
33
+
34
+ - `QUEUE_RULESETS` no longer also covers `launchRulesetsFor`; `LAUNCH_RULESETS` is its own constant.
35
+ - `ADD_TERMINALS` was inserted between `SET_TERMINALS` and `SET_PRIMARY_TERMINAL`.
36
+ - `SET_TOKEN_METADATA`, `SET_BUYBACK_HOOK`, `SET_ROUTER_TERMINAL`, and `SET_SUCKER_DEPRECATION` are new constants.
37
+ - `ADD_SWAP_TERMINAL_POOL` and `ADD_SWAP_TERMINAL_TWAP_PARAMS` were removed.
38
+
39
+ ## Breaking ABI changes
40
+
41
+ - There is no runtime contract ABI to port here.
42
+ - The breaking surface is compile-time and application-logic-level: constant names, meanings, and numeric values changed.
43
+
44
+ ## Indexer impact
45
+
46
+ - None directly from this repo.
47
+ - Indirectly, any off-chain access-control model keyed to raw numeric IDs must be updated.
48
+
49
+ ## Migration notes
50
+
51
+ - Hardcoded numeric permission IDs from v5 are stale and unsafe.
52
+ - Rebuild every permission check from the named v6 constants.
53
+ - Treat this repo as application-logic-critical even though it is not a large runtime surface.