@rev-net/core-v6 0.0.31 → 0.0.33

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
@@ -1,237 +1,86 @@
1
1
  # Administration
2
2
 
3
- Admin privileges and their scope in revnet-core-v6. Revnets are designed to be autonomous Juicebox projects with no traditional owner. This document covers what privileged operations exist, who can perform them, and -- critically -- what is intentionally made impossible.
4
-
5
3
  ## At A Glance
6
4
 
7
5
  | Item | Details |
8
- |------|---------|
9
- | Scope | Autonomous revnet deployment, split-operator powers, loan metadata ownership, hidden token management, and the boundaries imposed by revnet immutability. |
10
- | Operators | The per-revnet split operator, the global `REVLoans` owner for metadata cosmetics, the protocol-owned `REVDeployer`, loan NFT holders (or operators with `REPAY_LOAN`/`REALLOCATE_LOAN`/`OPEN_LOAN` permissions), `REVHiddenTokens` callers (or operators with `HIDE_TOKENS`/`REVEAL_TOKENS` permissions), and permissionless callers for open lifecycle actions. |
11
- | Highest-risk actions | Converting an existing project into a revnet, changing or burning the split operator, and configuring buyback, router, price-feed, or sucker permissions inside the narrow allowed operator surface. |
12
- | Recovery posture | Revnet economics are intentionally not admin-recoverable. A bad deployment generally means abandoning the revnet and deploying a new one. |
13
-
14
- ## Routine Operations
6
+ | --- | --- |
7
+ | Scope | Revnet deployment shape, split-operator runtime authority, and cosmetic `REVLoans` ownership |
8
+ | Control posture | Mostly immutable economics with a narrow runtime operator |
9
+ | Highest-risk actions | Deploying the wrong stage design, assigning the wrong split operator, and overestimating `REVLoans` owner power |
10
+ | Recovery posture | Core economic mistakes require new revnets; some optional integrations can be corrected by the split operator |
15
11
 
16
- - Use the split operator only for the limited post-launch surfaces the protocol deliberately leaves mutable: reserved-token split routing, selected hook metadata, router selection, and related operator-scoped settings.
17
- - Keep `REVLoans` owner actions limited to URI resolver maintenance; that role should never be treated as an economic admin.
18
- - Treat `deploySuckersFor`, buyback configuration, and router-terminal changes as operational extensions around a fixed revnet, not as tools to rewrite the revnet's stage economics.
19
- - If autonomy is the goal, consider relinquishing the split operator to `address(0)` only after all intended mutable integrations are finalized.
12
+ ## Purpose
20
13
 
21
- ## One-Way Or High-Risk Actions
14
+ `revnet-core-v6` is designed to minimize ongoing human control. The core split is between deployment-time shape, the limited split-operator role, the globally owned-but-cosmetic `REVLoans` metadata surface, and the intentionally ownerless project pattern enforced through `REVDeployer` and `REVOwner`.
22
15
 
23
- - Deploying a revnet or converting an existing project into one is irreversible from an ownership and stage-design perspective.
24
- - Setting the split operator to `address(0)` permanently burns the human-controlled role.
25
- - Stage schedules, issuance curves, cash-out tax rates, and core economic parameters are fixed at deployment.
16
+ ## Control Model
26
17
 
27
- ## Recovery Notes
28
-
29
- - There is no admin escape hatch for broken revnet stage design. The recovery path is a new revnet deployment with corrected parameters.
30
- - If an auxiliary integration such as a buyback hook or sucker is wrong but the split operator still has the relevant scoped power, fix that integration without expecting to change the underlying revnet economics.
18
+ - Deployment-time configuration is the real place where revnet economics are chosen.
19
+ - The split operator is the only intended human-controlled runtime role for a revnet.
20
+ - `REVLoans` owner only controls loan NFT metadata rendering.
21
+ - `REVDeployer` holds the project NFT structurally, not as a discretionary human admin.
22
+ - Many economically sensitive behaviors are intentionally not mutable after deployment.
31
23
 
32
24
  ## Roles
33
25
 
34
- ### Split Operator
35
-
36
- - **How assigned:** Specified at deployment via `REVConfig.splitOperator`. After deployment, only the current split operator can transfer the role to a new address by calling `setSplitOperatorOf()`.
37
- - **Scope:** Per-revnet. Each revnet has at most one split operator. The operator is the only human-controlled role in a deployed revnet.
38
- - **Can be permanently relinquished:** The split operator can transfer the role to `address(0)` via `setSplitOperatorOf()`, which permanently relinquishes operator powers. Permissions are granted to the zero address (which cannot execute transactions), effectively burning them. This is irreversible.
26
+ | Role | How Assigned | Scope | Notes |
27
+ | --- | --- | --- | --- |
28
+ | Split operator | `REVConfig.splitOperator` at deployment | Per revnet | Narrow runtime operator surface |
29
+ | `REVLoans` owner | `Ownable(owner)` on `REVLoans` | Global | Cosmetic metadata role, not economic admin |
30
+ | Loan NFT owner | ERC-721 loan ownership | Per loan | Can repay or reallocate subject to checks |
31
+ | Hidden-token caller or delegate | Holder or delegated permission | Per holder | Manages hide and reveal flows |
32
+ | Anyone | No assignment | Global or per revnet | Some lifecycle functions are permissionless |
39
33
 
