@bananapus/permission-ids-v6 0.0.17 → 0.0.18
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 +42 -127
- package/ARCHITECTURE.md +34 -23
- package/AUDIT_INSTRUCTIONS.md +24 -7
- package/README.md +36 -4
- package/RISKS.md +37 -23
- package/USER_JOURNEYS.md +79 -21
- package/package.json +1 -1
- package/references/runtime.md +3 -0
package/ADMINISTRATION.md
CHANGED
|
@@ -1,147 +1,62 @@
|
|
|
1
1
|
# Administration
|
|
2
2
|
|
|
3
|
-
Admin privileges and their scope in nana-permission-ids-v6.
|
|
4
|
-
|
|
5
3
|
## At A Glance
|
|
6
4
|
|
|
7
5
|
| Item | Details |
|
|
8
|
-
|
|
9
|
-
| Scope |
|
|
10
|
-
|
|
|
11
|
-
| Highest-risk actions |
|
|
12
|
-
| Recovery posture |
|
|
13
|
-
|
|
14
|
-
##
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| Scope | Shared permission ID namespace for the wider ecosystem |
|
|
8
|
+
| Control posture | Source-level coordination only |
|
|
9
|
+
| Highest-risk actions | Reordering or reusing IDs already assumed by deployed contracts |
|
|
10
|
+
| Recovery posture | Requires downstream code changes and redeployments where relevant |
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
|
|
14
|
+
`nana-permission-ids-v6` has no runtime admin surface. Its control significance is source-level: it defines the shared permission namespace used by the rest of the ecosystem.
|
|
15
|
+
|
|
16
|
+
## Control Model
|
|
17
|
+
|
|
18
|
+
- No owner
|
|
19
|
+
- No runtime governance
|
|
20
|
+
- No mutable onchain state
|
|
21
|
+
- Source-code level coordination only
|
|
22
|
+
|
|
23
|
+
## Roles
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
| Role | How Assigned | Scope | Notes |
|
|
26
|
+
| --- | --- | --- | --- |
|
|
27
|
+
| Maintainer | Source-code author | Ecosystem-wide | Can add or reorder constants only by editing and redeploying dependent code |
|
|
21
28
|
|
|
22
|
-
|
|
23
|
-
- The library itself has no admin keys, but stale docs around it can mislead operators about real powers elsewhere in the ecosystem.
|
|
29
|
+
## Privileged Surfaces
|
|
24
30
|
|
|
25
|
-
|
|
31
|
+
There are no privileged runtime functions. The only meaningful changes are source changes to `JBPermissionIds.sol`.
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
- There is no on-chain migration knob in this repo because it only ships compile-time constants.
|
|
33
|
+
## Immutable And One-Way
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
- Once deployed contracts depend on a given ID mapping, that mapping is effectively immutable for those deployments.
|
|
36
|
+
- Reusing or reordering IDs is a cross-repo breaking change.
|
|
31
37
|
|
|
32
|
-
|
|
38
|
+
## Operational Notes
|
|
33
39
|
|
|
34
|
-
|
|
40
|
+
- Add new permission IDs append-only.
|
|
41
|
+
- Update downstream docs and call sites in the same change set.
|
|
42
|
+
- Treat permission ID changes as protocol changes, not refactors.
|
|
35
43
|
|
|
36
|
-
##
|
|
44
|
+
## Machine Notes
|
|
37
45
|
|
|
38
|
-
|
|
46
|
+
- Do not infer semantic compatibility from matching names if numeric IDs changed.
|
|
47
|
+
- Treat `src/JBPermissionIds.sol` as append-only unless a breaking ecosystem-wide migration is intentional.
|
|
48
|
+
- If docs and code disagree on a permission number, trust the code and update the docs before further admin review.
|
|
39
49
|
|
|
40
|
-
|
|
41
|
-
|----|----------|---------|-----------------|
|
|
42
|
-
| 1 | `ROOT` | All contracts (via `JBPermissions`) | Grants every permission. See [ROOT Permission](#root-permission). |
|
|
43
|
-
| 2 | `QUEUE_RULESETS` | nana-core (`JBController`) | `JBController.queueRulesetsOf` -- queue new rulesets for a project. |
|
|
44
|
-
| 3 | `LAUNCH_RULESETS` | nana-core (`JBController`) | `JBController.launchRulesetsFor` -- launch a project's initial rulesets. Also requires `SET_TERMINALS` (ID 15). |
|
|
45
|
-
| 4 | `CASH_OUT_TOKENS` | nana-core (`JBMultiTerminal`) | `JBMultiTerminal.cashOutTokensOf` -- redeem tokens for surplus. Checked against the **token holder**, not the project owner. |
|
|
46
|
-
| 5 | `SEND_PAYOUTS` | nana-core (`JBMultiTerminal`) | `JBMultiTerminal.sendPayoutsOf` -- distribute payouts to splits. |
|
|
47
|
-
| 6 | `MIGRATE_TERMINAL` | nana-core (`JBMultiTerminal`) | `JBMultiTerminal.migrateBalanceOf` -- migrate a project's balance to another terminal. |
|
|
48
|
-
| 7 | `SET_PROJECT_URI` | nana-core (`JBController`) | `JBController.setUriOf` -- set project metadata URI. |
|
|
49
|
-
| 8 | `DEPLOY_ERC20` | nana-core (`JBController`) | `JBController.deployERC20For` -- deploy a new ERC-20 token for a project. |
|
|
50
|
-
| 9 | `SET_TOKEN` | nana-core (`JBController`) | `JBController.setTokenFor` -- set an existing ERC-20 token for a project. |
|
|
51
|
-
| 10 | `MINT_TOKENS` | nana-core (`JBController`) | `JBController.mintTokensOf` -- mint new project tokens. Only effective when the current ruleset allows owner minting. |
|
|
52
|
-
| 11 | `BURN_TOKENS` | nana-core (`JBController`) | `JBController.burnTokensOf` -- burn tokens. Checked against the **token holder**. |
|
|
53
|
-
| 12 | `CLAIM_TOKENS` | nana-core (`JBController`) | `JBController.claimTokensFor` -- claim internal credits as ERC-20. Checked against the **token holder**. |
|
|
54
|
-
| 13 | `TRANSFER_CREDITS` | nana-core (`JBController`) | `JBController.transferCreditsFrom` -- transfer internal credits. Checked against the **token holder**. |
|
|
55
|
-
| 14 | `SET_CONTROLLER` | nana-core (`JBDirectory`) | `JBDirectory.setControllerOf` -- set a project's controller. |
|
|
56
|
-
| 15 | `SET_TERMINALS` | nana-core (`JBDirectory`) | `JBDirectory.setTerminalsOf` -- set a project's terminals. **Warning:** can remove the primary terminal. |
|
|
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 | `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.
|
|
84
|
-
|
|
85
|
-
## ROOT Permission
|
|
86
|
-
|
|
87
|
-
`ROOT` (ID 1) is a superuser permission. When an operator has ROOT for a given project, `JBPermissions` treats every permission check as passing for that project. It is the only permission that grants blanket access.
|
|
88
|
-
|
|
89
|
-
Restrictions enforced by `JBPermissions`:
|
|
90
|
-
|
|
91
|
-
- **Cannot be granted for the wildcard project ID (0).** Attempting to set ROOT with `projectId = 0` reverts with `JBPermissions_CantSetRootPermissionForWildcardProject()`. This prevents a single operator from controlling all projects owned by an account.
|
|
92
|
-
- **ROOT operators cannot grant ROOT to others.** A ROOT operator can call `setPermissionsFor` on behalf of the account, but the new permission set must not include ROOT and must not target the wildcard project ID.
|
|
93
|
-
- **ROOT is scoped per project.** Having ROOT for project 5 does not grant any permissions for project 6.
|
|
94
|
-
|
|
95
|
-
## Wildcard Project ID
|
|
96
|
-
|
|
97
|
-
When permissions are granted with `projectId = 0`, they apply to **every project** owned by the granting account. This is checked by `JBPermissions` as a fallback: if the operator does not have a specific permission for the target project, the contract checks whether the operator has that permission for `projectId = 0`.
|
|
98
|
-
|
|
99
|
-
ROOT cannot be set for the wildcard project ID. All other permissions can.
|
|
100
|
-
|
|
101
|
-
## How Permissions Are Checked
|
|
102
|
-
|
|
103
|
-
Permissions are stored in `JBPermissions` as a 256-bit packed integer per (operator, account, projectId) tuple:
|
|
104
|
-
|
|
105
|
-
```
|
|
106
|
-
permissionsOf[operator][account][projectId] => uint256 (packed bits)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
Each bit position corresponds to a permission ID. When a contract checks whether an operator has a permission, it calls `JBPermissions.hasPermission(operator, account, projectId, permissionId, includeRoot, includeWildcardProjectId)`, which:
|
|
50
|
+
## Recovery
|
|
110
51
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
3. Checks whether the specific permission bit is set for the specific project -- if so, returns true.
|
|
114
|
-
4. If `includeWildcardProjectId`, checks whether the specific permission bit is set for the wildcard project (`projectId = 0`) -- if so, returns true.
|
|
52
|
+
- There is no runtime recovery surface.
|
|
53
|
+
- A bad ID assignment is fixed only by downstream code changes and redeployments where needed.
|
|
115
54
|
|
|
116
|
-
|
|
55
|
+
## Admin Boundaries
|
|
117
56
|
|
|
118
|
-
|
|
57
|
+
- Nobody can patch deployed contracts to reinterpret old permission bits.
|
|
58
|
+
- This repo cannot grant, revoke, or inspect permissions by itself.
|
|
119
59
|
|
|
120
|
-
##
|
|
60
|
+
## Source Map
|
|
121
61
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
- **`ROOT` (1):** Full access to all gated functions for a project.
|
|
125
|
-
- **`SET_TERMINALS` (15):** Can remove the primary terminal, breaking payments and cashouts.
|
|
126
|
-
- **`USE_ALLOWANCE` (18):** Can send surplus funds to any address.
|
|
127
|
-
- **`SET_BUYBACK_HOOK` (30):** Can permanently lock the buyback hook configuration.
|
|
128
|
-
- **`SET_ROUTER_TERMINAL` (31):** Can permanently lock the router terminal configuration.
|
|
129
|
-
- **`MINT_TOKENS` (10):** Can inflate token supply (subject to ruleset allowing owner minting).
|
|
130
|
-
|
|
131
|
-
## Holder vs. Owner Permissions
|
|
132
|
-
|
|
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**:
|
|
134
|
-
|
|
135
|
-
| Permission | Checked Against |
|
|
136
|
-
|-----------|----------------|
|
|
137
|
-
| `CASH_OUT_TOKENS` (4) | Token holder |
|
|
138
|
-
| `BURN_TOKENS` (11) | Token holder |
|
|
139
|
-
| `CLAIM_TOKENS` (12) | Token holder |
|
|
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 |
|
|
146
|
-
|
|
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.
|
|
62
|
+
- `src/JBPermissionIds.sol`
|
package/ARCHITECTURE.md
CHANGED
|
@@ -2,41 +2,52 @@
|
|
|
2
2
|
|
|
3
3
|
## Purpose
|
|
4
4
|
|
|
5
|
-
`nana-permission-ids-v6` is the shared permission namespace for the ecosystem. It
|
|
5
|
+
`nana-permission-ids-v6` is the shared permission namespace for the V6 ecosystem. It ensures every repo agrees on what each permission bit means when interacting with `JBPermissions`.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## System Overview
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- Its value is stability, not sophistication.
|
|
11
|
-
- The constants here are coupled to checks spread across many sibling repos.
|
|
9
|
+
The repo intentionally contains almost no logic. Its value is stable coordination across the stack. Other repos import `JBPermissionIds` and compare permission bits against these constants.
|
|
12
10
|
|
|
13
|
-
##
|
|
11
|
+
## Core Invariants
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
- Existing IDs must remain stable once consumed by deployed contracts or integrations.
|
|
14
|
+
- New IDs should be appended intentionally, not reused or repurposed.
|
|
15
|
+
- Numeric stability matters more than naming convenience; changing a value while keeping a familiar name is still a protocol break.
|
|
16
|
+
- `ROOT` must stay aligned with `JBPermissions` expectations in `nana-core-v6`.
|
|
18
17
|
|
|
19
|
-
##
|
|
18
|
+
## Modules
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
| Module | Responsibility | Notes |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| `JBPermissionIds` | Defines canonical `uint8` permission IDs | Entire repo value |
|
|
22
23
|
|
|
23
|
-
##
|
|
24
|
+
## Trust Boundaries
|
|
24
25
|
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
- `ROOT` stays special and must remain consistent with `JBPermissions` expectations.
|
|
26
|
+
- This repo has no runtime authority by itself.
|
|
27
|
+
- It is semantically coupled to `nana-core-v6` and every repo that performs permission checks.
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Critical Flows
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
- Mistakes here look like harmless renames until they land in downstream permission checks.
|
|
31
|
+
There is no runtime flow. Other repos import the library and use the constants in permission checks.
|
|
33
32
|
|
|
34
|
-
##
|
|
33
|
+
## Accounting Model
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
No accounting lives here.
|
|
36
|
+
|
|
37
|
+
## Security Model
|
|
38
|
+
|
|
39
|
+
- The code is trivial, but the coordination burden is not.
|
|
40
|
+
- A seemingly harmless rename or reorder here can silently break permissions across the ecosystem.
|
|
41
|
+
- This repo's real blast radius comes from deployed contracts that have already baked these values into their runtime behavior.
|
|
42
|
+
- There is no meaningful local runtime test surface in this repo today; correctness is mostly enforced by downstream compatibility and reviewer discipline.
|
|
37
43
|
|
|
38
44
|
## Safe Change Guide
|
|
39
45
|
|
|
40
|
-
- Treat
|
|
41
|
-
- When adding a permission, update
|
|
42
|
-
- Do not add
|
|
46
|
+
- Treat any ID change as a cross-repo protocol change.
|
|
47
|
+
- When adding a permission, update downstream repos and docs in the same change set.
|
|
48
|
+
- Do not add aliases that obscure the one-to-one mapping between bit position and meaning.
|
|
49
|
+
|
|
50
|
+
## Source Map
|
|
51
|
+
|
|
52
|
+
- `src/JBPermissionIds.sol`
|
|
53
|
+
- `references/runtime.md`
|
package/AUDIT_INSTRUCTIONS.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
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
|
-
## Objective
|
|
5
|
+
## Audit Objective
|
|
6
6
|
|
|
7
7
|
Find issues that:
|
|
8
8
|
- assign duplicate IDs to different semantic permissions
|
|
@@ -14,6 +14,24 @@ Find issues that:
|
|
|
14
14
|
In scope:
|
|
15
15
|
- `src/JBPermissionIds.sol`
|
|
16
16
|
|
|
17
|
+
## Start Here
|
|
18
|
+
|
|
19
|
+
1. `src/JBPermissionIds.sol`
|
|
20
|
+
2. downstream consumers in `nana-core-v6` and `revnet-core-v6`
|
|
21
|
+
|
|
22
|
+
## Security Model
|
|
23
|
+
|
|
24
|
+
This repo defines canonical numeric IDs that other repos treat as part of their permission model.
|
|
25
|
+
- the file is small, but stale renumbering or collisions can silently widen or break access control elsewhere
|
|
26
|
+
- correctness depends on cross-repo alignment, not local logic alone
|
|
27
|
+
|
|
28
|
+
## Integration Assumptions
|
|
29
|
+
|
|
30
|
+
| Dependency | Assumption | What breaks if wrong |
|
|
31
|
+
|------------|------------|----------------------|
|
|
32
|
+
| `nana-core-v6` | ERC-20 signature delegation still uses the documented ID | Signature authority checks mismatch |
|
|
33
|
+
| `revnet-core-v6` | Loan and hidden-token permissions still use the documented IDs | Delegated actions widen, fail, or misroute |
|
|
34
|
+
|
|
17
35
|
## Critical Invariants
|
|
18
36
|
|
|
19
37
|
1. Each permission semantic has one stable numeric ID.
|
|
@@ -22,14 +40,13 @@ In scope:
|
|
|
22
40
|
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
41
|
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`.
|
|
24
42
|
|
|
25
|
-
##
|
|
43
|
+
## Attack Surfaces
|
|
26
44
|
|
|
27
|
-
|
|
45
|
+
- duplicate or reordered constants
|
|
46
|
+
- stale cross-repo assumptions
|
|
47
|
+
- permission additions that collide with previously assigned meanings
|
|
28
48
|
|
|
29
|
-
##
|
|
49
|
+
## Verification
|
|
30
50
|
|
|
31
|
-
Standard workflow:
|
|
32
51
|
- `npm install`
|
|
33
52
|
- `forge build`
|
|
34
|
-
|
|
35
|
-
A meaningful finding here should show a real downstream permission check becoming broader, narrower, or mismatched because of the constant set.
|
package/README.md
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
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
|
-
Architecture: [ARCHITECTURE.md](./ARCHITECTURE.md)
|
|
5
|
+
Architecture: [ARCHITECTURE.md](./ARCHITECTURE.md)
|
|
6
|
+
User journeys: [USER_JOURNEYS.md](./USER_JOURNEYS.md)
|
|
7
|
+
Skills: [SKILLS.md](./SKILLS.md)
|
|
8
|
+
Risks: [RISKS.md](./RISKS.md)
|
|
9
|
+
Administration: [ADMINISTRATION.md](./ADMINISTRATION.md)
|
|
10
|
+
Audit instructions: [AUDIT_INSTRUCTIONS.md](./AUDIT_INSTRUCTIONS.md)
|
|
6
11
|
|
|
7
12
|
## Overview
|
|
8
13
|
|
|
@@ -21,17 +26,43 @@ If the question is "who can do this action?" you will still need `JBPermissions`
|
|
|
21
26
|
| `1` | global `ROOT` permission |
|
|
22
27
|
| `2-23` | core protocol permissions |
|
|
23
28
|
| `24-27` | 721 hook permissions |
|
|
24
|
-
| `28-30` | buyback hook permissions |
|
|
25
|
-
| `31` | router terminal permission |
|
|
26
|
-
| `32-35` | sucker and omnichain permissions |
|
|
29
|
+
| `28-30` | buyback hook and registry permissions |
|
|
30
|
+
| `31` | router terminal registry permission |
|
|
31
|
+
| `32-35` | sucker and omnichain-deployment permissions |
|
|
27
32
|
| `36-40` | revnet-core permissions (hidden tokens, loans) |
|
|
28
33
|
|
|
29
34
|
The exact constants live in `src/JBPermissionIds.sol`.
|
|
30
35
|
|
|
36
|
+
Two IDs deserve special attention:
|
|
37
|
+
|
|
38
|
+
- `SET_BUYBACK_HOOK` covers both setting and permanently locking the configured buyback hook
|
|
39
|
+
- `SET_ROUTER_TERMINAL` covers both setting and permanently locking the configured router terminal
|
|
40
|
+
|
|
31
41
|
## Mental Model
|
|
32
42
|
|
|
33
43
|
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.
|
|
34
44
|
|
|
45
|
+
## Read This File First
|
|
46
|
+
|
|
47
|
+
1. `src/JBPermissionIds.sol`
|
|
48
|
+
|
|
49
|
+
## Integration Traps
|
|
50
|
+
|
|
51
|
+
- changing an existing numeric constant is a breaking ecosystem change, not an internal refactor
|
|
52
|
+
- adding a new permission ID without coordinating downstream repos creates semantic drift even if the code still compiles
|
|
53
|
+
- wildcard project permissions remain dangerous even when the numeric IDs themselves are correct
|
|
54
|
+
|
|
55
|
+
## Where Meaning Lives
|
|
56
|
+
|
|
57
|
+
- numeric permission labels live in `JBPermissionIds.sol`
|
|
58
|
+
- runtime permission checks live in `nana-core-v6/src/JBPermissions.sol`
|
|
59
|
+
- repo-specific uses of those IDs live in the downstream package that imports them
|
|
60
|
+
|
|
61
|
+
## For AI Agents
|
|
62
|
+
|
|
63
|
+
- Treat this repo as a naming registry for permission bits, not as the runtime permission engine.
|
|
64
|
+
- If asked whether an action is allowed, inspect the downstream repo that checks the ID in addition to this file.
|
|
65
|
+
|
|
35
66
|
## Install
|
|
36
67
|
|
|
37
68
|
```bash
|
|
@@ -56,4 +87,5 @@ src/
|
|
|
56
87
|
|
|
57
88
|
- `ROOT` is intentionally powerful and should be granted sparingly
|
|
58
89
|
- wildcard project scope is convenient but easy to misuse operationally
|
|
90
|
+
- some IDs intentionally bundle configuration and irreversible locking authority, so their blast radius is larger than their names first suggest
|
|
59
91
|
- any change to this file has ecosystem-wide consequences because other repos assume the values are stable
|
package/RISKS.md
CHANGED
|
@@ -1,36 +1,50 @@
|
|
|
1
1
|
# Permission IDs Risk Register
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This file focuses on the coordination risks in `JBPermissionIds`. The contract surface is tiny, but any semantic drift here can corrupt access control across the entire V6 ecosystem.
|
|
4
4
|
|
|
5
5
|
## How to use this file
|
|
6
6
|
|
|
7
|
-
- Read `Priority risks` first;
|
|
8
|
-
-
|
|
9
|
-
-
|
|
7
|
+
- Read `Priority risks` first; the main danger is cross-repo disagreement, not local bugs.
|
|
8
|
+
- Treat every ID change as an ecosystem migration event.
|
|
9
|
+
- Use `Invariants to Verify` to keep append-only discipline explicit.
|
|
10
10
|
|
|
11
11
|
## Priority risks
|
|
12
12
|
|
|
13
13
|
| Priority | Risk | Why it matters | Primary controls |
|
|
14
14
|
|----------|------|----------------|------------------|
|
|
15
|
-
| P0 | Semantic drift across repos | If two
|
|
16
|
-
| P1 |
|
|
17
|
-
|
|
|
15
|
+
| P0 | Semantic drift across repos | If two packages assign different meanings to the same numeric ID, permission checks silently authorize the wrong actions. | Single source of truth, append-only changes, and synchronized downstream updates. |
|
|
16
|
+
| P1 | Reusing or reordering existing IDs | Renumbering breaks already-deployed contracts and off-chain tooling without any on-chain migration safety. | Never repurpose an assigned ID. Append only. |
|
|
17
|
+
| P1 | Over-trusting high-impact IDs | Some IDs directly control funds, terminal routing, hook locking, or wildcard authority. Misgrants are catastrophic. | Explicit operator review and narrow-scoped permission grants. |
|
|
18
18
|
|
|
19
19
|
## 1. Known Risks
|
|
20
20
|
|
|
21
|
-
- **
|
|
22
|
-
-
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
- **No
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
21
|
+
- **No runtime enforcement here.** This library only defines constants. Safety depends on every consuming repo checking the intended ID.
|
|
22
|
+
- **`ROOT` is ecosystem-wide god mode.** `ROOT` (ID `1`) grants all permissions, including permissions added in the future.
|
|
23
|
+
- **Wildcard grants amplify blast radius.** Any permission granted with `projectId = 0` applies to all projects owned by that account. System contracts may need this, but operator mistakes become ecosystem-wide.
|
|
24
|
+
- **Hook and router lock powers are bundled.** `SET_BUYBACK_HOOK` (ID `30`) controls both hook selection and hook locking. `SET_ROUTER_TERMINAL` (ID `31`) controls both terminal selection and terminal locking.
|
|
25
|
+
- **No on-chain namespace for third-party extensions.** IDs `41-255` are socially available, not registry-managed. External packages can collide unless teams coordinate out of band.
|
|
26
|
+
|
|
27
|
+
## 2. High-Impact IDs
|
|
28
|
+
|
|
29
|
+
- **Fund-moving IDs.** `CASH_OUT_TOKENS` (`4`), `SEND_PAYOUTS` (`5`), `MIGRATE_TERMINAL` (`6`), `SET_TERMINALS` (`15`), `USE_ALLOWANCE` (`18`), and `SET_SPLIT_GROUPS` (`19`) can redirect or release value.
|
|
30
|
+
- **Hook-routing IDs.** `SET_BUYBACK_POOL` (`28`), `SET_BUYBACK_HOOK` (`30`), and `SET_ROUTER_TERMINAL` (`31`) materially control execution routes and can lock those routes permanently.
|
|
31
|
+
- **Revnet loan IDs.** `OPEN_LOAN` (`37`), `REALLOCATE_LOAN` (`38`), and `REPAY_LOAN` (`39`) are operationally powerful because they move collateral and debt state.
|
|
32
|
+
|
|
33
|
+
## 3. Integration Risks
|
|
34
|
+
|
|
35
|
+
- **Docs can lag deployed assumptions.** Off-chain tooling, UIs, and auditors often rely on human-readable permission names. A stale doc can be almost as dangerous as a stale constant if operators grant the wrong ID.
|
|
36
|
+
- **Cross-package imports must remain canonical.** Downstream repos should import this library instead of redefining numeric literals locally.
|
|
37
|
+
- **Future IDs inherit current trust assumptions.** Because `ROOT` covers future IDs, any new permission expands the capability of existing ROOT operators immediately after deployment.
|
|
38
|
+
|
|
39
|
+
## 4. Invariants to Verify
|
|
40
|
+
|
|
41
|
+
- Assigned IDs are append-only and never repurposed.
|
|
42
|
+
- `0` remains unused as a permission ID.
|
|
43
|
+
- Every documented ID in this repo matches the numeric checks in downstream consuming contracts.
|
|
44
|
+
- New IDs added after `40` do not collide with existing ecosystem assignments.
|
|
45
|
+
|
|
46
|
+
## 5. Accepted Behaviors
|
|
47
|
+
|
|
48
|
+
### 5.1 This repo is coordination infrastructure, not an enforcement layer
|
|
49
|
+
|
|
50
|
+
`JBPermissionIds` intentionally has no access control, storage, or runtime checks. The value of the repo is that every other package can import the same constants and mean the same thing.
|
package/USER_JOURNEYS.md
CHANGED
|
@@ -1,44 +1,102 @@
|
|
|
1
1
|
# User Journeys
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Repo Purpose
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
This repo is the shared permission vocabulary for the V6 ecosystem.
|
|
6
|
+
It does not store permissions or enforce them at runtime. It defines the constants downstream repos should import so
|
|
7
|
+
permissioned behavior stays legible and consistent.
|
|
8
|
+
|
|
9
|
+
## Primary Actors
|
|
10
|
+
|
|
11
|
+
- engineers choosing which permission constant should guard a feature
|
|
12
|
+
- auditors checking whether a repo drifted from the shared vocabulary
|
|
13
|
+
- maintainers extending the permission map without numeric collisions
|
|
14
|
+
|
|
15
|
+
## Key Surfaces
|
|
16
|
+
|
|
17
|
+
- `JBPermissionIds`: library of canonical permission constants used across V6 repos
|
|
18
|
+
- grouped constants for core, 721, router, buyback, sucker, Revnet, and related ecosystem actions
|
|
19
|
+
- reserved ranges documented in `README.md`, including `ROOT = 1`, ecosystem-managed IDs through `40`, and socially coordinated extension space above that
|
|
8
20
|
|
|
9
21
|
## Journey 1: Map A Product Action To The Right Permission
|
|
10
22
|
|
|
11
|
-
**
|
|
23
|
+
**Actor:** downstream engineer.
|
|
12
24
|
|
|
13
|
-
**
|
|
25
|
+
**Intent:** protect an action with the canonical permission constant instead of inventing a local number.
|
|
14
26
|
|
|
15
|
-
**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
**Preconditions**
|
|
28
|
+
- the action is governed by `JBPermissions`
|
|
29
|
+
- the engineer knows which repo or domain owns the action
|
|
30
|
+
|
|
31
|
+
**Main Flow**
|
|
32
|
+
1. Find the action domain in `JBPermissionIds`, such as core, 721, router, buyback, or sucker permissions.
|
|
33
|
+
2. Import the constant into the downstream repo.
|
|
34
|
+
3. Use that constant in the runtime authorization check.
|
|
35
|
+
4. Treat bundled high-impact IDs like `SET_BUYBACK_HOOK` and `SET_ROUTER_TERMINAL` as broader powers than their short names suggest because they also gate locking.
|
|
36
|
+
|
|
37
|
+
**Failure Modes**
|
|
38
|
+
- the repo hardcodes a number locally and drifts from the shared vocabulary
|
|
39
|
+
- a repo picks the wrong existing constant because the action sounds similar but is not actually equivalent
|
|
40
|
+
- a team grants `ROOT` or wildcard project permissions without appreciating that future IDs inherit that blast radius
|
|
41
|
+
- docs and tests describe a permission by nickname rather than the imported constant
|
|
42
|
+
|
|
43
|
+
**Postconditions**
|
|
44
|
+
- the downstream action is guarded by the shared permission vocabulary instead of a local numeric convention
|
|
19
45
|
|
|
20
46
|
## Journey 2: Review An Existing Operator Setup
|
|
21
47
|
|
|
22
|
-
**
|
|
48
|
+
**Actor:** auditor, operator, or curious integrator.
|
|
49
|
+
|
|
50
|
+
**Intent:** decode opaque permission bits into named actions.
|
|
23
51
|
|
|
24
|
-
**
|
|
52
|
+
**Preconditions**
|
|
53
|
+
- the operator bitset or granted permission IDs are already known
|
|
54
|
+
- the reviewer understands that this repo names permissions but does not prove how each repo uses them
|
|
25
55
|
|
|
26
|
-
**Flow**
|
|
56
|
+
**Main Flow**
|
|
27
57
|
1. Start with the permission bits granted on the project.
|
|
28
|
-
2. Map each bit
|
|
29
|
-
3. Confirm
|
|
58
|
+
2. Map each bit to its named constant here.
|
|
59
|
+
3. Confirm the downstream repo still uses that constant consistently at its authorization checks and docs.
|
|
60
|
+
4. Check whether any granted IDs are effectively funds-moving, routing, locking, or loan-management powers rather than low-risk admin toggles.
|
|
61
|
+
|
|
62
|
+
**Failure Modes**
|
|
63
|
+
- downstream code reuses a permission ID for a different meaning
|
|
64
|
+
- reviewers decode the bit correctly but underestimate what the downstream repo lets that permission do in practice
|
|
65
|
+
- reviewers assume this repo alone is enough and skip the actual guarded code
|
|
66
|
+
|
|
67
|
+
**Postconditions**
|
|
68
|
+
- the reviewer has a named permission map and knows which downstream repos still need inspection
|
|
30
69
|
|
|
31
70
|
## Journey 3: Add A New Ecosystem Surface Without Permission Drift
|
|
32
71
|
|
|
33
|
-
**
|
|
72
|
+
**Actor:** maintainer extending the permission vocabulary.
|
|
34
73
|
|
|
35
|
-
**
|
|
74
|
+
**Intent:** add one new permission constant in a way the rest of the ecosystem can reuse.
|
|
36
75
|
|
|
37
|
-
**
|
|
38
|
-
|
|
76
|
+
**Preconditions**
|
|
77
|
+
- no existing constant already matches the new action
|
|
78
|
+
- the maintainer understands the numeric ranges already in use
|
|
79
|
+
|
|
80
|
+
**Main Flow**
|
|
81
|
+
1. Choose the next unused ID in the relevant range.
|
|
39
82
|
2. Add the named constant in `JBPermissionIds.sol`.
|
|
40
|
-
3. Update downstream repos to import
|
|
41
|
-
4.
|
|
83
|
+
3. Update downstream repos to import the constant instead of duplicating the number.
|
|
84
|
+
4. Refresh docs and tests that explain the permission.
|
|
85
|
+
5. If the new ID goes above the ecosystem-managed range, coordinate externally so third-party packages do not collide on the same number.
|
|
86
|
+
|
|
87
|
+
**Failure Modes**
|
|
88
|
+
- a new repo defines its own numeric constant first and creates drift
|
|
89
|
+
- a new constant is added in the wrong semantic range, making later review harder
|
|
90
|
+
- a new ID silently expands what existing `ROOT` operators can do without that blast radius being reviewed
|
|
91
|
+
- documentation updates lag behind the code change
|
|
92
|
+
|
|
93
|
+
**Postconditions**
|
|
94
|
+
- the new ecosystem surface has a reusable canonical permission ID with coordinated downstream adoption
|
|
95
|
+
|
|
96
|
+
## Trust Boundaries
|
|
97
|
+
|
|
98
|
+
- this repo is trusted only as shared vocabulary; actual storage and enforcement live elsewhere
|
|
99
|
+
- downstream repos can still misuse a constant even when they import the right one
|
|
42
100
|
|
|
43
101
|
## Hand-Offs
|
|
44
102
|
|
package/package.json
CHANGED
package/references/runtime.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Permission IDs Runtime
|
|
2
2
|
|
|
3
|
+
Use this file when you need to confirm the canonical numeric labels, not when you need to understand enforcement behavior.
|
|
4
|
+
|
|
3
5
|
## Core Role
|
|
4
6
|
|
|
5
7
|
- [`src/JBPermissionIds.sol`](../src/JBPermissionIds.sol) defines the canonical numeric labels used by the rest of the ecosystem.
|
|
@@ -13,3 +15,4 @@
|
|
|
13
15
|
|
|
14
16
|
- If you edit a constant, audit every dependent repo that imports it.
|
|
15
17
|
- If you need to know who can exercise a permission, follow the usage into the enforcing repo rather than stopping here.
|
|
18
|
+
- There are no repo-local tests here, so downstream compile and behavior audits matter more than this package in isolation.
|