@rev-net/core-v6 0.0.32 → 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 +60 -211
- package/ARCHITECTURE.md +68 -41
- package/AUDIT_INSTRUCTIONS.md +28 -45
- package/README.md +25 -6
- package/RISKS.md +8 -1
- package/SKILLS.md +13 -4
- package/USER_JOURNEYS.md +158 -54
- package/foundry.toml +1 -0
- package/package.json +36 -36
- package/references/operations.md +7 -0
- package/references/runtime.md +8 -0
- package/src/structs/REV721TiersHookFlags.sol +0 -1
- package/src/structs/REVAutoIssuance.sol +0 -1
- package/src/structs/REVBaseline721HookConfig.sol +0 -1
- package/src/structs/REVConfig.sol +0 -1
- package/src/structs/REVCroptopAllowedPost.sol +0 -1
- package/src/structs/REVDeploy721TiersHookConfig.sol +0 -1
- package/src/structs/REVDescription.sol +0 -1
- package/src/structs/REVLoan.sol +0 -1
- package/src/structs/REVLoanSource.sol +0 -1
- package/src/structs/REVStageConfig.sol +0 -1
- package/src/structs/REVSuckerDeploymentConfig.sol +0 -1
package/README.md
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
# Revnet Core
|
|
2
2
|
|
|
3
|
-
`@rev-net/core-v6` deploys and operates Revnets:
|
|
3
|
+
`@rev-net/core-v6` deploys and operates Revnets: Juicebox project shapes with staged economics, optional tiered NFTs, cross-chain support, buyback integration, and token-collateralized loans.
|
|
4
4
|
|
|
5
5
|
Docs: <https://docs.juicebox.money>
|
|
6
|
-
Architecture: [ARCHITECTURE.md](./ARCHITECTURE.md)
|
|
6
|
+
Architecture: [ARCHITECTURE.md](./ARCHITECTURE.md)
|
|
7
|
+
User journeys: [USER_JOURNEYS.md](./USER_JOURNEYS.md)
|
|
8
|
+
Skills: [SKILLS.md](./SKILLS.md)
|
|
9
|
+
Risks: [RISKS.md](./RISKS.md)
|
|
10
|
+
Administration: [ADMINISTRATION.md](./ADMINISTRATION.md)
|
|
11
|
+
Audit instructions: [AUDIT_INSTRUCTIONS.md](./AUDIT_INSTRUCTIONS.md)
|
|
7
12
|
|
|
8
13
|
## Overview
|
|
9
14
|
|
|
10
|
-
A Revnet is meant to
|
|
15
|
+
A Revnet is meant to minimize human administration after launch. Its economics are encoded up front as a sequence of stages, and the runtime hook plus loan system enforce those rules over time.
|
|
11
16
|
|
|
12
17
|
This package provides:
|
|
13
18
|
|
|
@@ -17,9 +22,9 @@ This package provides:
|
|
|
17
22
|
|
|
18
23
|
It also composes with the 721 hook stack, buyback hook, router terminal, Croptop, and suckers where needed.
|
|
19
24
|
|
|
20
|
-
Use this repo when the product is
|
|
25
|
+
Use this repo when the product is a treasury-backed network with encoded stage transitions and a tightly constrained post-launch admin surface. Do not use it when governance, mutable operator control, or simple project deployment is the goal.
|
|
21
26
|
|
|
22
|
-
The key point is that a Revnet is not just "a Juicebox project with presets." It is a project shape whose admin surface is intentionally collapsed into deployment-time configuration plus constrained runtime operators.
|
|
27
|
+
The key point is that a Revnet is not just "a Juicebox project with presets." It is a project shape whose admin surface is intentionally collapsed into deployment-time configuration plus constrained runtime operators, even though the deployer contract still retains the project NFT.
|
|
23
28
|
|
|
24
29
|
## Key Contracts
|
|
25
30
|
|
|
@@ -71,6 +76,14 @@ The shortest useful reading order is:
|
|
|
71
76
|
|
|
72
77
|
Do not audit those contracts in isolation if the deployment enables cross-package features; the composed network is the real product.
|
|
73
78
|
|
|
79
|
+
## High-Signal Tests
|
|
80
|
+
|
|
81
|
+
1. `test/REVLifecycle.t.sol`
|
|
82
|
+
2. `test/REVLoans.invariants.t.sol`
|
|
83
|
+
3. `test/TestLongTailEconomics.t.sol`
|
|
84
|
+
4. `test/fork/TestLoanBorrowFork.t.sol`
|
|
85
|
+
5. `test/audit/CodexPhantomSurplusTerminal.t.sol`
|
|
86
|
+
|
|
74
87
|
## Install
|
|
75
88
|
|
|
76
89
|
```bash
|
|
@@ -94,7 +107,7 @@ Useful scripts:
|
|
|
94
107
|
|
|
95
108
|
## Deployment Notes
|
|
96
109
|
|
|
97
|
-
Revnet deployment assumes the core protocol, 721 hook, buyback hook, router terminal, suckers, and Croptop packages are available.
|
|
110
|
+
Revnet deployment assumes the core protocol, 721 hook, buyback hook, router terminal, suckers, and Croptop packages are available. Revnets are intentionally unowned in the direct human-EOA sense after deployment, but the deployer contract itself retains the project NFT and remains part of the ownership model.
|
|
98
111
|
|
|
99
112
|
## Repository Layout
|
|
100
113
|
|
|
@@ -120,3 +133,9 @@ script/
|
|
|
120
133
|
- burned-collateral lending is operationally different from escrowed-collateral lending and needs clear integrator expectations
|
|
121
134
|
|
|
122
135
|
The usual review failure mode is to focus on the loans or the stages in isolation. The real system is the combination of stage economics, runtime hook behavior, and who is still allowed to act after deployment.
|
|
136
|
+
|
|
137
|
+
## For AI Agents
|
|
138
|
+
|
|
139
|
+
- Describe Revnets as treasury-backed Juicebox project shapes with encoded stage transitions, not as simple deploy presets.
|
|
140
|
+
- Read `REVDeployer`, `REVOwner`, and `REVLoans` together before answering economic or admin-surface questions.
|
|
141
|
+
- If a deployment enables buybacks, 721 hooks, or suckers, inspect those sibling repos before making definitive claims.
|
package/RISKS.md
CHANGED
|
@@ -28,6 +28,8 @@ Read [ARCHITECTURE.md](./ARCHITECTURE.md) and [SKILLS.md](./SKILLS.md) for proto
|
|
|
28
28
|
- **Bonding curve is the sole collateral oracle.** `REVLoans` uses `JBCashOuts.cashOutFrom` to value collateral. There is no external price oracle, no liquidation margin, and no health factor. The borrowable amount equals the cash-out value at the moment of borrowing.
|
|
29
29
|
- **Juicebox core contracts are correct.** `JBController`, `JBMultiTerminal`, `JBTerminalStore`, `JBTokens`, `JBPrices` -- a bug in any of these is a bug in every revnet.
|
|
30
30
|
- **Buyback hook operates correctly.** `BUYBACK_HOOK` handles swap-vs-mint routing. All revnets from the same deployer share one instance. Failure falls back to direct minting (not a revert), so the failure mode is economic inefficiency, not fund loss.
|
|
31
|
+
- **Buyback pool auto-initialization is best-effort, not guaranteed.** `REVDeployer._tryInitializeBuybackPoolFor` silently catches `initializePoolFor(...)` failures. That means a revnet can deploy successfully while the expected default buyback pool is missing, misconfigured, or already initialized differently. Operators must verify pool state after deployment instead of assuming launch implies the buyback pool is ready.
|
|
32
|
+
- **REVOwner expects at most one buyback cash-out hook spec.** In `beforeCashOutRecordedWith`, `REVOwner` keeps only `buybackHookSpecifications[0]` when composing the buyback path with the rev fee hook. If a future buyback hook implementation returns multiple cash-out hook specs, the additional specs are silently dropped.
|
|
31
33
|
- **Suckers are honest bridges.** Suckers get 0% cashout tax in `beforeCashOutRecordedWith`. A compromised or malicious sucker registered in `SUCKER_REGISTRY` can extract funds from any revnet at zero cost.
|
|
32
34
|
- **Auto-issuance beneficiaries are set at deployment.** Beneficiary addresses are baked into the stage configuration. If a beneficiary address is a contract that becomes compromised, or an EOA whose keys are lost, those auto-issuance tokens are either captured or permanently unclaimable.
|
|
33
35
|
- **REVLoans contract address is immutable per deployer.** `LOANS` is set once in the REVDeployer constructor (and shared as an immutable on REVOwner) with wildcard `USE_ALLOWANCE` permission (`projectId=0`). If the loans contract has a vulnerability, every revnet's surplus is exposed.
|
|
@@ -93,7 +95,7 @@ Read [ARCHITECTURE.md](./ARCHITECTURE.md) and [SKILLS.md](./SKILLS.md) for proto
|
|
|
93
95
|
### Loan source rotation after deployment
|
|
94
96
|
|
|
95
97
|
- **Loan sources grow monotonically.** `_loanSourcesOf[revnetId]` is append-only. Each new `(terminal, token)` pair used for borrowing adds an entry. Entries are never removed, even if all loans from that source are repaid. `_totalBorrowedFrom` iterates the entire array on every borrow/repay.
|
|
96
|
-
- **Removed terminals remain as loan sources.** If a terminal is de-registered from `JBDirectory` (via migration), existing loans from that terminal remain valid
|
|
98
|
+
- **Removed terminals remain as loan sources.** If a terminal is de-registered from `JBDirectory` (via migration), existing loans from that terminal remain valid because each loan stores a direct terminal reference. New borrows against that terminal are blocked by the `DIRECTORY.isTerminalOf` check in `borrowFrom`, but `_totalBorrowedFrom` still queries the old terminal's `accountingContextForTokenOf`. On current core terminals that call returns the stored accounting context rather than reverting, so debt accounting continues to depend on that legacy terminal's retained token configuration even after directory migration.
|
|
97
99
|
|
|
98
100
|
### `reallocateCollateralFromLoan` sandwich potential
|
|
99
101
|
|
|
@@ -193,6 +195,7 @@ These MUST hold. Breaking any of them is a finding.
|
|
|
193
195
|
- **Stage progression monotonicity.** `startsAtOrAfter` values strictly increase between stages. The first stage can be 0 (mapped to `block.timestamp`).
|
|
194
196
|
- **Auto-issuance single-claim.** Each `(revnetId, stageId, beneficiary)` can only be claimed once. `amountToAutoIssue` is zeroed BEFORE the external `mintTokensOf` call (CEI pattern).
|
|
195
197
|
- **Split percentages.** Per-stage `splitPercent > 0` requires `splits.length > 0`. Split percentages are validated by `JBSplits` in core (must sum to <= `SPLITS_TOTAL_PERCENT`).
|
|
198
|
+
- **Buyback pool readiness is not implied by successful deployment.** `deployFor` can finish even when `_tryInitializeBuybackPoolFor` failed internally. Post-deploy verification must check the actual buyback pool registration and initialization state rather than inferring success from the absence of a revert.
|
|
196
199
|
|
|
197
200
|
### Fee flows
|
|
198
201
|
|
|
@@ -245,3 +248,7 @@ This is accepted because the JBPermissions delegation model is opt-in: a holder
|
|
|
245
248
|
### 8.6 Borrow-repay arbitrage is unprofitable (by design)
|
|
246
249
|
|
|
247
250
|
A borrower who pays the prepaid fee upfront (minimum 2.5% + REV fee 1% = 3.5%) can repay at any time within the prepaid duration with no additional cost. If the bonding curve value of the collateral increases during the prepaid window, the borrower can repay, recover their collateral, and cash out at the higher value. This is not profitable as a standalone strategy because the 3.5% minimum fee exceeds the expected value gained from short-term surplus fluctuations. For borrowers who need liquidity anyway, it provides free optionality — which is the intended use case.
|
|
251
|
+
|
|
252
|
+
### 8.7 REVOwner only forwards the first buyback cash-out hook spec
|
|
253
|
+
|
|
254
|
+
When `REVOwner.beforeCashOutRecordedWith` combines the buyback hook response with its own rev-fee hook spec, it only preserves the first element of `buybackHookSpecifications`. This is accepted because the current buyback-hook design is expected to return at most one cash-out hook spec. The trade-off is forward-compatibility risk: if a future buyback hook starts returning multiple cash-out hook specs, revnets using this owner contract will silently drop the extras unless `REVOwner` is updated too.
|
package/SKILLS.md
CHANGED
|
@@ -3,19 +3,20 @@
|
|
|
3
3
|
## Use This File For
|
|
4
4
|
|
|
5
5
|
- Use this file when the task involves revnet deployment, staged issuance, split operator logic, auto-issuance, or the revnet loan system built on top of Juicebox core.
|
|
6
|
-
- Start here, then
|
|
6
|
+
- Start here, then decide whether the issue is really in `REVDeployer` deployment shape, `REVOwner` runtime-hook behavior, or `REVLoans` debt accounting. Most confusion in this repo comes from mixing those three roles.
|
|
7
7
|
|
|
8
8
|
## Read This Next
|
|
9
9
|
|
|
10
10
|
| If you need... | Open this next |
|
|
11
11
|
|---|---|
|
|
12
|
-
| Repo overview and operator flow | [`README.md`](./README.md) |
|
|
12
|
+
| Repo overview and operator flow | [`README.md`](./README.md), [`ARCHITECTURE.md`](./ARCHITECTURE.md) |
|
|
13
13
|
| Deployment and stage config | [`src/REVDeployer.sol`](./src/REVDeployer.sol), [`script/Deploy.s.sol`](./script/Deploy.s.sol) |
|
|
14
|
-
| Runtime owner and data-hook behavior | [`src/REVOwner.sol`](./src/REVOwner.sol) |
|
|
14
|
+
| Runtime owner and data-hook behavior | [`src/REVOwner.sol`](./src/REVOwner.sol), [`references/runtime.md`](./references/runtime.md) |
|
|
15
15
|
| Loan accounting and liquidation behavior | [`src/REVLoans.sol`](./src/REVLoans.sol) |
|
|
16
16
|
| Temporary token hiding and supply exclusion | [`src/REVHiddenTokens.sol`](./src/REVHiddenTokens.sol) |
|
|
17
17
|
| Types and helpers | [`src/structs/`](./src/structs/), [`src/interfaces/`](./src/interfaces/), [`test/helpers/`](./test/helpers/) |
|
|
18
|
-
|
|
|
18
|
+
| Lifecycle, loans, and economic proofs | [`test/REVLifecycle.t.sol`](./test/REVLifecycle.t.sol), [`test/REVLoansRegressions.t.sol`](./test/REVLoansRegressions.t.sol), [`test/REVLoans.invariants.t.sol`](./test/REVLoans.invariants.t.sol), [`test/TestLongTailEconomics.t.sol`](./test/TestLongTailEconomics.t.sol) |
|
|
19
|
+
| Stage, fee, and adversarial edge cases | [`test/TestStageTransitionBorrowable.t.sol`](./test/TestStageTransitionBorrowable.t.sol), [`test/TestSplitWeightE2E.t.sol`](./test/TestSplitWeightE2E.t.sol), [`test/TestLoansCashOutDelay.t.sol`](./test/TestLoansCashOutDelay.t.sol), [`test/REVLoansAttacks.t.sol`](./test/REVLoansAttacks.t.sol), [`test/TestFlashLoanSurplus.t.sol`](./test/TestFlashLoanSurplus.t.sol) |
|
|
19
20
|
|
|
20
21
|
## Repo Map
|
|
21
22
|
|
|
@@ -40,5 +41,13 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
40
41
|
## Working Rules
|
|
41
42
|
|
|
42
43
|
- Start in `REVDeployer` for launch-time behavior, `REVOwner` for runtime hook behavior, `REVLoans` for collateral and debt accounting, and `REVHiddenTokens` for temporary supply exclusion.
|
|
44
|
+
- Revnets are intentionally ownerless after deployment. Treat any “admin recovery” instinct as suspect unless the code proves it.
|
|
45
|
+
- `REVOwner` is not a minor helper; it is the live ruleset data hook. Cash-out fees, sucker exemptions, buyback composition, and mint permission checks all run through it.
|
|
46
|
+
- `REVOwner.beforePayRecordedWith(...)` intentionally composes 721 split specs before buyback routing and then rescales weight to the amount that actually enters the project. Treat that ordering as an invariant.
|
|
47
|
+
- Loan collateral is burned and re-minted, not escrowed. Any change that assumes escrow semantics is likely wrong.
|
|
48
|
+
- Cash-out delay is enforced in both runtime cash-outs and loan borrowing. If one path changes without the other, the protection is broken.
|
|
49
|
+
- Hidden tokens are supply exclusion, not a side balance. They change redemption economics by reducing visible supply until revealed.
|
|
43
50
|
- Verify any economic assumption in code or tests before relying on it. Revnet docs carry more economic interpretation than most repos.
|
|
51
|
+
- Loan behavior, stage transitions, and split-weight adjustments interact. Do not treat them as independent subsystems when editing economics.
|
|
52
|
+
- Cash-out delay, buyback defaults, and sucker deployment rules all exist to protect cross-chain and launch-time economics. They are not optional configuration sugar.
|
|
44
53
|
- For anything cross-chain or stage-related, check both the deployer path and the reading-state reference before editing.
|
package/USER_JOURNEYS.md
CHANGED
|
@@ -1,108 +1,212 @@
|
|
|
1
1
|
# User Journeys
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Repo Purpose
|
|
4
|
+
|
|
5
|
+
This repo packages autonomous Revnets: staged Juicebox projects whose runtime behavior is intentionally constrained
|
|
6
|
+
after launch. It owns deploy-time stage encoding, runtime enforcement, hidden-token mechanics, and lending against
|
|
7
|
+
Revnet token exposure. It does not turn the project back into an ordinary owner-governed treasury after deployment.
|
|
8
|
+
|
|
9
|
+
## Primary Actors
|
|
4
10
|
|
|
5
11
|
- teams launching autonomous Revnets with encoded stage transitions
|
|
6
12
|
- participants buying, holding, and cashing out Revnet exposure over time
|
|
7
13
|
- borrowers using Revnet tokens as collateral instead of selling them
|
|
8
14
|
- operators working inside the narrow post-launch envelope the deployer allows
|
|
9
15
|
|
|
16
|
+
## Key Surfaces
|
|
17
|
+
|
|
18
|
+
- `REVDeployer`: launch-time packaging, stage config, and operator envelope
|
|
19
|
+
- `REVOwner`: runtime pay and cash-out behavior for active Revnets
|
|
20
|
+
- `REVLoans`: borrowing, repayment, transfer, reallocation, and liquidation
|
|
21
|
+
- `REVHiddenTokens`: temporarily hide and later reveal token supply
|
|
22
|
+
- `autoIssueFor(...)`, `hideTokensOf(...)`, `revealTokensOf(...)`, `borrowFrom(...)`: high-signal runtime entrypoints
|
|
23
|
+
|
|
10
24
|
## Journey 1: Launch A Revnet With Its Long-Lived Rules Encoded Up Front
|
|
11
25
|
|
|
12
|
-
**
|
|
26
|
+
**Actor:** launch team.
|
|
27
|
+
|
|
28
|
+
**Intent:** deploy a Revnet whose economic envelope is encoded up front and stays bounded afterward.
|
|
29
|
+
|
|
30
|
+
**Preconditions**
|
|
31
|
+
- the team knows the stage schedule, issuance behavior, operator envelope, and optional integrations
|
|
32
|
+
- the team accepts that many choices become expensive or impossible to change later
|
|
33
|
+
|
|
34
|
+
**Main Flow**
|
|
35
|
+
1. Use `REVDeployer` with the staged config, split operators, and optional integrations.
|
|
36
|
+
2. The deployer launches the underlying project and preserves the intended ownership model.
|
|
37
|
+
3. Stage and auxiliary behavior are committed at launch instead of left to ordinary owner discretion.
|
|
38
|
+
4. The Revnet can now accept payments and progress through stages under the encoded rules.
|
|
13
39
|
|
|
14
|
-
**
|
|
40
|
+
**Failure Modes**
|
|
41
|
+
- teams assume deploy-time parameters can be revisited casually
|
|
42
|
+
- optional integrations are enabled without auditing their effect on the resulting network
|
|
15
43
|
|
|
16
|
-
**
|
|
17
|
-
|
|
18
|
-
2. The deployer launches the underlying project and keeps the ownership model aligned with the Revnet runtime contracts.
|
|
19
|
-
3. Stage config, issuance behavior, and auxiliary surfaces are committed as part of the launch instead of being left to human operators later.
|
|
20
|
-
4. The network can now accept payments and transition across stages without ordinary project-owner governance.
|
|
44
|
+
**Postconditions**
|
|
45
|
+
- the Revnet launches with its long-lived stage envelope encoded up front
|
|
21
46
|
|
|
22
47
|
## Journey 2: Participate In The Revnet Across Stage Transitions
|
|
23
48
|
|
|
24
|
-
**
|
|
49
|
+
**Actor:** participant.
|
|
25
50
|
|
|
26
|
-
**
|
|
51
|
+
**Intent:** buy, hold, and exit Revnet exposure across stage changes.
|
|
27
52
|
|
|
28
|
-
**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
3. As stages advance, later pays and cash outs follow the newly active parameters while the project identity stays constant.
|
|
53
|
+
**Preconditions**
|
|
54
|
+
- the Revnet is already live
|
|
55
|
+
- the participant understands active stage parameters can change behavior over time
|
|
32
56
|
|
|
33
|
-
**
|
|
57
|
+
**Main Flow**
|
|
58
|
+
1. Pay through the configured terminal or router.
|
|
59
|
+
2. Let `REVOwner` enforce runtime behavior such as pay handling, delayed exits, and stage-sensitive constraints.
|
|
60
|
+
3. As stages advance, later pays and exits follow the new active parameters while identity stays constant.
|
|
61
|
+
|
|
62
|
+
**Failure Modes**
|
|
63
|
+
- stage parameters are misread as mutable when they are fixed
|
|
64
|
+
- delayed cash-out behavior is misunderstood
|
|
65
|
+
- optional integrations materially change the participant experience in ways the caller ignored
|
|
66
|
+
|
|
67
|
+
**Postconditions**
|
|
68
|
+
- the participant's buys and exits now follow the active stage's constraints
|
|
34
69
|
|
|
35
70
|
## Journey 3: Claim Stage-Based Auto-Issuance When It Becomes Available
|
|
36
71
|
|
|
37
|
-
**
|
|
72
|
+
**Actor:** auto-issuance beneficiary.
|
|
73
|
+
|
|
74
|
+
**Intent:** claim stage-specific issuance only when it is actually live.
|
|
75
|
+
|
|
76
|
+
**Preconditions**
|
|
77
|
+
- the Revnet was deployed with auto-issuance allocations
|
|
78
|
+
- the target stage has started
|
|
38
79
|
|
|
39
|
-
**
|
|
80
|
+
**Main Flow**
|
|
81
|
+
1. Check `amountToAutoIssue(...)`.
|
|
82
|
+
2. Call `autoIssueFor(...)` once the stage is active.
|
|
83
|
+
3. The stored allocation is consumed and cannot be claimed twice.
|
|
40
84
|
|
|
41
|
-
**
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
85
|
+
**Failure Modes**
|
|
86
|
+
- callers try to claim before the stage is active
|
|
87
|
+
- reviewers assume auto-issuance is a generic mint path rather than a bounded stage allocation
|
|
88
|
+
|
|
89
|
+
**Postconditions**
|
|
90
|
+
- the stage allocation is either claimed once or remains reserved until it becomes valid
|
|
45
91
|
|
|
46
92
|
## Journey 3a: Hide Tokens To Increase Cash-Out Value For Remaining Holders
|
|
47
93
|
|
|
48
|
-
**
|
|
94
|
+
**Actor:** holder or authorized operator.
|
|
95
|
+
|
|
96
|
+
**Intent:** remove tokens from visible supply temporarily and later restore them.
|
|
97
|
+
|
|
98
|
+
**Preconditions**
|
|
99
|
+
- the holder granted the required permissions
|
|
100
|
+
- the holder accepts the supply and collateral implications of hiding tokens
|
|
49
101
|
|
|
50
|
-
**
|
|
102
|
+
**Main Flow**
|
|
103
|
+
1. Grant `BURN_TOKENS` to `REVHiddenTokens`.
|
|
104
|
+
2. Call `hideTokensOf(...)` to burn tokens and track the hidden balance.
|
|
105
|
+
3. The lower visible supply changes per-token cash-out value.
|
|
106
|
+
4. Later call `revealTokensOf(...)` to re-mint hidden tokens.
|
|
51
107
|
|
|
52
|
-
**
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
4. When the holder wants their tokens back, call `revealTokensOf(revnetId, tokenCount, beneficiary, holder)` to re-mint them. An operator with `REVEAL_TOKENS` permission can call this on behalf of the holder.
|
|
108
|
+
**Failure Modes**
|
|
109
|
+
- more tokens are revealed than were hidden
|
|
110
|
+
- holders forget revealed tokens increase visible supply again
|
|
111
|
+
- hidden tokens are assumed to remain usable as loan collateral
|
|
57
112
|
|
|
58
|
-
**
|
|
113
|
+
**Postconditions**
|
|
114
|
+
- visible supply is reduced or restored according to the holder's hidden-token state
|
|
59
115
|
|
|
60
116
|
## Journey 4: Borrow Against Revnet Tokens Instead Of Selling Them
|
|
61
117
|
|
|
62
|
-
**
|
|
118
|
+
**Actor:** holder or delegated loan operator.
|
|
63
119
|
|
|
64
|
-
**
|
|
120
|
+
**Intent:** borrow against Revnet exposure instead of selling it.
|
|
65
121
|
|
|
66
|
-
**
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
122
|
+
**Preconditions**
|
|
123
|
+
- the holder has eligible Revnet token exposure
|
|
124
|
+
- the holder trusts any delegated operator with `OPEN_LOAN`
|
|
125
|
+
|
|
126
|
+
**Main Flow**
|
|
127
|
+
1. Interact with `REVLoans` using eligible token exposure as collateral.
|
|
128
|
+
2. The system burns the collateralized token exposure and mints a loan NFT.
|
|
129
|
+
3. Borrowed value is issued under live Revnet economics.
|
|
130
|
+
4. The borrower can later repay, reallocate, transfer, or face liquidation.
|
|
131
|
+
|
|
132
|
+
**Failure Modes**
|
|
133
|
+
- delegated operators redirect value in ways the holder did not intend
|
|
134
|
+
- reviewers model the loan system as escrowed collateral when it is burned-collateral lending
|
|
135
|
+
|
|
136
|
+
**Postconditions**
|
|
137
|
+
- collateralized exposure is transformed into a live loan position under Revnet economics
|
|
71
138
|
|
|
72
139
|
## Journey 5: Repay, Transfer, Or Liquidate A Loan Position
|
|
73
140
|
|
|
74
|
-
**
|
|
141
|
+
**Actor:** borrower, loan owner, or liquidator.
|
|
142
|
+
|
|
143
|
+
**Intent:** change or settle an existing loan position.
|
|
75
144
|
|
|
76
|
-
**
|
|
145
|
+
**Preconditions**
|
|
146
|
+
- a loan already exists
|
|
147
|
+
- the actor has the rights or economic incentives required for the chosen path
|
|
77
148
|
|
|
78
|
-
**Flow**
|
|
79
|
-
1.
|
|
80
|
-
2.
|
|
81
|
-
3.
|
|
149
|
+
**Main Flow**
|
|
150
|
+
1. Repay to burn debt and restore the collateralized exposure.
|
|
151
|
+
2. Transfer the loan NFT if ownership of the debt position should move.
|
|
152
|
+
3. Liquidate if the encoded conditions permit it.
|
|
82
153
|
|
|
83
|
-
**
|
|
154
|
+
**Failure Modes**
|
|
155
|
+
- cross-ruleset behavior is misread
|
|
156
|
+
- zero-value or sourced-versus-unsourced paths are handled incorrectly by integrations
|
|
157
|
+
|
|
158
|
+
**Postconditions**
|
|
159
|
+
- the loan position is repaid, transferred, or liquidated according to the chosen path
|
|
84
160
|
|
|
85
161
|
## Journey 6: Operate Inside The Bounded Post-Launch Control Envelope
|
|
86
162
|
|
|
87
|
-
**
|
|
163
|
+
**Actor:** operator with ongoing powers.
|
|
164
|
+
|
|
165
|
+
**Intent:** use the sanctioned post-launch controls without violating the autonomous model.
|
|
166
|
+
|
|
167
|
+
**Preconditions**
|
|
168
|
+
- the Revnet is live
|
|
169
|
+
- the operator knows exactly which controls the deployment left available
|
|
88
170
|
|
|
89
|
-
**
|
|
171
|
+
**Main Flow**
|
|
172
|
+
1. Review what `REVDeployer` allowed.
|
|
173
|
+
2. Use only those sanctioned surfaces.
|
|
174
|
+
3. Audit cross-package behavior whenever optional integrations are enabled.
|
|
90
175
|
|
|
91
|
-
**
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
176
|
+
**Failure Modes**
|
|
177
|
+
- operators behave as though the Revnet were a normal owner-governed project
|
|
178
|
+
- reviewers inspect controls in isolation and miss integrated runtime behavior
|
|
179
|
+
|
|
180
|
+
**Postconditions**
|
|
181
|
+
- post-launch control remains inside the bounded envelope the deployment left available
|
|
95
182
|
|
|
96
183
|
## Journey 7: Receive Cross-Chain Payments With Correct Hook Routing
|
|
97
184
|
|
|
98
|
-
**
|
|
185
|
+
**Actor:** remote participant or integrator using suckers.
|
|
186
|
+
|
|
187
|
+
**Intent:** preserve the real beneficiary during cross-chain payments into a Revnet.
|
|
99
188
|
|
|
100
|
-
**
|
|
189
|
+
**Preconditions**
|
|
190
|
+
- the Revnet is configured with suckers and optional hooks that depend on the beneficiary
|
|
191
|
+
- relay-beneficiary metadata is provided correctly
|
|
101
192
|
|
|
102
|
-
**Flow**
|
|
193
|
+
**Main Flow**
|
|
103
194
|
1. The sucker calls `terminal.pay()` with relay-beneficiary metadata.
|
|
104
|
-
2. `REVOwner.beforePayRecordedWith()` resolves the
|
|
105
|
-
3.
|
|
195
|
+
2. `REVOwner.beforePayRecordedWith()` resolves the real beneficiary when the payer is a registered sucker.
|
|
196
|
+
3. Downstream hooks observe the remote user rather than the sucker contract.
|
|
197
|
+
|
|
198
|
+
**Failure Modes**
|
|
199
|
+
- relay metadata is absent or malformed
|
|
200
|
+
- downstream hooks accidentally attribute minting or routing to the sucker instead of the user
|
|
201
|
+
|
|
202
|
+
**Postconditions**
|
|
203
|
+
- cross-chain payments preserve the intended remote beneficiary through the Revnet hook stack
|
|
204
|
+
|
|
205
|
+
## Trust Boundaries
|
|
206
|
+
|
|
207
|
+
- `REVDeployer` is trusted for the launch-time envelope the Revnet will live inside
|
|
208
|
+
- `REVOwner` is economically binding runtime logic, not advisory middleware
|
|
209
|
+
- optional integrations such as 721 hooks, buybacks, router terminals, and suckers materially alter the resulting network
|
|
106
210
|
|
|
107
211
|
## Hand-Offs
|
|
108
212
|
|
package/foundry.toml
CHANGED
package/package.json
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
2
|
+
"name": "@rev-net/core-v6",
|
|
3
|
+
"version": "0.0.33",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/rev-net/revnet-core-v6"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=20.0.0"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "forge test",
|
|
14
|
+
"coverage": "forge coverage --match-path \"./src/*.sol\" --report lcov --report summary",
|
|
15
|
+
"deploy:mainnets": "source ./.env && export START_TIME=$(date +%s) && npx sphinx propose ./script/Deploy.s.sol --networks mainnets",
|
|
16
|
+
"deploy:mainnets:1_1": "source ./.env && npx sphinx propose ./script/Deploy1_1.s.sol --networks mainnets",
|
|
17
|
+
"deploy:testnets": "source ./.env && export START_TIME=$(date +%s) && npx sphinx propose ./script/Deploy.s.sol --networks testnets",
|
|
18
|
+
"deploy:testnets:1_1": "source ./.env && npx sphinx propose ./script/Deploy1_1.s.sol --networks testnets",
|
|
19
|
+
"artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'revnet-core-v6'"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@bananapus/721-hook-v6": "^0.0.35",
|
|
23
|
+
"@bananapus/buyback-hook-v6": "^0.0.27",
|
|
24
|
+
"@bananapus/core-v6": "^0.0.34",
|
|
25
|
+
"@bananapus/ownable-v6": "^0.0.17",
|
|
26
|
+
"@bananapus/permission-ids-v6": "^0.0.17",
|
|
27
|
+
"@bananapus/router-terminal-v6": "^0.0.26",
|
|
28
|
+
"@bananapus/suckers-v6": "^0.0.25",
|
|
29
|
+
"@croptop/core-v6": "github:mejango/croptop-core-v6",
|
|
30
|
+
"@openzeppelin/contracts": "^5.6.1",
|
|
31
|
+
"@uniswap/v4-core": "^1.0.2",
|
|
32
|
+
"@uniswap/v4-periphery": "^1.0.3"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@bananapus/address-registry-v6": "^0.0.17",
|
|
36
|
+
"@sphinx-labs/plugins": "^0.33.2"
|
|
37
|
+
}
|
|
38
38
|
}
|
package/references/operations.md
CHANGED
|
@@ -143,6 +143,7 @@ Use this file when you need revnet-specific risks, state reads, constants, or ex
|
|
|
143
143
|
19. **39.16% cash-out tax crossover.** Below ~39% cash-out tax, cashing out is more capital-efficient than borrowing. Above ~39%, loans become more efficient because they preserve upside while providing liquidity. Based on CryptoEconLab academic research. Design implication: revnets intended for active token trading should consider this threshold when setting `cashOutTaxRate`.
|
|
144
144
|
20. **REVDeployer always deploys a 721 hook** via `HOOK_DEPLOYER.deployHookFor` — even if `baseline721HookConfiguration` has empty tiers. This is correct by design: it lets the split operator add and sell NFTs later without migration. Non-revnet projects should follow the same pattern by using `JB721TiersHookProjectDeployer.launchProjectFor` (or `JBOmnichainDeployer.launchProjectFor`) instead of bare `launchProjectFor`.
|
|
145
145
|
21. **REVOwner deployer binding is precomputed.** REVOwner records the account that created it as an internal one-time binder. That account must call `setDeployer(precomputedRevDeployerAddress)` exactly once before the canonical REVDeployer is deployed. This avoids an ambient public initializer while keeping the circular dependency manageable. If `setDeployer(...)` is never called, all DEPLOYER-gated runtime configuration breaks.
|
|
146
|
+
22. **Hidden tokens are economic, not cosmetic.** Hiding burns visible tokens and lowers visible supply until reveal. That changes cash-out and loan-relative economics for everyone else.
|
|
146
147
|
|
|
147
148
|
### NATIVE_TOKEN Accounting on Non-ETH Chains
|
|
148
149
|
|
|
@@ -198,6 +199,12 @@ Quick-reference for common read operations. All functions are `view`/`pure` and
|
|
|
198
199
|
|------|------|---------|
|
|
199
200
|
| Remaining auto-issuance for beneficiary | `REVDeployer.amountToAutoIssue(revnetId, stageId, beneficiary)` | `uint256` (0 if already claimed) |
|
|
200
201
|
|
|
202
|
+
### Hidden Tokens
|
|
203
|
+
|
|
204
|
+
| What | Call | Returns |
|
|
205
|
+
|------|------|---------|
|
|
206
|
+
| Hidden balance for holder | `REVHiddenTokens.hiddenBalanceOf(holder, revnetId)` | `uint256` |
|
|
207
|
+
|
|
201
208
|
### Loans
|
|
202
209
|
|
|
203
210
|
| What | Call | Returns |
|
package/references/runtime.md
CHANGED
|
@@ -13,6 +13,7 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
13
13
|
| `REVDeployer` | Deploys revnets, permanently owns the project NFT. Manages stages, splits, auto-issuance, buyback hooks, suckers, split operators, and configuration state storage. Exposes `OWNER()` view returning the REVOwner address. Calls DEPLOYER-restricted setters on REVOwner during deployment to store `cashOutDelayOf` and `tiered721HookOf`. |
|
|
14
14
|
| `REVOwner` | Runtime hook contract for all revnets. Implements `IJBRulesetDataHook` + `IJBCashOutHook`. Set as the `dataHook` in each revnet's ruleset metadata. Handles pay hooks, cash-out hooks, mint permissions, and sucker verification. Stores `cashOutDelayOf` and `tiered721HookOf` mappings (set by REVDeployer via DEPLOYER-restricted setters `setCashOutDelayOf()` and `setTiered721HookOf()`). |
|
|
15
15
|
| `REVLoans` | Issues token-collateralized loans from revnet treasuries. Each loan is an ERC-721 NFT. Burns collateral on borrow, re-mints on repay. Charges tiered fees (REV protocol fee + source fee + prepaid fee). |
|
|
16
|
+
| `REVHiddenTokens` | Burns tokens into a hidden balance and can later re-mint them. This is a supply-management primitive, not just a wallet convenience feature. |
|
|
16
17
|
|
|
17
18
|
## Key Functions
|
|
18
19
|
|
|
@@ -66,6 +67,7 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
66
67
|
| `REVLoans.loanOf(loanId)` | Returns the full `REVLoan` struct for a loan. |
|
|
67
68
|
| `REVLoans.loanSourcesOf(revnetId)` | Returns all `(terminal, token)` pairs used for loans by a revnet. |
|
|
68
69
|
| `REVLoans.revnetIdOfLoanWith(loanId)` | Decode the revnet ID from a loan ID (`loanId / 1_000_000_000_000`). |
|
|
70
|
+
| `REVHiddenTokens.hiddenBalanceOf(holder, revnetId)` | Returns how many tokens a holder has hidden from visible supply. |
|
|
69
71
|
|
|
70
72
|
## Integration Points
|
|
71
73
|
|
|
@@ -96,3 +98,9 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
96
98
|
| `REV721TiersHookFlags` | `noNewTiersWithReserves`, `noNewTiersWithVotes`, `noNewTiersWithOwnerMinting`, `preventOverspending` | Same as `JB721TiersHookFlags` minus `issueTokensForSplits`. Revnets do their own weight adjustment for splits. |
|
|
97
99
|
| `REVCroptopAllowedPost` | `category` (uint24), `minimumPrice` (uint104), `minimumTotalSupply` (uint32), `maximumTotalSupply` (uint32), `allowedAddresses[]` | Croptop posting criteria |
|
|
98
100
|
| `REVSuckerDeploymentConfig` | `deployerConfigurations[]`, `salt` | Cross-chain sucker deployment |
|
|
101
|
+
### Hidden Tokens
|
|
102
|
+
|
|
103
|
+
| Function | Permissions | What it does |
|
|
104
|
+
|----------|------------|-------------|
|
|
105
|
+
| `REVHiddenTokens.hideTokensOf(holder, revnetId, tokenCount)` | Holder or delegated permission | Burns visible tokens, increases hidden balance, and lowers visible supply. |
|
|
106
|
+
| `REVHiddenTokens.revealTokensOf(holder, revnetId, tokenCount, beneficiary)` | Holder or delegated permission | Re-mints previously hidden tokens to a beneficiary and reduces hidden balance. |
|
|
@@ -6,7 +6,6 @@ pragma solidity ^0.8.0;
|
|
|
6
6
|
/// @custom:member noNewTiersWithOwnerMinting A flag indicating if new tiers with owner minting are forbidden.
|
|
7
7
|
/// @custom:member preventOverspending A flag indicating if payments exceeding the price of minted NFTs should be
|
|
8
8
|
/// prevented.
|
|
9
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
10
9
|
struct REV721TiersHookFlags {
|
|
11
10
|
bool noNewTiersWithReserves;
|
|
12
11
|
bool noNewTiersWithVotes;
|
|
@@ -4,7 +4,6 @@ pragma solidity ^0.8.0;
|
|
|
4
4
|
/// @custom:member chainId The ID of the chain on which the mint should be honored.
|
|
5
5
|
/// @custom:member count The number of tokens that should be minted.
|
|
6
6
|
/// @custom:member beneficiary The address that will receive the minted tokens.
|
|
7
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
8
7
|
struct REVAutoIssuance {
|
|
9
8
|
uint32 chainId;
|
|
10
9
|
uint104 count;
|
|
@@ -14,7 +14,6 @@ import {REV721TiersHookFlags} from "./REV721TiersHookFlags.sol";
|
|
|
14
14
|
/// @custom:member tiersConfig The tier configuration for the NFT collection.
|
|
15
15
|
/// @custom:member flags A set of flags that configure the 721 hook. Omits `issueTokensForSplits` since revnets
|
|
16
16
|
/// always force it to `false`.
|
|
17
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
18
17
|
struct REVBaseline721HookConfig {
|
|
19
18
|
string name;
|
|
20
19
|
string symbol;
|
|
@@ -9,7 +9,6 @@ import {REVStageConfig} from "./REVStageConfig.sol";
|
|
|
9
9
|
/// @custom:member splitOperator The address that will receive the token premint and initial production split,
|
|
10
10
|
/// and who is allowed to change who the operator is. Only the operator can replace itself after deployment.
|
|
11
11
|
/// @custom:member stageConfigurations The periods of changing constraints.
|
|
12
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
13
12
|
struct REVConfig {
|
|
14
13
|
REVDescription description;
|
|
15
14
|
uint32 baseCurrency;
|
|
@@ -10,7 +10,6 @@ pragma solidity ^0.8.0;
|
|
|
10
10
|
/// @custom:member maximumSplitPercent The maximum split percent (out of JBConstants.SPLITS_TOTAL_PERCENT) that a
|
|
11
11
|
/// poster can set. 0 means splits are not allowed.
|
|
12
12
|
/// @custom:member allowedAddresses A list of addresses that are allowed to post on the category through Croptop.
|
|
13
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
14
13
|
struct REVCroptopAllowedPost {
|
|
15
14
|
uint24 category;
|
|
16
15
|
uint104 minimumPrice;
|
|
@@ -13,7 +13,6 @@ import {REVBaseline721HookConfig} from "./REVBaseline721HookConfig.sol";
|
|
|
13
13
|
/// minting 721's from tiers that allow it.
|
|
14
14
|
/// @custom:member preventSplitOperatorIncreasingDiscountPercent A flag indicating if the revnet's split operator should
|
|
15
15
|
/// be prevented from increasing the discount of a tier.
|
|
16
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
17
16
|
struct REVDeploy721TiersHookConfig {
|
|
18
17
|
REVBaseline721HookConfig baseline721HookConfiguration;
|
|
19
18
|
bytes32 salt;
|
|
@@ -6,7 +6,6 @@ pragma solidity ^0.8.0;
|
|
|
6
6
|
/// @custom:member uri The metadata URI containing revnet's info.
|
|
7
7
|
/// @custom:member salt Revnets deployed across chains by the same address with the same salt will have the same
|
|
8
8
|
/// address.
|
|
9
|
-
// forge-lint: disable-next-line(pascal-case-struct)
|
|
10
9
|
struct REVDescription {
|
|
11
10
|
string name;
|
|
12
11
|
string ticker;
|