40
- ### REVLoans Owner (Ownable)
34
+ ## Privileged Surfaces
41
35
 
42
- - **How assigned:** Set at `REVLoans` contract deployment via the `owner` constructor parameter. Transferable via OpenZeppelin `Ownable.transferOwnership()`.
43
- - **Scope:** Global across all revnets using this loans contract. Controls only the loan NFT metadata URI resolver -- has no power over loan parameters, collateral, or funds.
36
+ | Contract | Function | Who Can Call | Effect |
37
+ | --- | --- | --- | --- |
38
+ | `REVDeployer` | `deployFor(...)` | Anyone for new deployments, or current owner for conversion path | Creates or converts a project into a revnet |
39
+ | `REVDeployer` | `deploySuckersFor(...)` | Split operator | Adds sucker infra where the revnet config allows it |
40
+ | `REVDeployer` | `setSplitOperatorOf(...)` | Current split operator | Replaces or burns the split-operator role |
41
+ | `REVLoans` | `setTokenUriResolver(...)` | `REVLoans` owner | Cosmetic loan-NFT metadata control |
42
+ | `REVLoans` | `borrowFrom(...)`, `repayLoan(...)`, `reallocateCollateralFromLoan(...)` | Holder or delegated loan operator | Position-level administration, not protocol-level governance |
44
43
 
45
- ### REVDeployer (as Juicebox project owner)
44
+ ## Immutable And One-Way
46
45
 
47
- - **How assigned:** Automatic. When a revnet is deployed, the `REVDeployer` contract becomes the permanent owner of the Juicebox project NFT. If initializing an existing project, the caller's project NFT is irreversibly transferred to `REVDeployer`.
48
- - **Scope:** The deployer holds the project NFT and uses its owner authority to enforce revnet rules. It acts as a protocol-level constraint layer, not as a discretionary admin. No human can exercise this ownership.
46
+ - Stage schedule and core economics are chosen at deployment and then fixed.
47
+ - Converting an existing project into a revnet is effectively irreversible.
48
+ - Burning the split-operator role to `address(0)` is final.
49
+ - `REVDeployer` structurally retains project-NFT ownership in the design.
50
+ - Expired loans can eventually liquidate into permanently lost collateral if they are not repaid within the long liquidation window.
49
51
 
50
- ### Loan NFT Owner
52
+ ## Operational Notes
51
53
 
52
- - **How assigned:** The `holder` specified in `borrowFrom()` receives the loan ERC-721. When no operator delegation is used, the caller passes themselves as `holder`. Transferable like any ERC-721.
53
- - **Scope:** Per-loan. The current NFT owner or an operator with the relevant `JBPermissionIds` (`REPAY_LOAN`, `REALLOCATE_LOAN`) — can repay the loan, return collateral, or reallocate collateral to a new loan.
54
+ - Use the split operator only for the intentionally narrow surfaces left mutable.
55
+ - Treat buyback, router, sucker, and optional 721 adjustments as operational extensions around a fixed economic core.
56
+ - Keep `REVLoans` owner power limited to URI resolver maintenance.
57
+ - Treat loan operations as position management with real long-tail irreversibility; after the liquidation duration expires, collateral recovery is no longer available.
54
58
 
55
- ### Anyone (Permissionless)
59
+ ## Machine Notes
56
60
 
57
- - **Scope:** Several functions are callable by any address with no access control, as documented in the Privileged Functions tables below.
61
+ - Do not infer broad control from `REVDeployer` holding the project NFT; the design is intentionally constrained.
62
+ - Treat `src/REVDeployer.sol`, `src/REVOwner.sol`, and `src/REVLoans.sol` together when crawling authority.
63
+ - If stage config or split-operator assumptions differ from deployed state, stop; those are foundational revnet assumptions, not cosmetic metadata.
58
64
 
59
- ## Privileged Functions
65
+ ## Recovery
60
66
 
61
- ### REVDeployer
67
+ - Wrong stage design is not realistically recoverable in place; deploy a new revnet.
68
+ - Wrong optional integration can sometimes be corrected if the split operator still has the required scoped power.
69
+ - There is no broad admin escape hatch that can rewrite revnet economics after launch.
70
+ - Liquidated loan collateral is not an admin-recoverable asset; recovery must happen before liquidation through borrower action.
62
71
 
