@bananapus/permission-ids-v6 0.0.14 → 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 +62 -26
- package/ARCHITECTURE.md +36 -60
- package/AUDIT_INSTRUCTIONS.md +21 -170
- package/CHANGELOG.md +49 -0
- package/README.md +40 -98
- package/RISKS.md +22 -8
- package/SKILLS.md +19 -162
- package/STYLE_GUIDE.md +71 -19
- package/USER_JOURNEYS.md +30 -284
- package/package.json +1 -1
- package/references/runtime.md +15 -0
- package/src/JBPermissionIds.sol +34 -20
- package/CHANGE_LOG.md +0 -155
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
|
|
38
|
+
All 39 defined permission IDs and what they control:
|
|
14
39
|
|
|
15
40
|
| ID | Constant | Used By | What It Controls |
|
|
16
41
|
|----|----------|---------|-----------------|
|
|
@@ -29,26 +54,32 @@ All 33 defined permission IDs and what they control:
|
|
|
29
54
|
| 13 | `TRANSFER_CREDITS` | nana-core (`JBController`) | `JBController.transferCreditsFrom` -- transfer internal credits. Checked against the **token holder**. |
|
|
30
55
|
| 14 | `SET_CONTROLLER` | nana-core (`JBDirectory`) | `JBDirectory.setControllerOf` -- set a project's controller. |
|
|
31
56
|
| 15 | `SET_TERMINALS` | nana-core (`JBDirectory`) | `JBDirectory.setTerminalsOf` -- set a project's terminals. **Warning:** can remove the primary terminal. |
|
|
32
|
-
| 16 | `
|
|
33
|
-
| 17 | `
|
|
34
|
-
| 18 | `
|
|
35
|
-
| 19 | `
|
|
36
|
-
| 20 | `
|
|
37
|
-
| 21 | `
|
|
38
|
-
| 22 | `
|
|
39
|
-
| 23 | `
|
|
40
|
-
| 24 | `
|
|
41
|
-
| 25 | `
|
|
42
|
-
| 26 | `
|
|
43
|
-
| 27 | `
|
|
44
|
-
| 28 | `
|
|
45
|
-
| 29 | `
|
|
46
|
-
| 30 | `
|
|
47
|
-
| 31 | `
|
|
48
|
-
| 32 | `
|
|
49
|
-
| 33 | `
|
|
50
|
-
|
|
51
|
-
|
|
57
|
+
| 16 | `ADD_TERMINALS` | nana-core (`JBDirectory`) | `JBDirectory.setPrimaryTerminalOf` -- add a new terminal when `setPrimaryTerminalOf` implicitly adds it. |
|
|
58
|
+
| 17 | `SET_PRIMARY_TERMINAL` | nana-core (`JBDirectory`) | `JBDirectory.setPrimaryTerminalOf` -- set the primary terminal for a token. |
|
|
59
|
+
| 18 | `USE_ALLOWANCE` | nana-core (`JBMultiTerminal`) | `JBMultiTerminal.useAllowanceOf` -- spend surplus allowance to an arbitrary address. |
|
|
60
|
+
| 19 | `SET_SPLIT_GROUPS` | nana-core (`JBController`) | `JBController.setSplitGroupsOf` -- configure payout and reserved token splits. |
|
|
61
|
+
| 20 | `ADD_PRICE_FEED` | nana-core (`JBController`) | `JBController.addPriceFeedFor` (which internally calls `JBPrices.addPriceFeedFor`) -- add a price feed for a project. |
|
|
62
|
+
| 21 | `ADD_ACCOUNTING_CONTEXTS` | nana-core (`JBMultiTerminal`) | `JBMultiTerminal.addAccountingContextsFor` -- add accepted tokens to a terminal. |
|
|
63
|
+
| 22 | `SET_TOKEN_METADATA` | nana-core (`JBController`) | `JBController.setTokenMetadataOf` -- set a project token's name and symbol. |
|
|
64
|
+
| 23 | `ADJUST_721_TIERS` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.adjustTiers` -- add or remove NFT tiers. |
|
|
65
|
+
| 24 | `SET_721_METADATA` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.setMetadata` -- set NFT metadata URIs. |
|
|
66
|
+
| 25 | `MINT_721` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.mintFor` -- manually mint NFTs to a beneficiary. |
|
|
67
|
+
| 26 | `SET_721_DISCOUNT_PERCENT` | nana-721-hook (`JB721TiersHook`) | `JB721TiersHook.setDiscountPercentOf` -- set discount percent on NFT tiers. |
|
|
68
|
+
| 27 | `SET_BUYBACK_TWAP` | nana-buyback-hook (`JBBuybackHook`) | `JBBuybackHook.setTwapWindowOf` -- configure the TWAP oracle window. |
|
|
69
|
+
| 28 | `SET_BUYBACK_POOL` | nana-buyback-hook (`JBBuybackHook`) | `JBBuybackHook.setPoolFor` -- set the Uniswap pool for buybacks. |
|
|
70
|
+
| 29 | `SET_BUYBACK_HOOK` | nana-buyback-hook (`JBBuybackHookRegistry`) | `JBBuybackHookRegistry.setHookFor` and `lockHookFor` -- configure and permanently lock the buyback hook. |
|
|
71
|
+
| 30 | `SET_ROUTER_TERMINAL` | nana-router-terminal (`JBRouterTerminalRegistry`) | `JBRouterTerminalRegistry.setTerminalFor` and `lockTerminalFor` -- configure and permanently lock the router terminal. |
|
|
72
|
+
| 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. |
|
|
73
|
+
| 32 | `DEPLOY_SUCKERS` | nana-suckers (`JBSuckerRegistry`) | `JBSuckerRegistry.deploySuckersFor` -- deploy sucker contracts for cross-chain bridging. |
|
|
74
|
+
| 33 | `SUCKER_SAFETY` | nana-suckers (`JBSucker`) | `JBSucker.enableEmergencyHatchFor` -- enable the emergency hatch to recover stuck tokens. |
|
|
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**. |
|
|
81
|
+
|
|
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.
|
|
52
83
|
|
|
53
84
|
## ROOT Permission
|
|
54
85
|
|
|
@@ -91,14 +122,14 @@ Some permissions warrant extra caution when granting:
|
|
|
91
122
|
|
|
92
123
|
- **`ROOT` (1):** Full access to all gated functions for a project.
|
|
93
124
|
- **`SET_TERMINALS` (15):** Can remove the primary terminal, breaking payments and cashouts.
|
|
94
|
-
- **`USE_ALLOWANCE` (
|
|
95
|
-
- **`SET_BUYBACK_HOOK` (
|
|
96
|
-
- **`SET_ROUTER_TERMINAL` (
|
|
125
|
+
- **`USE_ALLOWANCE` (18):** Can send surplus funds to any address.
|
|
126
|
+
- **`SET_BUYBACK_HOOK` (29):** Can permanently lock the buyback hook configuration.
|
|
127
|
+
- **`SET_ROUTER_TERMINAL` (30):** Can permanently lock the router terminal configuration.
|
|
97
128
|
- **`MINT_TOKENS` (10):** Can inflate token supply (subject to ruleset allowing owner minting).
|
|
98
129
|
|
|
99
130
|
## Holder vs. Owner Permissions
|
|
100
131
|
|
|
101
|
-
Most permissions are checked against the **project owner** (the account that owns the project NFT).
|
|
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**:
|
|
102
133
|
|
|
103
134
|
| Permission | Checked Against |
|
|
104
135
|
|-----------|----------------|
|
|
@@ -106,5 +137,10 @@ Most permissions are checked against the **project owner** (the account that own
|
|
|
106
137
|
| `BURN_TOKENS` (11) | Token holder |
|
|
107
138
|
| `CLAIM_TOKENS` (12) | Token holder |
|
|
108
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 |
|
|
109
145
|
|
|
110
|
-
This means a token holder can grant an operator permission to cash out, burn, claim, or
|
|
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,66 +1,42 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Architecture
|
|
2
2
|
|
|
3
3
|
## Purpose
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
##
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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 | `SET_PRIMARY_TERMINAL` | nana-core | `JBDirectory.setPrimaryTerminalOf` |
|
|
46
|
-
| 17 | `USE_ALLOWANCE` | nana-core | `JBMultiTerminal.useAllowanceOf` |
|
|
47
|
-
| 18 | `SET_SPLIT_GROUPS` | nana-core | `JBController.setSplitGroupsOf` |
|
|
48
|
-
| 19 | `ADD_PRICE_FEED` | nana-core | `JBController.addPriceFeedFor` |
|
|
49
|
-
| 20 | `ADD_ACCOUNTING_CONTEXTS` | nana-core | `JBMultiTerminal.addAccountingContextsFor` |
|
|
50
|
-
| 21 | `SET_TOKEN_METADATA` | nana-core | `JBController.setTokenMetadataOf` |
|
|
51
|
-
| 22 | `ADJUST_721_TIERS` | nana-721-hook | `JB721TiersHook.adjustTiers` |
|
|
52
|
-
| 23 | `SET_721_METADATA` | nana-721-hook | `JB721TiersHook.setMetadata` |
|
|
53
|
-
| 24 | `MINT_721` | nana-721-hook | `JB721TiersHook.mintFor` |
|
|
54
|
-
| 25 | `SET_721_DISCOUNT_PERCENT` | nana-721-hook | `JB721TiersHook.setDiscountPercentOf` |
|
|
55
|
-
| 26 | `SET_BUYBACK_TWAP` | nana-buyback-hook | `JBBuybackHook.setTwapWindowOf` |
|
|
56
|
-
| 27 | `SET_BUYBACK_POOL` | nana-buyback-hook | `JBBuybackHook.setPoolFor` |
|
|
57
|
-
| 28 | `SET_BUYBACK_HOOK` | nana-buyback-hook | `JBBuybackHookRegistry.setHookFor` + `lockHookFor` |
|
|
58
|
-
| 29 | `SET_ROUTER_TERMINAL` | nana-router-terminal | `JBRouterTerminalRegistry.setTerminalFor` + `lockTerminalFor` |
|
|
59
|
-
| 30 | `MAP_SUCKER_TOKEN` | nana-suckers | `JBSucker.mapToken` |
|
|
60
|
-
| 31 | `DEPLOY_SUCKERS` | nana-suckers | `JBSuckerRegistry.deploySuckersFor` |
|
|
61
|
-
| 32 | `SUCKER_SAFETY` | nana-suckers | `JBSucker.enableEmergencyHatchFor` |
|
|
62
|
-
| 33 | `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.
|
|
63
33
|
|
|
64
34
|
## Dependencies
|
|
65
35
|
|
|
66
|
-
|
|
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.
|
package/AUDIT_INSTRUCTIONS.md
CHANGED
|
@@ -1,183 +1,34 @@
|
|
|
1
|
-
# Audit Instructions
|
|
1
|
+
# Audit Instructions
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
##
|
|
5
|
+
## Objective
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
src/JBPermissionIds.sol # Constants library (~67 lines, 33 permission IDs)
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
**Out of scope:** All consuming contracts (nana-core, nana-721-hook, nana-buyback-hook, nana-router-terminal, nana-suckers, revnet-core, croptop-core). The constants library has no dependencies.
|
|
49
|
-
|
|
50
|
-
## Architecture
|
|
51
|
-
|
|
52
|
-
`JBPermissionIds` is a Solidity library containing 33 `uint8 internal constant` values numbered 1 through 33. These IDs are used with `JBPermissions.setPermissionsFor()` to grant scoped access to protocol functions. The permission system stores permissions as a 256-bit packed integer (`uint256`), with each bit corresponding to a permission ID.
|
|
53
|
-
|
|
54
|
-
### Permission System Overview
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
permissionsOf[operator][account][projectId] => uint256 (one bit per permission ID)
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
- **Bit 0 (ID 0):** Reserved, cannot be set. `JBPermissions` reverts if bit 0 is included.
|
|
61
|
-
- **Bit 1 (ID 1, ROOT):** Grants all permissions across all contracts. Cannot be granted for wildcard `projectId = 0`.
|
|
62
|
-
- **Bits 2-33:** Individual permissions, each gating a specific function (or set of functions) in the ecosystem.
|
|
63
|
-
- **Bits 34-255:** Unassigned, available for future extensions.
|
|
64
|
-
|
|
65
|
-
### All Permission IDs
|
|
66
|
-
|
|
67
|
-
| ID | Constant | Gated Function(s) | Checked Against |
|
|
68
|
-
|----|----------|-------------------|-----------------|
|
|
69
|
-
| 1 | `ROOT` | All permissions (implicit) | Project owner |
|
|
70
|
-
| 2 | `QUEUE_RULESETS` | `JBController.queueRulesetsOf` | Project owner |
|
|
71
|
-
| 3 | `LAUNCH_RULESETS` | `JBController.launchRulesetsFor` (also needs SET_TERMINALS) | Project owner |
|
|
72
|
-
| 4 | `CASH_OUT_TOKENS` | `JBMultiTerminal.cashOutTokensOf` | **Token holder** |
|
|
73
|
-
| 5 | `SEND_PAYOUTS` | `JBMultiTerminal.sendPayoutsOf` | Project owner |
|
|
74
|
-
| 6 | `MIGRATE_TERMINAL` | `JBMultiTerminal.migrateBalanceOf` | Project owner |
|
|
75
|
-
| 7 | `SET_PROJECT_URI` | `JBController.setUriOf` | Project owner |
|
|
76
|
-
| 8 | `DEPLOY_ERC20` | `JBController.deployERC20For` | Project owner |
|
|
77
|
-
| 9 | `SET_TOKEN` | `JBController.setTokenFor` | Project owner |
|
|
78
|
-
| 10 | `MINT_TOKENS` | `JBController.mintTokensOf` | Project owner |
|
|
79
|
-
| 11 | `BURN_TOKENS` | `JBController.burnTokensOf` | **Token holder** |
|
|
80
|
-
| 12 | `CLAIM_TOKENS` | `JBController.claimTokensFor` | **Token holder** |
|
|
81
|
-
| 13 | `TRANSFER_CREDITS` | `JBController.transferCreditsFrom` | **Token holder** |
|
|
82
|
-
| 14 | `SET_CONTROLLER` | `JBDirectory.setControllerOf` | Project owner |
|
|
83
|
-
| 15 | `SET_TERMINALS` | `JBDirectory.setTerminalsOf` (WARNING: can remove primary terminal) | Project owner |
|
|
84
|
-
| 16 | `SET_PRIMARY_TERMINAL` | `JBDirectory.setPrimaryTerminalOf` | Project owner |
|
|
85
|
-
| 17 | `USE_ALLOWANCE` | `JBMultiTerminal.useAllowanceOf` | Project owner |
|
|
86
|
-
| 18 | `SET_SPLIT_GROUPS` | `JBController.setSplitGroupsOf` | Project owner |
|
|
87
|
-
| 19 | `ADD_PRICE_FEED` | `JBController.addPriceFeedFor` (not `JBPrices` directly) | Project owner |
|
|
88
|
-
| 20 | `ADD_ACCOUNTING_CONTEXTS` | `JBMultiTerminal.addAccountingContextsFor` | Project owner |
|
|
89
|
-
| 21 | `SET_TOKEN_METADATA` | `JBController.setTokenMetadataOf` | Project owner |
|
|
90
|
-
| 22 | `ADJUST_721_TIERS` | `JB721TiersHook.adjustTiers` | Hook owner |
|
|
91
|
-
| 23 | `SET_721_METADATA` | `JB721TiersHook.setMetadata` | Hook owner |
|
|
92
|
-
| 24 | `MINT_721` | `JB721TiersHook.mintFor` | Hook owner |
|
|
93
|
-
| 25 | `SET_721_DISCOUNT_PERCENT` | `JB721TiersHook.setDiscountPercentOf` | Hook owner |
|
|
94
|
-
| 26 | `SET_BUYBACK_TWAP` | `JBBuybackHook.setTwapWindowOf` | Project owner |
|
|
95
|
-
| 27 | `SET_BUYBACK_POOL` | `JBBuybackHook.setPoolFor` | Project owner |
|
|
96
|
-
| 28 | `SET_BUYBACK_HOOK` | `JBBuybackHookRegistry.setHookFor` + `lockHookFor` | Project owner |
|
|
97
|
-
| 29 | `SET_ROUTER_TERMINAL` | `JBRouterTerminalRegistry.setTerminalFor` + `lockTerminalFor` | Project owner |
|
|
98
|
-
| 30 | `MAP_SUCKER_TOKEN` | `JBSucker.mapToken` | Project owner |
|
|
99
|
-
| 31 | `DEPLOY_SUCKERS` | `JBSuckerRegistry.deploySuckersFor` | Project owner |
|
|
100
|
-
| 32 | `SUCKER_SAFETY` | `JBSucker.enableEmergencyHatchFor` | Project owner |
|
|
101
|
-
| 33 | `SET_SUCKER_DEPRECATION` | `JBSucker.setDeprecation` | Project owner |
|
|
102
|
-
|
|
103
|
-
## Priority Audit Areas
|
|
104
|
-
|
|
105
|
-
### 1. ID Uniqueness (Highest Priority)
|
|
106
|
-
|
|
107
|
-
Every permission ID must be unique. Two different constants with the same numeric value would cause one permission grant to silently authorize a different action. Verify:
|
|
108
|
-
|
|
109
|
-
- All 33 constants have distinct values.
|
|
110
|
-
- Values are sequential from 1 to 33 with no gaps and no duplicates.
|
|
111
|
-
- No other file in the ecosystem defines additional permission ID constants that could collide with these.
|
|
112
|
-
|
|
113
|
-
### 2. ID-to-Function Mapping Correctness
|
|
114
|
-
|
|
115
|
-
Each constant's doc comment claims it gates a specific function. Verify against the actual source code of each consuming contract:
|
|
116
|
-
|
|
117
|
-
- **nana-core-v6**: IDs 2-21 should match the `_requirePermissionFrom` calls in `JBController`, `JBMultiTerminal`, and `JBDirectory`.
|
|
118
|
-
- **nana-721-hook-v6**: IDs 22-25 should match permission checks in `JB721TiersHook`.
|
|
119
|
-
- **nana-buyback-hook-v6**: IDs 26-28 should match permission checks in `JBBuybackHook` and `JBBuybackHookRegistry`.
|
|
120
|
-
- **nana-router-terminal-v6**: ID 29 should match permission checks in `JBRouterTerminalRegistry`.
|
|
121
|
-
- **nana-suckers-v6**: IDs 30-33 should match permission checks in `JBSucker` and `JBSuckerRegistry`.
|
|
122
|
-
|
|
123
|
-
### 3. Holder-Scoped vs Owner-Scoped Permissions
|
|
124
|
-
|
|
125
|
-
Four permissions are checked against the **token holder**, not the project owner:
|
|
126
|
-
|
|
127
|
-
- `CASH_OUT_TOKENS` (4) -- holder authorizes cashout of their tokens
|
|
128
|
-
- `BURN_TOKENS` (11) -- holder authorizes burning their tokens
|
|
129
|
-
- `CLAIM_TOKENS` (12) -- holder authorizes claiming their credits as ERC-20
|
|
130
|
-
- `TRANSFER_CREDITS` (13) -- holder authorizes transferring their credit balance
|
|
131
|
-
|
|
132
|
-
Verify that no consuming contract incorrectly checks these against the project owner. A confused check would mean the project owner could burn or cash out any holder's tokens (massive vulnerability).
|
|
133
|
-
|
|
134
|
-
### 4. Dual-Purpose Permission IDs
|
|
135
|
-
|
|
136
|
-
Two IDs intentionally gate both a "set" and a "lock" operation:
|
|
137
|
-
|
|
138
|
-
- **SET_BUYBACK_HOOK (28)**: Gates both `setHookFor` (configurable) and `lockHookFor` (permanent). An operator with this permission can permanently lock the hook configuration.
|
|
139
|
-
- **SET_ROUTER_TERMINAL (29)**: Gates both `setTerminalFor` (configurable) and `lockTerminalFor` (permanent). An operator with this permission can permanently lock the terminal configuration.
|
|
140
|
-
|
|
141
|
-
Verify that project owners are aware of the locking implication when granting these permissions. The source code includes `@dev` documentation, but this is a significant trust escalation.
|
|
142
|
-
|
|
143
|
-
### 5. ROOT Permission Safety
|
|
144
|
-
|
|
145
|
-
ROOT (ID 1) is the superadmin permission. The `JBPermissions` contract implements critical safety rails:
|
|
146
|
-
|
|
147
|
-
- ROOT cannot be granted for wildcard `projectId = 0` (would grant root across all projects)
|
|
148
|
-
- A ROOT operator can call `setPermissionsFor` on behalf of the account but cannot grant ROOT to others
|
|
149
|
-
- ROOT cannot be included when setting wildcard project permissions
|
|
150
|
-
|
|
151
|
-
Verify these constraints are enforced in `JBPermissions`, not in this library (this library only defines the constant).
|
|
152
|
-
|
|
153
|
-
### 6. SET_TERMINALS (ID 15) Risk
|
|
154
|
-
|
|
155
|
-
The source comment warns: "Be careful - `SET_TERMINALS` can be used to remove the primary terminal." Additionally, `LAUNCH_RULESETS` (ID 3) requires both ID 3 AND ID 15 because the launch function configures terminals. Verify:
|
|
156
|
-
|
|
157
|
-
- Granting `SET_TERMINALS` alone is sufficient to replace the entire terminal list, potentially breaking a project.
|
|
158
|
-
- Granting `LAUNCH_RULESETS` without also granting `SET_TERMINALS` will cause `launchRulesetsFor` to revert (dual permission check).
|
|
14
|
+
In scope:
|
|
15
|
+
- `src/JBPermissionIds.sol`
|
|
159
16
|
|
|
160
|
-
## Invariants
|
|
17
|
+
## Critical Invariants
|
|
161
18
|
|
|
162
|
-
1.
|
|
163
|
-
2.
|
|
164
|
-
3.
|
|
165
|
-
4.
|
|
166
|
-
5. **Sequential assignment**: IDs are assigned 1 through 33 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`.
|
|
167
23
|
|
|
168
|
-
##
|
|
24
|
+
## Threat Model
|
|
169
25
|
|
|
170
|
-
|
|
26
|
+
Prioritize stale or inconsistent constants, especially where wildcard grants or deployer permissions depend on a specific numeric value.
|
|
171
27
|
|
|
172
|
-
|
|
173
|
-
cd nana-permission-ids-v6
|
|
174
|
-
forge build # Ensures the library compiles
|
|
175
|
-
```
|
|
28
|
+
## Build And Verification
|
|
176
29
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
grep -r "JBPermissionIds\." ../nana-core-v6/src/ ../nana-721-hook-v6/src/ ../nana-buyback-hook-v6/src/ ../nana-router-terminal-v6/src/ ../nana-suckers-v6/src/
|
|
181
|
-
```
|
|
30
|
+
Standard workflow:
|
|
31
|
+
- `npm install`
|
|
32
|
+
- `forge build`
|
|
182
33
|
|
|
183
|
-
|
|
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.
|