@rev-net/core-v6 0.0.19 → 0.0.21
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 +2 -2
- package/ARCHITECTURE.md +1 -1
- package/AUDIT_INSTRUCTIONS.md +7 -7
- package/CHANGE_LOG.md +3 -4
- package/README.md +2 -2
- package/RISKS.md +1 -1
- package/SKILLS.md +2 -2
- package/package.json +1 -1
- package/script/Deploy.s.sol +0 -5
- package/script/helpers/RevnetCoreDeploymentLib.sol +8 -0
- package/src/REVDeployer.sol +3 -0
- package/src/REVOwner.sol +5 -6
- package/test/REV.integrations.t.sol +0 -2
- package/test/REVAutoIssuanceFuzz.t.sol +0 -2
- package/test/REVDeployerRegressions.t.sol +0 -2
- package/test/REVInvincibility.t.sol +0 -4
- package/test/REVLifecycle.t.sol +0 -2
- package/test/REVLoans.invariants.t.sol +0 -2
- package/test/REVLoansAttacks.t.sol +0 -2
- package/test/REVLoansFeeRecovery.t.sol +0 -2
- package/test/REVLoansFindings.t.sol +0 -2
- package/test/REVLoansRegressions.t.sol +0 -2
- package/test/REVLoansSourceFeeRecovery.t.sol +0 -2
- package/test/REVLoansSourced.t.sol +0 -2
- package/test/REVLoansUnSourced.t.sol +0 -2
- package/test/TestBurnHeldTokens.t.sol +0 -2
- package/test/TestCEIPattern.t.sol +0 -1
- package/test/TestCashOutCallerValidation.t.sol +0 -2
- package/test/TestConversionDocumentation.t.sol +0 -2
- package/test/TestCrossCurrencyReclaim.t.sol +0 -2
- package/test/TestCrossSourceReallocation.t.sol +0 -1
- package/test/TestERC2771MetaTx.t.sol +0 -2
- package/test/TestEmptyBuybackSpecs.t.sol +0 -1
- package/test/TestFlashLoanSurplus.t.sol +0 -1
- package/test/TestHookArrayOOB.t.sol +0 -1
- package/test/TestLiquidationBehavior.t.sol +0 -1
- package/test/TestLoanSourceRotation.t.sol +0 -2
- package/test/TestLoansCashOutDelay.t.sol +0 -2
- package/test/TestLongTailEconomics.t.sol +0 -2
- package/test/TestLowFindings.t.sol +0 -2
- package/test/TestMixedFixes.t.sol +0 -1
- package/test/TestPermit2Signatures.t.sol +0 -2
- package/test/TestReallocationSandwich.t.sol +0 -1
- package/test/TestRevnetRegressions.t.sol +0 -2
- package/test/TestSplitWeightAdjustment.t.sol +0 -2
- package/test/TestSplitWeightE2E.t.sol +0 -3
- package/test/TestSplitWeightFork.t.sol +0 -2
- package/test/TestStageTransitionBorrowable.t.sol +0 -1
- package/test/TestSwapTerminalPermission.t.sol +0 -1
- package/test/TestUint112Overflow.t.sol +0 -2
- package/test/TestZeroRepayment.t.sol +0 -1
- package/test/audit/LoanIdOverflowGuard.t.sol +0 -2
- package/test/fork/ForkTestBase.sol +0 -2
- package/test/regression/TestBurnPermissionRequired.t.sol +0 -1
- package/test/regression/TestCashOutBuybackFeeLeak.t.sol +0 -2
- package/test/regression/TestCrossRevnetLiquidation.t.sol +0 -1
- package/test/regression/TestCumulativeLoanCounter.t.sol +0 -1
- package/test/regression/TestLiquidateGapHandling.t.sol +0 -1
- package/test/regression/TestZeroPriceFeed.t.sol +0 -2
package/ADMINISTRATION.md
CHANGED
|
@@ -140,14 +140,14 @@ The following parameters are set at deployment and can never be changed:
|
|
|
140
140
|
- `DEFAULT_BUYBACK_TWAP_WINDOW` -- 2 days
|
|
141
141
|
- `OWNER()` -- view returning the REVOwner address
|
|
142
142
|
|
|
143
|
-
### REVOwner (global, set at contract deployment
|
|
143
|
+
### REVOwner (global, set at contract deployment)
|
|
144
144
|
- `BUYBACK_HOOK` -- the buyback hook (shared immutable with REVDeployer)
|
|
145
145
|
- `DIRECTORY` -- the Juicebox directory (shared immutable with REVDeployer)
|
|
146
146
|
- `FEE_REVNET_ID` -- the project ID that receives cash-out fees (shared immutable)
|
|
147
147
|
- `SUCKER_REGISTRY` -- the sucker registry (shared immutable)
|
|
148
148
|
- `LOANS` -- the loans contract address (shared immutable)
|
|
149
149
|
- `FEE` -- the cash-out fee constant (2.5%)
|
|
150
|
-
- `DEPLOYER` -- the REVDeployer address (storage variable, set once via `
|
|
150
|
+
- `DEPLOYER` -- the REVDeployer address (storage variable, set once via `setDeployer()` called from REVDeployer's constructor)
|
|
151
151
|
|
|
152
152
|
### REVLoans (global, set at contract deployment)
|
|
153
153
|
- `CONTROLLER`, `DIRECTORY`, `PRICES`, `PROJECTS` -- protocol infrastructure
|
package/ARCHITECTURE.md
CHANGED
|
@@ -143,7 +143,7 @@ Fields set automatically by the deployer (not configurable per stage):
|
|
|
143
143
|
## Key Design Decisions
|
|
144
144
|
- Stages are immutable after deployment — no owner can change ruleset parameters
|
|
145
145
|
- Matching hash ensures cross-chain deployments have identical economic parameters. It covers all economic fields (issuance, decay, tax rates, auto-issuances) but intentionally excludes split recipient addresses, which may differ by chain. The hash is used as a CREATE2 salt component for sucker deployment, so mismatched configs produce different sucker addresses that cannot peer with each other.
|
|
146
|
-
- REVOwner is the data hook for all revnets — centralizes runtime behavioral control (pay hooks, cash-out hooks, mint permissions) and stores `cashOutDelayOf` and `tiered721HookOf` per revnet. REVDeployer handles deployment and configuration state storage. The split was necessary to stay under the EIP-170 contract size limit (24,576 bytes). Deploy order: REVOwner first, then REVDeployer(owner=REVOwner)
|
|
146
|
+
- REVOwner is the data hook for all revnets — centralizes runtime behavioral control (pay hooks, cash-out hooks, mint permissions) and stores `cashOutDelayOf` and `tiered721HookOf` per revnet. REVDeployer handles deployment and configuration state storage. The split was necessary to stay under the EIP-170 contract size limit (24,576 bytes). Deploy order: REVOwner first, then REVDeployer(owner=REVOwner) -- the constructor calls `REVOwner.setDeployer()` atomically. REVDeployer calls DEPLOYER-restricted setters on REVOwner (`setCashOutDelayOf`, `setTiered721HookOf`) during deployment.
|
|
147
147
|
- Loans use bonding curve value, not market price — independent of external DEX pricing
|
|
148
148
|
- Auto-issuance is deferred, not instant — token amounts are recorded at deploy time but minted via a separate `autoIssueFor` call after the stage starts. This separates deployment from issuance, allows anyone to trigger the mint permissionlessly, and ensures tokens are not minted before their stage is active.
|
|
149
149
|
- No approval hook — revnet rulesets set `approvalHook` to `address(0)` because stages are configured immutably at deployment. There is no governance or owner who could queue a change that would need approval.
|
package/AUDIT_INSTRUCTIONS.md
CHANGED
|
@@ -11,7 +11,7 @@ Read [RISKS.md](./RISKS.md) for the trust model and known risks. Read [ARCHITECT
|
|
|
11
11
|
| Contract | Lines | Role |
|
|
12
12
|
|----------|-------|------|
|
|
13
13
|
| `src/REVDeployer.sol` | ~19,746 bytes | Deploys revnets. Manages stages, splits, auto-issuance, buyback hook delegation, 721 hook deployment, suckers, split operator permissions, and all state storage. Split from original monolith to stay under EIP-170 (24,576 bytes). |
|
|
14
|
-
| `src/REVOwner.sol` | ~8,
|
|
14
|
+
| `src/REVOwner.sol` | ~8,434 bytes (~310 lines) | Runtime hook contract. Implements `IJBRulesetDataHook` + `IJBCashOutHook`. Set as the `dataHook` in each revnet's ruleset metadata. Handles `beforePayRecordedWith`, `beforeCashOutRecordedWith`, `afterCashOutRecordedWith`, `hasMintPermissionFor`, and sucker verification. Stores `cashOutDelayOf` and `tiered721HookOf` mappings (set by REVDeployer via DEPLOYER-restricted setters). **Key audit focus: the `setDeployer()` one-shot pattern, DEPLOYER-restricted setter access control, and circular dependency with REVDeployer.** |
|
|
15
15
|
| `src/REVLoans.sol` | ~1,359 lines | Token-collateralized lending. Burns collateral on borrow, re-mints on repay. ERC-721 loan NFTs. Three-layer fee model. Permit2 integration. |
|
|
16
16
|
| `src/interfaces/` | ~525 | Interface definitions for both contracts |
|
|
17
17
|
| `src/structs/` | ~212 | All struct definitions |
|
|
@@ -128,7 +128,7 @@ Borrower calls REVLoans.borrowFrom()
|
|
|
128
128
|
|
|
129
129
|
| Variable | Purpose | Audit Focus |
|
|
130
130
|
|----------|---------|-------------|
|
|
131
|
-
| `DEPLOYER` | REVDeployer address | Set once via `
|
|
131
|
+
| `DEPLOYER` | REVDeployer address | Set once via `setDeployer()` called from REVDeployer's constructor. **Not immutable** -- stored as a regular storage variable to break circular dependency. `setDeployer()` sets `msg.sender` as `DEPLOYER` and reverts if already set (`REVOwner_AlreadyInitialized`). Used to restrict access to `setCashOutDelayOf()` and `setTiered721HookOf()`. |
|
|
132
132
|
| `cashOutDelayOf[revnetId]` | Timestamp when cash-outs unlock | Set by REVDeployer via `setCashOutDelayOf()` (DEPLOYER-restricted). Applied only for existing revnets deployed to new chains. **Read by REVLoans via IREVOwner.** Verify only DEPLOYER can call the setter. |
|
|
133
133
|
| `tiered721HookOf[revnetId]` | 721 hook address | Set by REVDeployer via `setTiered721HookOf()` (DEPLOYER-restricted). Set once during deploy, never changed. **Read by REVOwner internally during pay hooks.** Verify only DEPLOYER can call the setter. |
|
|
134
134
|
|
|
@@ -274,12 +274,12 @@ Verify:
|
|
|
274
274
|
|
|
275
275
|
### 8. REVOwner initialization and circular dependency
|
|
276
276
|
|
|
277
|
-
REVOwner and REVDeployer have a circular dependency broken by
|
|
277
|
+
REVOwner and REVDeployer have a circular dependency broken by `setDeployer()`, called atomically from REVDeployer's constructor. Deploy order: REVOwner first, then REVDeployer(owner=REVOwner) -- the constructor calls `REVOwner.setDeployer()` atomically. Verify:
|
|
278
278
|
|
|
279
|
-
- `
|
|
279
|
+
- `setDeployer()` sets `msg.sender` as `DEPLOYER` and reverts if already set (`REVOwner_AlreadyInitialized`)
|
|
280
280
|
- `DEPLOYER` is a storage variable, not immutable, to break the circular dependency
|
|
281
|
-
- Before `
|
|
282
|
-
-
|
|
281
|
+
- Before `setDeployer()` is called, the DEPLOYER-restricted setters (`setCashOutDelayOf`, `setTiered721HookOf`) would reject calls, leaving `cashOutDelayOf` and `tiered721HookOf` unpopulated
|
|
282
|
+
- After `setDeployer()` has been called once, no subsequent call can change the `DEPLOYER` address
|
|
283
283
|
- Only DEPLOYER can call `setCashOutDelayOf()` and `setTiered721HookOf()` -- verify access control on these setters
|
|
284
284
|
- `cashOutDelayOf` and `tiered721HookOf` are stored on REVOwner (not REVDeployer) -- verify REVOwner reads from its own storage and the setters cannot be called by unauthorized addresses
|
|
285
285
|
- Both contracts define `FEE = 25` independently -- verify they stay in sync
|
|
@@ -293,7 +293,7 @@ Fuzzable properties that should hold for all valid inputs:
|
|
|
293
293
|
3. **Loan NFT ownership**: The ERC-721 owner of a loan NFT is the only address authorized to repay, reallocate, or manage that loan (absent ROOT or explicit permission grants).
|
|
294
294
|
4. **No flash-loan profit**: Borrowing and repaying in the same block (zero time elapsed) should never yield a net profit to the borrower after all fees.
|
|
295
295
|
5. **Stage monotonicity**: Stage transitions are monotonically increasing in time -- a later stage's `startsAtOrAfter` is always strictly greater than the previous stage's.
|
|
296
|
-
6. **REVOwner initialization**: `DEPLOYER` is set exactly once via `
|
|
296
|
+
6. **REVOwner initialization**: `DEPLOYER` is set exactly once via `setDeployer()` (called from REVDeployer's constructor) and matches the REVDeployer that references this REVOwner via `OWNER()`. Only the initialized `DEPLOYER` can call `setCashOutDelayOf()` and `setTiered721HookOf()`.
|
|
297
297
|
|
|
298
298
|
## How to Run Tests
|
|
299
299
|
|
package/CHANGE_LOG.md
CHANGED
|
@@ -11,7 +11,7 @@ REVDeployer exceeded the EIP-170 contract size limit (24,576 bytes) at 26,397 by
|
|
|
11
11
|
| Contract | Size | Role |
|
|
12
12
|
|----------|------|------|
|
|
13
13
|
| `REVDeployer` | 19,746 bytes | Deployment, configuration, state storage, split operator management |
|
|
14
|
-
| `REVOwner` | 8,
|
|
14
|
+
| `REVOwner` | 8,434 bytes (~310 lines) | Runtime hook behavior: `IJBRulesetDataHook` + `IJBCashOutHook` |
|
|
15
15
|
|
|
16
16
|
### What moved to REVOwner
|
|
17
17
|
|
|
@@ -51,10 +51,9 @@ The `cashOutDelayOf` and `tiered721HookOf` storage mappings were moved from REVD
|
|
|
51
51
|
REVDeployer needs REVOwner (as the `dataHook` address and to set `cashOutDelayOf`/`tiered721HookOf` via restricted setters), and REVOwner references REVDeployer (to restrict setter access). This circular dependency is broken by:
|
|
52
52
|
|
|
53
53
|
1. Deploy REVOwner first
|
|
54
|
-
2. Deploy REVDeployer with `owner=REVOwner`
|
|
55
|
-
3. Call `REVOwner.initialize(deployer)` to set the `DEPLOYER` storage variable
|
|
54
|
+
2. Deploy REVDeployer with `owner=REVOwner` -- the constructor calls `REVOwner.setDeployer()` atomically
|
|
56
55
|
|
|
57
|
-
`REVOwner.DEPLOYER` is a **storage variable** (not immutable) because the deployer address is not known at REVOwner construction time.
|
|
56
|
+
`REVOwner.DEPLOYER` is a **storage variable** (not immutable) because the deployer address is not known at REVOwner construction time. `setDeployer()` sets `msg.sender` as `DEPLOYER` and reverts if already set (`REVOwner_AlreadyInitialized`). After initialization, `DEPLOYER` is used to restrict access to `setCashOutDelayOf()` and `setTiered721HookOf()`.
|
|
58
57
|
|
|
59
58
|
### Shared immutables
|
|
60
59
|
|
package/README.md
CHANGED
|
@@ -96,7 +96,7 @@ Every revnet gets a tiered ERC-721 hook deployed automatically — even if no ti
|
|
|
96
96
|
|
|
97
97
|
### How They Relate
|
|
98
98
|
|
|
99
|
-
`REVDeployer` owns every revnet's Juicebox project NFT and holds all administrative permissions. `REVOwner` is set as the `dataHook` for every revnet's rulesets, handling all runtime hook behavior (pay hooks, cash-out hooks, mint permissions) and storing `cashOutDelayOf` and `tiered721HookOf` per revnet (set by REVDeployer via DEPLOYER-restricted setters during deployment). Deploy order: REVOwner
|
|
99
|
+
`REVDeployer` owns every revnet's Juicebox project NFT and holds all administrative permissions. `REVOwner` is set as the `dataHook` for every revnet's rulesets, handling all runtime hook behavior (pay hooks, cash-out hooks, mint permissions) and storing `cashOutDelayOf` and `tiered721HookOf` per revnet (set by REVDeployer via DEPLOYER-restricted setters during deployment). Deploy order: REVOwner first, then REVDeployer(owner=REVOwner) -- the constructor calls `REVOwner.setDeployer()` atomically. Both contracts share immutables: `BUYBACK_HOOK`, `DIRECTORY`, `FEE_REVNET_ID`, `SUCKER_REGISTRY`, `LOANS`. During deployment, REVDeployer grants `REVLoans` the `USE_ALLOWANCE` permission so loans can pull funds from the revnet's terminal. `REVLoans` imports `IREVOwner` (not `IREVDeployer`) for `cashOutDelayOf` calls and verifies that a revnet was deployed by its expected `REVDeployer` before issuing any loan.
|
|
100
100
|
|
|
101
101
|
### Interfaces
|
|
102
102
|
|
|
@@ -209,7 +209,7 @@ Plus optional from 721 hook config: `ADJUST_721_TIERS`, `SET_721_METADATA`, `MIN
|
|
|
209
209
|
## Risks
|
|
210
210
|
|
|
211
211
|
- **No human owner.** `REVDeployer` permanently holds the project NFT. There is no function to release it. This is by design -- revnets are ownerless. But it means bugs in stage configurations cannot be fixed after deployment.
|
|
212
|
-
- **REVOwner circular dependency.** REVOwner and REVDeployer have a circular dependency broken by
|
|
212
|
+
- **REVOwner circular dependency.** REVOwner and REVDeployer have a circular dependency broken by `setDeployer()`, called atomically from REVDeployer's constructor. `REVOwner.DEPLOYER` is a storage variable (not immutable). `setDeployer()` sets `msg.sender` as `DEPLOYER` and reverts if already set. If `setDeployer()` is never called, the DEPLOYER-restricted setters (`setCashOutDelayOf`, `setTiered721HookOf`) cannot be called correctly, and all runtime hook behavior breaks.
|
|
213
213
|
- **Loan flash-loan exposure.** `borrowableAmountFrom` reads live surplus, which can be inflated via flash loans. A borrower could temporarily inflate the treasury to borrow more than the sustained value would support.
|
|
214
214
|
- **uint112 truncation.** `REVLoan.amount` and `REVLoan.collateral` are `uint112` -- values above ~5.19e33 truncate silently.
|
|
215
215
|
- **Cash-out fee stacking.** Cash outs incur both the Juicebox terminal fee (2.5%) and the revnet cash-out fee (2.5% to fee revnet). These compound.
|
package/RISKS.md
CHANGED
|
@@ -11,7 +11,7 @@ Read [ARCHITECTURE.md](./ARCHITECTURE.md) and [SKILLS.md](./SKILLS.md) for proto
|
|
|
11
11
|
### What the system assumes to be correct
|
|
12
12
|
|
|
13
13
|
- **REVOwner is a singleton data hook.** Every revnet shares one `beforePayRecordedWith` and `beforeCashOutRecordedWith` implementation in REVOwner. A bug in either function affects ALL revnets deployed by that deployer simultaneously. There is no per-project isolation and no circuit breaker.
|
|
14
|
-
- **REVOwner circular dependency.** REVOwner and REVDeployer have a circular dependency broken by
|
|
14
|
+
- **REVOwner circular dependency.** REVOwner and REVDeployer have a circular dependency broken by `setDeployer()`, called atomically from REVDeployer's constructor. `REVOwner.DEPLOYER` is a storage variable (not immutable). `setDeployer()` sets `msg.sender` as `DEPLOYER` and reverts if already set. If `setDeployer()` is never called, REVDeployer cannot call the DEPLOYER-restricted setters (`setCashOutDelayOf`, `setTiered721HookOf`) on REVOwner, and `cashOutDelayOf`/`tiered721HookOf` will never be populated, breaking all runtime hook behavior. Because the call is made atomically from REVDeployer's constructor, the correct deployer address is guaranteed to be set during deployment.
|
|
15
15
|
- **Stage immutability is the trust model.** Once `deployFor()` completes, stage parameters (issuance, `cashOutTaxRate`, splits, auto-issuances) are locked forever. No owner, no governance, no upgrade path. A misconfigured deployment is permanent. This is intentional -- the absence of admin keys IS the security property.
|
|
16
16
|
- **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.
|
|
17
17
|
- **Juicebox core contracts are correct.** `JBController`, `JBMultiTerminal`, `JBTerminalStore`, `JBTokens`, `JBPrices` -- a bug in any of these is a bug in every revnet.
|
package/SKILLS.md
CHANGED
|
@@ -197,7 +197,7 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
197
197
|
|
|
198
198
|
| Mapping | Visibility | Type | Purpose |
|
|
199
199
|
|---------|-----------|------|---------|
|
|
200
|
-
| `DEPLOYER` | `public` | `address` | REVDeployer address (storage variable, set once via `
|
|
200
|
+
| `DEPLOYER` | `public` | `address` | REVDeployer address (storage variable, set once via `setDeployer()` called from REVDeployer's constructor) |
|
|
201
201
|
| `cashOutDelayOf` | `public` | `revnetId => uint256` | Timestamp when cash outs unlock (0 = no delay). Set by REVDeployer via `setCashOutDelayOf()`. |
|
|
202
202
|
| `tiered721HookOf` | `public` | `revnetId => address` | Deployed 721 hook address (if any). Set by REVDeployer via `setTiered721HookOf()`. |
|
|
203
203
|
|
|
@@ -235,7 +235,7 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
235
235
|
18. **Permit2 fallback.** `REVLoans` uses permit2 for ERC-20 transfers as a fallback when standard allowance is insufficient. Wrapped in try-catch.
|
|
236
236
|
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`.
|
|
237
237
|
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`.
|
|
238
|
-
21. **REVOwner circular dependency.** REVOwner and REVDeployer have a circular dependency broken by
|
|
238
|
+
21. **REVOwner circular dependency.** REVOwner and REVDeployer have a circular dependency broken by `setDeployer()`, called atomically from REVDeployer's constructor. `REVOwner.DEPLOYER` is a storage variable (not immutable). `setDeployer()` sets `msg.sender` as `DEPLOYER` if not already set -- reverts if already set. If `setDeployer()` is never called, all runtime hook behavior breaks. Deploy order: REVOwner first, then REVDeployer(owner=REVOwner) -- the constructor calls `REVOwner.setDeployer()` atomically. REVOwner stores `cashOutDelayOf` and `tiered721HookOf` mappings, which are set by REVDeployer via DEPLOYER-restricted setters (`setCashOutDelayOf()`, `setTiered721HookOf()`).
|
|
239
239
|
|
|
240
240
|
### NATIVE_TOKEN Accounting on Non-ETH Chains
|
|
241
241
|
|
package/package.json
CHANGED
package/script/Deploy.s.sol
CHANGED
|
@@ -491,11 +491,6 @@ contract DeployScript is Script, Sphinx {
|
|
|
491
491
|
owner: address(revOwner)
|
|
492
492
|
});
|
|
493
493
|
|
|
494
|
-
// Link the REVOwner to the REVDeployer (can only be called once).
|
|
495
|
-
if (!_deployerIsDeployed) {
|
|
496
|
-
revOwner.initialize(IREVDeployer(address(_basicDeployer)));
|
|
497
|
-
}
|
|
498
|
-
|
|
499
494
|
// Only configure the fee project if singletons were freshly deployed. Re-running `deployFor` on an
|
|
500
495
|
// already-configured project would fail because the project is no longer blank.
|
|
501
496
|
if (!_singletonsExist) {
|
|
@@ -7,11 +7,13 @@ import {SphinxConstants, NetworkInfo} from "@sphinx-labs/contracts/contracts/fou
|
|
|
7
7
|
|
|
8
8
|
import {IREVDeployer} from "./../../src/interfaces/IREVDeployer.sol";
|
|
9
9
|
import {IREVLoans} from "./../../src/interfaces/IREVLoans.sol";
|
|
10
|
+
import {REVOwner} from "./../../src/REVOwner.sol";
|
|
10
11
|
|
|
11
12
|
struct RevnetCoreDeployment {
|
|
12
13
|
// forge-lint: disable-next-line(mixed-case-variable)
|
|
13
14
|
IREVDeployer basic_deployer;
|
|
14
15
|
IREVLoans loans;
|
|
16
|
+
REVOwner owner;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
library RevnetCoreDeploymentLib {
|
|
@@ -58,6 +60,12 @@ library RevnetCoreDeploymentLib {
|
|
|
58
60
|
path: path, project_name: "revnet-core-v6", network_name: network_name, contractName: "REVLoans"
|
|
59
61
|
})
|
|
60
62
|
);
|
|
63
|
+
|
|
64
|
+
deployment.owner = REVOwner(
|
|
65
|
+
_getDeploymentAddress({
|
|
66
|
+
path: path, project_name: "revnet-core-v6", network_name: network_name, contractName: "REVOwner"
|
|
67
|
+
})
|
|
68
|
+
);
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
/// @notice Get the address of a contract that was deployed by the Deploy script.
|
package/src/REVDeployer.sol
CHANGED
|
@@ -210,6 +210,9 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
210
210
|
|
|
211
211
|
// Give the buyback hook (registry) permission to configure pools on all revnets.
|
|
212
212
|
_setPermission({operator: address(BUYBACK_HOOK), revnetId: 0, permissionId: JBPermissionIds.SET_BUYBACK_POOL});
|
|
213
|
+
|
|
214
|
+
// Link the REVOwner to this deployer so it can accept setter calls.
|
|
215
|
+
REVOwner(OWNER).setDeployer();
|
|
213
216
|
}
|
|
214
217
|
|
|
215
218
|
//*********************************************************************//
|
package/src/REVOwner.sol
CHANGED
|
@@ -80,7 +80,7 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook {
|
|
|
80
80
|
mapping(uint256 revnetId => IJB721TiersHook tiered721Hook) public tiered721HookOf;
|
|
81
81
|
|
|
82
82
|
/// @notice The deployer that manages revnet state.
|
|
83
|
-
/// @dev Set once via `
|
|
83
|
+
/// @dev Set once via `setDeployer()` from the REVDeployer's constructor. Reverts if called again.
|
|
84
84
|
IREVDeployer public DEPLOYER;
|
|
85
85
|
|
|
86
86
|
//*********************************************************************//
|
|
@@ -362,12 +362,11 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook {
|
|
|
362
362
|
}
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
-
/// @notice
|
|
366
|
-
/// @dev
|
|
367
|
-
|
|
368
|
-
function initialize(IREVDeployer deployer) external {
|
|
365
|
+
/// @notice Set the caller as this contract's deployer.
|
|
366
|
+
/// @dev Called by the REVDeployer's constructor. Reverts if a deployer is already set.
|
|
367
|
+
function setDeployer() external {
|
|
369
368
|
if (address(DEPLOYER) != address(0)) revert REVOwner_AlreadyInitialized();
|
|
370
|
-
DEPLOYER =
|
|
369
|
+
DEPLOYER = IREVDeployer(msg.sender);
|
|
371
370
|
}
|
|
372
371
|
|
|
373
372
|
/// @notice Store the cash out delay for a revnet.
|
|
@@ -241,8 +241,6 @@ contract REVnet_Integrations is TestBaseWorkflow {
|
|
|
241
241
|
address(revOwner)
|
|
242
242
|
);
|
|
243
243
|
|
|
244
|
-
revOwner.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
245
|
-
|
|
246
244
|
// Deploy the ARB sucker deployer.
|
|
247
245
|
JBArbitrumSuckerDeployer _deployer =
|
|
248
246
|
new JBArbitrumSuckerDeployer(jbDirectory(), jbPermissions(), jbTokens(), address(this), address(0));
|
|
@@ -104,8 +104,6 @@ contract REVAutoIssuanceFuzz_Local is TestBaseWorkflow {
|
|
|
104
104
|
address(revOwner)
|
|
105
105
|
);
|
|
106
106
|
|
|
107
|
-
revOwner.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
108
|
-
|
|
109
107
|
vm.prank(multisig());
|
|
110
108
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
111
109
|
}
|
|
@@ -271,8 +271,6 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
|
|
|
271
271
|
address(REV_OWNER)
|
|
272
272
|
);
|
|
273
273
|
|
|
274
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
275
|
-
|
|
276
274
|
// Deploy fee project
|
|
277
275
|
vm.prank(multisig());
|
|
278
276
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -1055,8 +1053,6 @@ contract REVInvincibility_Invariants is StdInvariant, TestBaseWorkflow {
|
|
|
1055
1053
|
address(REV_OWNER)
|
|
1056
1054
|
);
|
|
1057
1055
|
|
|
1058
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
1059
|
-
|
|
1060
1056
|
// Deploy fee project
|
|
1061
1057
|
{
|
|
1062
1058
|
JBAccountingContext[] memory ctx = new JBAccountingContext[](1);
|
package/test/REVLifecycle.t.sol
CHANGED
|
@@ -569,8 +569,6 @@ contract InvariantREVLoansTests is StdInvariant, TestBaseWorkflow {
|
|
|
569
569
|
address(REV_OWNER)
|
|
570
570
|
);
|
|
571
571
|
|
|
572
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
573
|
-
|
|
574
572
|
// Approve the basic deployer to configure the project.
|
|
575
573
|
vm.prank(address(multisig()));
|
|
576
574
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -410,8 +410,6 @@ contract REVLoansAttacks is TestBaseWorkflow {
|
|
|
410
410
|
address(REV_OWNER)
|
|
411
411
|
);
|
|
412
412
|
|
|
413
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
414
|
-
|
|
415
413
|
// Deploy fee project
|
|
416
414
|
vm.prank(address(multisig()));
|
|
417
415
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -376,8 +376,6 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
|
|
|
376
376
|
address(REV_OWNER)
|
|
377
377
|
);
|
|
378
378
|
|
|
379
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
380
|
-
|
|
381
379
|
// Deploy fee project.
|
|
382
380
|
vm.prank(multisig());
|
|
383
381
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -256,8 +256,6 @@ contract REVLoansSourceFeeRecovery is TestBaseWorkflow {
|
|
|
256
256
|
address(REV_OWNER)
|
|
257
257
|
);
|
|
258
258
|
|
|
259
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
260
|
-
|
|
261
259
|
// Deploy fee project.
|
|
262
260
|
vm.prank(multisig());
|
|
263
261
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -355,8 +355,6 @@ contract REVLoansSourcedTests is TestBaseWorkflow {
|
|
|
355
355
|
address(REV_OWNER)
|
|
356
356
|
);
|
|
357
357
|
|
|
358
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
359
|
-
|
|
360
358
|
// Approve the basic deployer to configure the project.
|
|
361
359
|
vm.prank(address(multisig()));
|
|
362
360
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -331,8 +331,6 @@ contract REVLoansUnsourcedTests is TestBaseWorkflow {
|
|
|
331
331
|
address(REV_OWNER)
|
|
332
332
|
);
|
|
333
333
|
|
|
334
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
335
|
-
|
|
336
334
|
// Approve the basic deployer to configure the project.
|
|
337
335
|
vm.prank(address(multisig()));
|
|
338
336
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -234,8 +234,6 @@ contract TestBurnHeldTokens is TestBaseWorkflow {
|
|
|
234
234
|
address(REV_OWNER)
|
|
235
235
|
);
|
|
236
236
|
|
|
237
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
238
|
-
|
|
239
237
|
// Deploy fee project.
|
|
240
238
|
vm.prank(multisig());
|
|
241
239
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -162,7 +162,6 @@ contract TestCEIPattern is TestBaseWorkflow {
|
|
|
162
162
|
address(REV_OWNER)
|
|
163
163
|
);
|
|
164
164
|
|
|
165
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
166
165
|
vm.prank(multisig());
|
|
167
166
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
168
167
|
_deployFeeProject();
|
|
@@ -247,8 +247,6 @@ contract TestCashOutCallerValidation is TestBaseWorkflow {
|
|
|
247
247
|
address(REV_OWNER)
|
|
248
248
|
);
|
|
249
249
|
|
|
250
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
251
|
-
|
|
252
250
|
// Approve the deployer to configure the fee project.
|
|
253
251
|
vm.prank(multisig());
|
|
254
252
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -177,8 +177,6 @@ contract TestConversionDocumentation is TestBaseWorkflow {
|
|
|
177
177
|
address(REV_OWNER)
|
|
178
178
|
);
|
|
179
179
|
|
|
180
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
181
|
-
|
|
182
180
|
// Deploy fee project as revnet.
|
|
183
181
|
vm.prank(multisig());
|
|
184
182
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -125,7 +125,6 @@ contract TestCrossSourceReallocation is TestBaseWorkflow {
|
|
|
125
125
|
address(REV_OWNER)
|
|
126
126
|
);
|
|
127
127
|
|
|
128
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
129
128
|
vm.prank(multisig());
|
|
130
129
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
131
130
|
_deployFeeProject();
|
|
@@ -318,8 +318,6 @@ contract TestERC2771MetaTx is TestBaseWorkflow {
|
|
|
318
318
|
address(REV_OWNER)
|
|
319
319
|
);
|
|
320
320
|
|
|
321
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
322
|
-
|
|
323
321
|
// Approve the deployer to configure the project.
|
|
324
322
|
vm.prank(address(multisig()));
|
|
325
323
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -128,7 +128,6 @@ contract TestFlashLoanSurplus is TestBaseWorkflow {
|
|
|
128
128
|
address(REV_OWNER)
|
|
129
129
|
);
|
|
130
130
|
|
|
131
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
132
131
|
vm.prank(multisig());
|
|
133
132
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
134
133
|
_deployFeeProject();
|
|
@@ -126,7 +126,6 @@ contract TestLiquidationBehavior is TestBaseWorkflow {
|
|
|
126
126
|
address(REV_OWNER)
|
|
127
127
|
);
|
|
128
128
|
|
|
129
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
130
129
|
vm.prank(multisig());
|
|
131
130
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
132
131
|
_deployFeeProject();
|
|
@@ -238,8 +238,6 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
|
|
|
238
238
|
address(REV_OWNER)
|
|
239
239
|
);
|
|
240
240
|
|
|
241
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
242
|
-
|
|
243
241
|
// Approve the deployer to configure the fee project.
|
|
244
242
|
vm.prank(multisig());
|
|
245
243
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -317,8 +317,6 @@ contract TestLowFindings is TestBaseWorkflow {
|
|
|
317
317
|
address(REV_OWNER)
|
|
318
318
|
);
|
|
319
319
|
|
|
320
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
321
|
-
|
|
322
320
|
// Deploy fee project.
|
|
323
321
|
vm.prank(multisig());
|
|
324
322
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -124,7 +124,6 @@ contract TestMixedFixes is TestBaseWorkflow {
|
|
|
124
124
|
address(REV_OWNER)
|
|
125
125
|
);
|
|
126
126
|
|
|
127
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
128
127
|
vm.prank(multisig());
|
|
129
128
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
130
129
|
_deployFeeProject();
|
|
@@ -285,8 +285,6 @@ contract TestPermit2Signatures is TestBaseWorkflow {
|
|
|
285
285
|
address(REV_OWNER)
|
|
286
286
|
);
|
|
287
287
|
|
|
288
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
289
|
-
|
|
290
288
|
// Approve the basic deployer to configure the project.
|
|
291
289
|
vm.prank(address(multisig()));
|
|
292
290
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -117,7 +117,6 @@ contract TestSplitWeightAdjustment is TestBaseWorkflow {
|
|
|
117
117
|
address(REV_OWNER)
|
|
118
118
|
);
|
|
119
119
|
|
|
120
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
121
120
|
vm.prank(multisig());
|
|
122
121
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
123
122
|
}
|
|
@@ -341,7 +340,6 @@ contract TestSplitWeightAdjustment is TestBaseWorkflow {
|
|
|
341
340
|
TRUSTED_FORWARDER,
|
|
342
341
|
address(ammOwner)
|
|
343
342
|
);
|
|
344
|
-
ammOwner.initialize(IREVDeployer(address(ammDeployer)));
|
|
345
343
|
|
|
346
344
|
vm.prank(multisig());
|
|
347
345
|
jbProjects().approve(address(ammDeployer), FEE_PROJECT_ID);
|
|
@@ -137,8 +137,6 @@ contract TestSplitWeightE2E is TestBaseWorkflow {
|
|
|
137
137
|
address(REV_OWNER)
|
|
138
138
|
);
|
|
139
139
|
|
|
140
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
141
|
-
|
|
142
140
|
vm.prank(multisig());
|
|
143
141
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
144
142
|
|
|
@@ -438,7 +436,6 @@ contract TestSplitWeightE2E is TestBaseWorkflow {
|
|
|
438
436
|
TRUSTED_FORWARDER,
|
|
439
437
|
address(ammOwner)
|
|
440
438
|
);
|
|
441
|
-
ammOwner.initialize(IREVDeployer(address(ammDeployer)));
|
|
442
439
|
|
|
443
440
|
vm.prank(multisig());
|
|
444
441
|
jbProjects().approve(address(ammDeployer), FEE_PROJECT_ID);
|
|
@@ -133,8 +133,6 @@ contract TestUint112Overflow is TestBaseWorkflow {
|
|
|
133
133
|
address(REV_OWNER)
|
|
134
134
|
);
|
|
135
135
|
|
|
136
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
137
|
-
|
|
138
136
|
// Deploy fee project
|
|
139
137
|
vm.prank(multisig());
|
|
140
138
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -126,7 +126,6 @@ contract TestZeroRepayment is TestBaseWorkflow {
|
|
|
126
126
|
address(REV_OWNER)
|
|
127
127
|
);
|
|
128
128
|
|
|
129
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
130
129
|
vm.prank(multisig());
|
|
131
130
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
132
131
|
_deployFeeProject();
|
|
@@ -183,8 +183,6 @@ contract LoanIdOverflowGuard is TestBaseWorkflow {
|
|
|
183
183
|
address(REV_OWNER)
|
|
184
184
|
);
|
|
185
185
|
|
|
186
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
187
|
-
|
|
188
186
|
// Approve the deployer to configure the fee project.
|
|
189
187
|
vm.prank(multisig());
|
|
190
188
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
@@ -128,7 +128,6 @@ contract TestBurnPermissionRequired is TestBaseWorkflow {
|
|
|
128
128
|
address(REV_OWNER)
|
|
129
129
|
);
|
|
130
130
|
|
|
131
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
132
131
|
vm.prank(multisig());
|
|
133
132
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
134
133
|
_deployFeeProject();
|
|
@@ -126,7 +126,6 @@ contract TestCrossRevnetLiquidation is TestBaseWorkflow {
|
|
|
126
126
|
address(REV_OWNER)
|
|
127
127
|
);
|
|
128
128
|
|
|
129
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
130
129
|
vm.prank(multisig());
|
|
131
130
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
132
131
|
_deployFeeProject();
|
|
@@ -130,7 +130,6 @@ contract TestCumulativeLoanCounter is TestBaseWorkflow {
|
|
|
130
130
|
address(REV_OWNER)
|
|
131
131
|
);
|
|
132
132
|
|
|
133
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
134
133
|
vm.prank(multisig());
|
|
135
134
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
136
135
|
_deployFeeProject();
|
|
@@ -132,7 +132,6 @@ contract TestLiquidateGapHandling is TestBaseWorkflow {
|
|
|
132
132
|
address(REV_OWNER)
|
|
133
133
|
);
|
|
134
134
|
|
|
135
|
-
REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
|
|
136
135
|
vm.prank(multisig());
|
|
137
136
|
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
138
137
|
_deployFeeProject();
|