63
- | Function | Required Role | Permission ID | What It Does |
64
- |----------|--------------|---------------|-------------|
65
- | `deployFor()` | Anyone (new revnet) or Juicebox project owner (existing project) | None | Deploys a new revnet or irreversibly converts an existing Juicebox project into a revnet. Both variants deploy a tiered ERC-721 hook: the 4-arg variant deploys a default empty hook; the 6-arg variant deploys a hook with pre-configured tiers and optional croptop posting rules. |
66
- | `deploySuckersFor()` | Split Operator | Checked via `_checkIfIsSplitOperatorOf()` | Deploys new cross-chain suckers for an existing revnet. Also requires the current ruleset's `extraMetadata` bit 2 to be set (allows deploying suckers). |
67
- | `setSplitOperatorOf()` | Split Operator | Checked via `_checkIfIsSplitOperatorOf()` | Replaces the current split operator with a new address. Revokes all operator permissions from the caller and grants them to the new address. |
68
- | `autoIssueFor()` | Anyone | None | Mints pre-configured auto-issuance tokens for a beneficiary once the relevant stage has started. Amounts are set at deployment and can only be claimed once. |
69
- | `burnHeldTokensOf()` | Anyone | None | Burns any of a revnet's tokens held by the `REVDeployer` contract (e.g., from reserved token splits that did not sum to 100%). |
70
- | `afterCashOutRecordedWith()` | Anyone (called by terminal) | None | **Note: This function lives on REVOwner, not REVDeployer.** Processes cash-out fees. No caller validation needed because a non-terminal caller would only be donating their own funds. |
71
-
72
- ### Split Operator Permissions (granted via JBPermissions)
73
-
74
- The split operator receives the following Juicebox permission IDs, scoped to its revnet:
72
+ ## Admin Boundaries
75
73
 
76
- | Permission ID | What It Allows |
77
- |---------------|----------------|
78
- | `SET_SPLIT_GROUPS` | Change how reserved tokens are distributed among split recipients. |
79
- | `SET_BUYBACK_POOL` | Configure which Uniswap V4 pool is used for the buyback hook. |
80
- | `SET_BUYBACK_TWAP` | Adjust the TWAP window for the buyback hook. |
81
- | `SET_PROJECT_URI` | Update the revnet's metadata URI. |
82
- | `ADD_PRICE_FEED` | Add a new price feed for the revnet. |
83
- | `SUCKER_SAFETY` | Manage sucker safety settings (e.g., emergency hatch). |
84
- | `SET_BUYBACK_HOOK` | Configure the buyback hook. |
85
- | `SET_ROUTER_TERMINAL` | Set the router terminal. |
86
- | `SET_TOKEN_METADATA` | Update the revnet token's name and symbol. |
87
-
88
- Optional 721 permissions (granted only if enabled at deployment via `REVDeploy721TiersHookConfig`):
89
-
90
- | Permission ID | Deployment Flag | What It Allows |
91
- |---------------|----------------|----------------|
92
- | `ADJUST_721_TIERS` | `preventSplitOperatorAdjustingTiers` | Add or remove ERC-721 tiers. Allowed unless prevented. |
93
- | `SET_721_METADATA` | `preventSplitOperatorUpdatingMetadata` | Update ERC-721 tier metadata. Allowed unless prevented. |
94
- | `MINT_721` | `preventSplitOperatorMinting` | Mint ERC-721s without payment from tiers with `allowOwnerMint`. Allowed unless prevented. |
95
- | `SET_721_DISCOUNT_PERCENT` | `preventSplitOperatorIncreasingDiscountPercent` | Increase the discount percentage of a tier. Allowed unless prevented. |
96
-
97
- ### REVLoans
98
-
99
- | Function | Required Role | Access Control | What It Does |
100
- |----------|--------------|----------------|-------------|
101
- | `borrowFrom()` | Holder or operator with `OPEN_LOAN` | `PERMISSIONS.hasPermission` if caller ≠ holder | Opens a loan against revnet token collateral. The `holder` parameter specifies whose tokens are burned; the loan NFT is minted to `holder`. |
102
- | `repayLoan()` | Loan NFT Owner or operator with `REPAY_LOAN` | `PERMISSIONS.hasPermission` if caller ≠ owner | Repays a loan (partially or fully) and returns collateral. Replacement loans are minted to the original loan owner. |
103
- | `reallocateCollateralFromLoan()` | Loan NFT Owner or operator with `REALLOCATE_LOAN` | `PERMISSIONS.hasPermission` if caller ≠ owner | Splits excess collateral from an existing loan into a new loan. Returned collateral and replacement loans go to the original loan owner. |
104
- | `liquidateExpiredLoansFrom()` | Anyone | None | Liquidates loans that have exceeded the 10-year liquidation duration. Permanently destroys collateral. |
105
- | `setTokenUriResolver()` | REVLoans Owner | `onlyOwner` (OpenZeppelin Ownable) | Sets the contract that resolves loan NFT metadata URIs. |
106
-
107
- ### Constructor-Level Permissions (set once at deployment)
108
-
109
- These permissions are granted in the `REVDeployer` constructor and apply globally (wildcard `projectId = 0`):
110
-
111
- | Grantee | Permission ID | Purpose |
112
- |---------|---------------|---------|
113
- | `SUCKER_REGISTRY` | `MAP_SUCKER_TOKEN` | Allows the sucker registry to map tokens for all revnets. |
114
- | `LOANS` | `USE_ALLOWANCE` | Allows the loans contract to use surplus allowance from all revnets to fund loans. |
115
- | `BUYBACK_HOOK` | `SET_BUYBACK_POOL` | Allows the buyback hook registry to configure Uniswap V4 pools for all revnets. |
116
-
117
- ## Autonomous Design
118
-
119
- Revnets are designed to operate without a traditional project owner. The following mechanisms enforce autonomy:
120
-
121
- - **Ownership transfer is permanent.** When a revnet is deployed, the Juicebox project NFT is transferred to the `REVDeployer` contract. No human holds the project NFT. There is no function to transfer it back.
122
- - **No ruleset queuing.** The `REVDeployer` does not expose any function to queue new rulesets after deployment. The stage progression is fully determined at deploy time. Nobody -- not the split operator, not the deployer, not anyone -- can change the issuance schedule, cash-out tax rates, or stage timing after deployment.
123
- - **No approval hooks.** All rulesets are deployed with `approvalHook = address(0)`. There is no mechanism to block or delay stage transitions.
124
- - **Cash outs cannot be fully disabled.** The deployer enforces `cashOutTaxRate < MAX_CASH_OUT_TAX_RATE` for every stage, guaranteeing that token holders always retain some ability to cash out.
125
- - **Data hook is REVOwner.** `REVOwner` is set as the data hook (`metadata.dataHook = address(OWNER())`) for all rulesets, ensuring consistent fee and sucker logic without external admin control. REVOwner stores `cashOutDelayOf` and `tiered721HookOf` in its own storage (set by REVDeployer via DEPLOYER-restricted setters during deployment).
126
- - **Mint permission is restricted.** Only the loans contract, the hidden tokens contract, the buyback hook (and its delegates), and registered suckers can mint tokens (as determined by `REVOwner.hasMintPermissionFor`). The split operator cannot mint fungible revnet tokens.
127
- - **No held fee manipulation.** The deployer has no function to process or return held fees arbitrarily.
128
- - **Owner minting is constrained.** While `allowOwnerMinting = true` is set in ruleset metadata, the "owner" is the `REVDeployer` contract. It only uses this to mint auto-issuance tokens (amounts fixed at deployment) and to return loan collateral.
129
-
130
- ## Loan Administration
131
-
132
- The `REVLoans` contract has minimal admin surface by design:
133
-
134
- - **All economic parameters are constants.** Loan liquidation duration (10 years), fee percentages (MIN 2.5%, MAX 50%), and the REV fee (1%) are hardcoded as immutable constants. No admin can change them.
135
- - **The only admin function is `setTokenUriResolver()`**, which controls how loan NFTs render their metadata. This is purely cosmetic and has no effect on loan economics, collateral, or fund flows.
136
- - **Loan management is permissioned to NFT holders or delegated operators.** Repayment requires loan NFT ownership or `REPAY_LOAN` permission. Collateral reallocation requires loan NFT ownership or `REALLOCATE_LOAN` permission. Borrowing on behalf of another holder requires `OPEN_LOAN` permission. In all delegated cases, collateral and loan NFTs flow to the original holder/owner, not the operator.
137
- - **Liquidation is permissionless.** Anyone can call `liquidateExpiredLoansFrom()` for loans past the 10-year duration.
138
-
139
- ## Hidden Tokens Administration
140
-
141
- The `REVHiddenTokens` contract inherits `JBPermissioned` for operator delegation but has no admin surface:
142
-
143
- - **Operations are holder-initiated or operator-delegated.** Any token holder can hide or reveal their own tokens. An operator with `HIDE_TOKENS` permission can hide tokens on behalf of a holder; an operator with `REVEAL_TOKENS` permission can reveal on their behalf.
144
- - **No owner or admin role.** The contract has no `Ownable` or privileged functions.
145
- - **Mint permission is granted via REVOwner.** `REVHiddenTokens` is listed in `REVOwner.hasMintPermissionFor` so it can re-mint tokens on reveal. This is a global immutable set at REVOwner deployment.
146
- - **BURN_TOKENS permission is per-user.** Each user must individually grant `BURN_TOKENS` permission to the `REVHiddenTokens` contract before hiding tokens.
147
-
148
- ## Immutable Configuration
149
-
150
- The following parameters are set at deployment and can never be changed:
151
-
152
- ### REVDeployer (per-revnet, set at `deployFor` time)
153
- - Stage schedule (start times, issuance rates, cut frequencies, cut percentages)
154
- - Cash-out tax rates per stage
155
- - Split percentages per stage
156
- - Auto-issuance amounts and beneficiaries
157
- - Base currency
158
- - ERC-20 token name and symbol
159
- - Encoded configuration hash (used for cross-chain sucker deployment verification)
160
-
161
- ### REVDeployer (global, set at contract deployment)
162
- - `CONTROLLER` -- the Juicebox controller
163
- - `DIRECTORY` -- the Juicebox directory
164
- - `PROJECTS` -- the Juicebox projects NFT contract
165
- - `PERMISSIONS` -- the Juicebox permissions contract
166
- - `SUCKER_REGISTRY` -- the sucker registry
167
- - `BUYBACK_HOOK` -- the buyback hook / data hook
168
- - `HOOK_DEPLOYER` -- the 721 tiers hook deployer
169
- - `PUBLISHER` -- the croptop publisher
170
- - `LOANS` -- the loans contract address
171
- - `FEE_REVNET_ID` -- the project ID that receives cash-out fees
172
- - `FEE` -- the cash-out fee (2.5%)
173
- - `CASH_OUT_DELAY` -- 30 days for cross-chain deployments
174
- - `DEFAULT_BUYBACK_POOL_FEE` -- 10,000 (1% Uniswap V4 fee tier)
175
- - `DEFAULT_BUYBACK_TICK_SPACING` -- 200
176
- - `DEFAULT_BUYBACK_TWAP_WINDOW` -- 2 days
177
- - `OWNER()` -- view returning the REVOwner address
178
-
179
- ### REVOwner (global, set at contract deployment)
180
- - `BUYBACK_HOOK` -- the buyback hook (shared immutable with REVDeployer)
181
- - `DIRECTORY` -- the Juicebox directory (shared immutable with REVDeployer)
182
- - `FEE_REVNET_ID` -- the project ID that receives cash-out fees (shared immutable)
183
- - `HIDDEN_TOKENS` -- the hidden tokens contract address (shared immutable)
184
- - `SUCKER_REGISTRY` -- the sucker registry (shared immutable)
185
- - `LOANS` -- the loans contract address (shared immutable)
186
- - `FEE` -- the cash-out fee constant (2.5%)
187
- - `DEPLOYER` -- the REVDeployer address (storage variable, set once by the REVOwner initializer account using the precomputed canonical deployer address)
188
-
189
- ### REVLoans (global, set at contract deployment)
190
- - `CONTROLLER`, `DIRECTORY`, `PRICES`, `PROJECTS` -- protocol infrastructure
191
- - `REV_ID` -- the REV revnet that receives loan fees
192
- - `PERMIT2` -- the permit2 contract
193
- - `LOAN_LIQUIDATION_DURATION` -- 10 years (3650 days)
194
- - `MIN_PREPAID_FEE_PERCENT` -- 2.5% (`25` out of `MAX_FEE = 1000`)
195
- - `MAX_PREPAID_FEE_PERCENT` -- 50% (`500` out of `MAX_FEE = 1000`)
196
- - `REV_PREPAID_FEE_PERCENT` -- 1% (`10` out of `MAX_FEE = 1000`)
74
+ - The split operator cannot rewrite issuance schedule, cash-out tax, or stage timing.
75
+ - `REVLoans` owner cannot redirect collateral or treasury funds.
76
+ - `REVDeployer` cannot act like a normal human owner despite holding the project NFT.
77
+ - Nobody can change the revnet's fundamental staged design after deployment.
78
+ - Nobody can administratively restore collateral after an expired loan has been liquidated.
197
79
 
198
- ## Admin Boundaries
80
+ ## Source Map
199
81
 
200
- What admins **cannot** do -- this is the most important section for understanding revnet security guarantees:
201
-
202
- ### The Split Operator Cannot:
203
- - Change issuance rates, schedules, or weight decay
204
- - Modify cash-out tax rates
205
- - Queue new rulesets or stages
206
- - Pause or disable cash outs
207
- - Mint fungible revnet tokens (only 721 minting if explicitly enabled at deploy)
208
- - Access or redirect treasury funds (no payout limit control)
209
- - Upgrade or migrate the revnet's controller
210
- - Change the revnet's terminals
211
- - Transfer the project NFT
212
- - Modify fund access limits or surplus allowances
213
- - Change the data hook or approval hook
214
- - Affect loan parameters or collateral
215
-
216
- ### The REVLoans Owner Cannot:
217
- - Change loan interest rates, fees, or liquidation timing
218
- - Access or redirect collateral or borrowed funds
219
- - Prevent loan creation, repayment, or liquidation
220
- - Mint or burn tokens
221
- - Affect any revnet's configuration
222
-
223
- ### The REVDeployer Contract Cannot (even though it holds the project NFT):
224
- - Queue new rulesets (no public or internal function exists for this)
225
- - Transfer the project NFT to any other address
226
- - Change terminals or the controller
227
- - Modify fund access limits after deployment
228
- - Override the data hook logic
229
- - Selectively block cash outs (beyond the time-limited `CASH_OUT_DELAY` for cross-chain deployments)
230
-
231
- ### Nobody Can:
232
- - Change a revnet's stage schedule after deployment
233
- - Prevent token holders from eventually cashing out
234
- - Extract funds from the treasury without going through the bonding curve
235
- - Modify the fee structure (2.5% cash-out fee, loan fees)
236
- - Change which contract is the data hook for a revnet (always REVOwner)
237
- - Alter auto-issuance amounts after deployment (they can only be claimed, not changed)
82
+ - `src/REVDeployer.sol`
83
+ - `src/REVOwner.sol`
84
+ - `src/REVLoans.sol`
85
+ - `src/REVHiddenTokens.sol`
86
+ - `test/`
package/ARCHITECTURE.md CHANGED
@@ -2,39 +2,51 @@
2
2
 
3
3
  ## Purpose
4
4
 
5
- `revnet-core-v6` defines an autonomous Juicebox project pattern with staged, precommitted economics and token-collateralized loans. A revnet is intentionally ownerless after deployment: project behavior follows its queued stages and integrated hooks rather than ongoing governance.
5
+ `revnet-core-v6` defines an autonomous Juicebox project pattern with staged, precommitted economics and token-collateralized loans. A revnet is intentionally ownerless after deployment in the human sense: behavior follows staged configuration and constrained runtime hooks instead of ongoing governance.
6
6
 
7
- ## Boundaries
7
+ ## System Overview
8
8
 
9
- - `REVDeployer` owns launch-time configuration and runtime wrapper behavior.
10
- - `REVOwner` owns owner-like data-hook behavior for revnet projects.
11
- - `REVLoans` owns the loan lifecycle.
12
- - `REVHiddenTokens` owns temporary token hiding and supply exclusion.
13
- - The repo composes several sibling repos instead of reimplementing them.
9
+ `REVDeployer` handles launch-time shape, staged rulesets, hook wiring, and runtime wrapper behavior. `REVOwner` provides the owner-like runtime policy surface for pay and cash-out hooks after launch. `REVLoans` manages burn-collateral loan positions represented as ERC-721 loans. `REVHiddenTokens` lets holders burn tokens to exclude them from total supply until they reveal them again.
14
10
 
15
- ## Main Components
11
+ ## Core Invariants
16
12
 
17
- | Component | Responsibility |
18
- | --- | --- |
19
- | `REVDeployer` | Launches revnets, queues staged rulesets, wires hooks, grants operator permissions, and exposes runtime wrapper behavior |
20
- | `REVOwner` | Ownerless policy surface plugged into revnet rulesets |
21
- | `REVLoans` | Burn-collateral borrow/repay/liquidate flow represented as ERC-721 loans |
22
- | `REVHiddenTokens` | Temporary token hiding: burn to exclude from totalSupply, re-mint on reveal |
23
- | config structs | Stage, auto-issuance, loan source, and 721-hook configuration surfaces |
13
+ - Revnets are intended to be ownerless after deployment; easy admin recovery paths would violate the product model.
14
+ - Stage configuration is effectively permanent once queued.
15
+ - Loan collateral is burned, not escrowed, and supply-sensitive logic must treat it as real destruction until repayment.
16
+ - Hidden tokens are burned, not escrowed, and reduce total supply until revealed.
17
+ - `REVOwner` and `REVDeployer` are tightly coupled; their setup order matters.
18
+ - Cash-out delay affects both exits and borrowing power. If the current stage delays cash out, `REVLoans` should treat borrowability as zero until that delay expires.
19
+ - Cross-chain supply and surplus are part of revnet economics. Local payouts and loans must not ignore remote sucker snapshots.
20
+
21
+ ## Modules
22
+
23
+ | Module | Responsibility | Notes |
24
+ | --- | --- | --- |
25
+ | `REVDeployer` | Launch, staged rulesets, hook wiring, permissions, runtime wrapper behavior | Launch-time and runtime wrapper |
26
+ | `REVOwner` | Runtime owner-like policy surface | Hook-facing policy |
27
+ | `REVLoans` | Borrow, repay, and liquidate burned-collateral loan positions | Economic core |
28
+ | `REVHiddenTokens` | Temporary supply exclusion through burn and reveal | Supply-sensitive utility |
29
+ | config structs | Stage, loan-source, auto-issuance, and hook config | Launch-time inputs |
30
+
31
+ ## Trust Boundaries
24
32
 
25
- ## Runtime Model
33
+ - Treasury and ruleset mechanics remain rooted in `nana-core-v6`.
34
+ - Optional integrations come from `nana-buyback-hook-v6`, `nana-router-terminal-v6`, `nana-suckers-v6`, and `nana-721-hook-v6`.
35
+ - This repo composes those systems into an ownerless product shape instead of reimplementing them.
36
+
37
+ ## Critical Flows
26
38
 
27
39
  ### Revnet Lifecycle
28
40
 
29
41
  ```text
30
42
  creator
31
- -> deploys a revnet with a fixed sequence of stages
43
+ -> deploys a revnet with a fixed stage sequence
32
44
  stage transitions
33
- -> happen automatically over time through ruleset activation
45
+ -> activate automatically over time through rulesets
34
46
  participants
35
- -> pay in, receive tokens, cash out, and interact with downstream hooks
47
+ -> pay in, receive tokens, cash out, and interact with enabled integrations
36
48
  operators or permissionless callers
37
- -> perform bounded maintenance actions such as auto-issuance claims
49
+ -> perform bounded maintenance such as auto-issuance claims
38
50
  ```
39
51
 
40
52
  ### Loan Lifecycle
@@ -42,35 +54,50 @@ operators or permissionless callers
42
54
  ```text
43
55
  borrower
44
56
  -> burns revnet tokens as collateral
45
- -> receives funds from the treasury through REVLoans
57
+ -> borrowability is computed from the current stage, omnichain supply/surplus, and local liquidity caps
58
+ -> receives treasury-backed funds through REVLoans
46
59
  -> later repays to remint collateral
47
- -> or gets liquidated after the long expiration window
60
+ -> or is liquidated after the expiration window
48
61
  ```
49
62
 
50
- ## Critical Invariants
51
-
52
- - The project is designed to be ownerless after deployment. "Easy" admin recovery paths would break the product thesis.
53
- - Stage configuration is effectively permanent once queued.
54
- - Loan collateral is burned, not escrowed. Supply-sensitive logic must treat that as real destruction until repayment.
55
- - Hidden tokens are burned, not escrowed. They reduce totalSupply until revealed. This interacts with bonding curve valuations.
56
- - `REVOwner` and `REVDeployer` are tightly coupled. Their setup order is part of correctness.
63
+ ## Accounting Model
57
64
 
58
- ## Where Complexity Lives
65
+ The repo does not replace core treasury accounting. Its critical economic logic is the interaction between staged revnet configuration, burned-collateral loan state, hidden-token supply exclusion, and omnichain revnet state imported from suckers.
59
66
 
60
- - Revnets span deployment-time guarantees, runtime hook behavior, and loan-state transitions.
61
- - The most subtle risks sit where treasury state, stage economics, and loan borrowability interact.
62
- - Ownerlessness is a feature, but it also removes easy operational recovery from misconfiguration.
67
+ `REVOwner` also composes payment and cash-out hooks. On pay, it merges 721-tier split forwarding with buyback-hook behavior and scales mint weight so the terminal only mints against the share actually entering the project. On cash out, it uses omnichain supply and surplus for reclaim math, exempts trusted suckers from tax and fee routing, and may append a fee hook spec that forwards rev fees to the fee revnet.
63
68
 
64
- ## Dependencies
69
+ ## Security Model
65
70
 
66
- - `nana-core-v6` for treasury and ruleset mechanics
67
- - `nana-buyback-hook-v6`, `nana-suckers-v6`, `nana-router-terminal-v6`, and optionally `nana-721-hook-v6` for composed features
68
- - `croptop-core-v6` and other product repos when revnets are used as economic backends
71
+ - The highest-risk interactions sit where stage economics, treasury state, and loan borrowability meet.
72
+ - Ownerlessness removes convenient operational recovery from misconfiguration.
73
+ - Hidden-token and burned-collateral semantics materially affect supply-sensitive pricing.
74
+ - `REVOwner` is a live runtime policy surface, not just a launch helper. Cash-out delay, buyback composition, sucker exemptions, and fee routing all pass through it.
75
+ - Rev cash-out fees stack on top of protocol-fee behavior rather than replacing it. Fee semantics should be reviewed with terminal behavior, not in isolation.
69
76
 
70
77
  ## Safe Change Guide
71
78
 
72
- - Treat deployer-time behavior and runtime wrapper behavior as one system.
73
- - Any change to stage semantics should be checked against loan math, cash-out semantics, and downstream fee-project expectations.
79
+ - Review deploy-time behavior and runtime wrapper behavior together.
80
+ - If stage semantics change, inspect loan math, cash-out behavior, and downstream fee expectations together.
74
81
  - Do not casually add mutable admin escape hatches.
75
- - Flash-loan and surplus-sensitive logic deserves adversarial review whenever loan calculations change.
76
- - If a change affects borrowability or repayment, test both sourced and unsourced loan paths.
82
+ - If you change borrowability, re-check cash-out-delay gating, omnichain surplus inputs, and local-surplus caps together.
83
+ - If you change hook composition, re-check 721 split handling, buyback hook assumptions, and which callers retain mint permission through `REVOwner`.
84
+ - If loan calculations change, review flash-loan and surplus-sensitive behavior adversarially.
85
+
86
+ ## Canonical Checks
87
+
88
+ - cash-out-delay interaction with loans:
89
+ `test/TestLoansCashOutDelay.t.sol`
90
+ - stage transitions and borrowability drift:
91
+ `test/TestStageTransitionBorrowable.t.sol`
92
+ - omnichain or phantom-surplus edge cases:
93
+ `test/audit/CodexPhantomSurplusTerminal.t.sol`
94
+
95
+ ## Source Map
96
+
97
+ - `src/REVDeployer.sol`
98
+ - `src/REVOwner.sol`
99
+ - `src/REVLoans.sol`
100
+ - `src/REVHiddenTokens.sol`
101
+ - `test/TestLoansCashOutDelay.t.sol`
102
+ - `test/TestStageTransitionBorrowable.t.sol`
103
+ - `test/audit/CodexPhantomSurplusTerminal.t.sol`
@@ -2,7 +2,7 @@
2
2
 
3
3
  Revnets are autonomous Juicebox projects with staged economics and token-collateralized loans. Audit this repo as both a privileged deployer layer and a live economic system.
4
4
 
5
- ## Objective
5
+ ## Audit Objective
6
6
 
7
7
  Find issues that:
8
8
  - let a participant borrow more than intended against revnet collateral
@@ -40,7 +40,7 @@ Read in this order:
40
40
  `REVDeployer` explains why that behavior exists.
41
41
  `REVLoans` is where those economics are turned into extractable collateral value.
42
42
 
43
- ## System Model
43
+ ## Security Model
44
44
 
45
45
  The repo splits responsibilities:
46
46
  - `REVDeployer`: launches revnets, encodes stage configs, manages optional 721 and sucker composition
@@ -57,6 +57,22 @@ Two mental models help here:
57
57
  - `REVDeployer` is mostly a launch-time authority that permanently shapes economics
58
58
  - `REVOwner` is a runtime hook that can make a launched revnet behave very differently from a plain Juicebox project
59
59
 
60
+ ## Roles And Privileges
61
+
62
+ | Role | Powers | How constrained |
63
+ |------|--------|-----------------|
64
+ | Revnet launcher | Set the stage schedule and optional compositions | Must not retain hidden runtime privilege |
65
+ | `REVOwner` | Alter payment and cash-out behavior at runtime | Must remain narrowly scoped to documented economics |
66
+ | Borrower or operator | Open, repay, reallocate, hide, or reveal with delegated permissions | Must not redirect collateral or proceeds away from the holder |
67
+
68
+ ## Integration Assumptions
69
+
70
+ | Dependency | Assumption | What breaks if wrong |
71
+ |------------|------------|----------------------|
72
+ | `nana-core-v6` | Surplus and issuance accounting remain coherent | Borrow limits and stage economics become unsound |
73
+ | `nana-721-hook-v6` and `nana-buyback-hook-v6` | Optional composition does not distort accounting unexpectedly | Runtime economics diverge from the stage design |
74
+ | `nana-suckers-v6` | Omnichain privilege surfaces identify real suckers only | Fee-free or mint exemptions widen |
75
+
60
76
  ## Critical Invariants
61
77
 
62
78
  1. Stage immutability
@@ -83,24 +99,7 @@ Tokens hidden via REVHiddenTokens must be exactly recoverable on reveal. The hid
83
99
  8. Stage transitions do not create hidden refinancing windows
84
100
  Changes in issuance or cash-out economics across stages must not let a borrower lock in value that the system intended to become unavailable.
85
101
 
86
- ## Threat Model
87
-
88
- Prioritize:
89
- - surplus manipulation before and after borrowing
90
- - stage-boundary timing attacks
91
- - cash-out delay bypasses
92
- - array or hook-spec assumptions that depend on non-empty returns
93
- - split-weight accounting during 721 compositions
94
- - Permit2 and ERC-2771 assisted loan flows
95
- - operator delegation abuse: `OPEN_LOAN`, `REPAY_LOAN`, `REALLOCATE_LOAN`, `HIDE_TOKENS`, `REVEAL_TOKENS` permission checks — verify collateral and loan NFTs always flow to the holder/owner, never the operator
96
-
97
- The best attacker mindsets here are:
98
- - a borrower who can move surplus or stage timing before and after borrowing
99
- - a caller exploiting the fact that revnets are composed from several optional subsystems, not one monolith
100
- - an operator or deployer helper that retained one capability too many
101
- - a delegated operator who tricks a holder into granting permission, then exploits the delegation to extract value (e.g., borrowing on behalf of a holder and directing funds to a beneficiary they control)
102
-
103
- ## Hotspots
102
+ ## Attack Surfaces
104
103
 
105
104
  - `REVOwner.beforePayRecordedWith`
106
105
  - `REVOwner.beforeCashOutRecordedWith`
@@ -110,35 +109,19 @@ The best attacker mindsets here are:
110
109
  - `REVLoans` operator delegation: `OPEN_LOAN`, `REPAY_LOAN`, `REALLOCATE_LOAN` inline permission checks — verify holder/owner receives collateral and loan NFTs in all delegation paths
111
110
  - any path that assumes a valid tiered 721 hook or sucker mapping exists
112
111
 
113
- ## Sequences Worth Replaying
114
-
115
- 1. Pay into a revnet with 721 and buyback composition enabled, then inspect how weight is scaled before and after hook specs are consumed.
116
- 2. Borrow near a stage boundary, then repay, refinance, or liquidate after the next stage becomes active.
117
- 3. Borrow after surplus inflation, then force or observe surplus contraction before liquidation.
118
- 4. Cash out through a legitimate sucker path versus a near-sucker spoof path.
119
- 5. Any path where `REVOwner` expects hook arrays or external replies to be non-empty.
120
- 6. Hide tokens, have an accomplice cash out at the inflated rate, then reveal — check whether the net outcome is profitable.
112
+ Replay these sequences:
113
+ 1. pay into a revnet with 721 and buyback composition enabled and inspect weight scaling
114
+ 2. borrow near a stage boundary, then repay, refinance, or liquidate in the next stage
115
+ 3. borrow after surplus inflation, then contract surplus before liquidation
116
+ 4. cash out through a legitimate sucker path versus a near-sucker spoof path
117
+ 5. hide tokens, let another actor cash out, then reveal
121
118
 
122
- ## Finding Bar
119
+ ## Accepted Risks Or Behaviors
123
120
 
124
- The best findings in this repo usually prove one of these:
125
- - a revnet mints or redeems on economics different from the stage schedule users think they are on
126
- - the runtime hook scales payment or cash-out accounting incorrectly during composition
127
- - the loan system can externalize loss to the treasury through timing, surplus movement, or fee math
128
- - a deployer-only or operator-only assumption survives launch and remains exploitable at runtime
121
+ - Composition is the default audit target here, not an edge case.
129
122
 
130
- ## Build And Verification
123
+ ## Verification
131
124
 
132
- Standard workflow:
133
125
  - `npm install`
134
126
  - `forge build`
135
127
  - `forge test`
136
-
137
- Current tests emphasize:
138
- - lifecycle and invincibility properties
139
- - loan invariants and attacks
140
- - fee recovery
141
- - split-weight adjustments
142
- - regressions around low-severity edge cases
143
-
144
- Strong findings in this repo usually combine economics and composition: a bug is especially valuable if it only appears once a revnet is wired into the rest of the ecosystem.