@rev-net/core-v6 0.0.36 → 0.0.39
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/CHANGELOG.md +2 -2
- package/README.md +6 -7
- package/foundry.toml +1 -1
- package/package.json +23 -16
- package/references/operations.md +1 -1
- package/references/runtime.md +1 -1
- package/script/Deploy.s.sol +12 -9
- package/src/REVDeployer.sol +60 -65
- package/src/REVHiddenTokens.sol +2 -2
- package/src/REVLoans.sol +134 -90
- package/src/REVOwner.sol +124 -17
- package/src/interfaces/IREVDeployer.sol +2 -1
- package/src/interfaces/IREVHiddenTokens.sol +4 -1
- package/src/interfaces/IREVOwner.sol +5 -0
- package/ADMINISTRATION.md +0 -73
- package/ARCHITECTURE.md +0 -116
- package/AUDIT_INSTRUCTIONS.md +0 -90
- package/RISKS.md +0 -97
- package/SKILLS.md +0 -46
- package/STYLE_GUIDE.md +0 -610
- package/USER_JOURNEYS.md +0 -195
- package/foundry.lock +0 -11
- package/slither-ci.config.json +0 -10
- package/sphinx.lock +0 -507
- package/test/REV.integrations.t.sol +0 -573
- package/test/REVAutoIssuanceFuzz.t.sol +0 -328
- package/test/REVDeployerRegressions.t.sol +0 -396
- package/test/REVInvincibility.t.sol +0 -1371
- package/test/REVInvincibilityHandler.sol +0 -387
- package/test/REVLifecycle.t.sol +0 -420
- package/test/REVLoans.invariants.t.sol +0 -724
- package/test/REVLoansAttacks.t.sol +0 -816
- package/test/REVLoansFeeRecovery.t.sol +0 -783
- package/test/REVLoansFindings.t.sol +0 -711
- package/test/REVLoansRegressions.t.sol +0 -364
- package/test/REVLoansSourceFeeRecovery.t.sol +0 -517
- package/test/REVLoansSourced.t.sol +0 -1839
- package/test/REVLoansUnSourced.t.sol +0 -409
- package/test/TestAuditFixVerification.t.sol +0 -675
- package/test/TestBurnHeldTokens.t.sol +0 -394
- package/test/TestCEIPattern.t.sol +0 -508
- package/test/TestCashOutCallerValidation.t.sol +0 -452
- package/test/TestConversionDocumentation.t.sol +0 -368
- package/test/TestCrossCurrencyReclaim.t.sol +0 -610
- package/test/TestCrossSourceReallocation.t.sol +0 -361
- package/test/TestERC2771MetaTx.t.sol +0 -585
- package/test/TestEmptyBuybackSpecs.t.sol +0 -300
- package/test/TestFlashLoanSurplus.t.sol +0 -365
- package/test/TestHiddenTokens.t.sol +0 -474
- package/test/TestHookArrayOOB.t.sol +0 -278
- package/test/TestLiquidationBehavior.t.sol +0 -398
- package/test/TestLoanSourceRotation.t.sol +0 -553
- package/test/TestLoansCashOutDelay.t.sol +0 -493
- package/test/TestLongTailEconomics.t.sol +0 -677
- package/test/TestLowFindings.t.sol +0 -677
- package/test/TestMixedFixes.t.sol +0 -593
- package/test/TestPermit2Signatures.t.sol +0 -683
- package/test/TestReallocationSandwich.t.sol +0 -412
- package/test/TestRevnetRegressions.t.sol +0 -350
- package/test/TestSplitWeightAdjustment.t.sol +0 -527
- package/test/TestSplitWeightE2E.t.sol +0 -605
- package/test/TestSplitWeightFork.t.sol +0 -855
- package/test/TestStageTransitionBorrowable.t.sol +0 -301
- package/test/TestSwapTerminalPermission.t.sol +0 -262
- package/test/TestTerminalEncodingInHash.t.sol +0 -326
- package/test/TestUint112Overflow.t.sol +0 -311
- package/test/TestZeroAmountLoanGuard.t.sol +0 -378
- package/test/TestZeroRepayment.t.sol +0 -354
- package/test/audit/CodexCrossChainBuybackRouteMismatch.t.sol +0 -184
- package/test/audit/CodexPhantomSurplusTerminal.t.sol +0 -367
- package/test/audit/CodexREVOwnerRemoteSurplusCurrencyMismatch.t.sol +0 -142
- package/test/audit/LoanIdOverflowGuard.t.sol +0 -523
- package/test/audit/NemesisOperatorDelegation.t.sol +0 -356
- package/test/audit/SupportsInterfaceTest.t.sol +0 -51
- package/test/audit/TestFeeAllowanceLeak.t.sol +0 -197
- package/test/audit/TestLoansAndDeployerFixes.t.sol +0 -576
- package/test/fork/ForkTestBase.sol +0 -727
- package/test/fork/TestAutoIssuanceFork.t.sol +0 -148
- package/test/fork/TestCashOutFork.t.sol +0 -253
- package/test/fork/TestIssuanceDecayFork.t.sol +0 -158
- package/test/fork/TestLoanBorrowFork.t.sol +0 -163
- package/test/fork/TestLoanCrossRulesetFork.t.sol +0 -308
- package/test/fork/TestLoanERC20Fork.t.sol +0 -465
- package/test/fork/TestLoanLiquidationFork.t.sol +0 -135
- package/test/fork/TestLoanReallocateFork.t.sol +0 -113
- package/test/fork/TestLoanRepayFork.t.sol +0 -188
- package/test/fork/TestLoanTransferFork.t.sol +0 -143
- package/test/fork/TestPermit2PaymentFork.t.sol +0 -300
- package/test/fork/TestSplitWeightFork.t.sol +0 -189
- package/test/helpers/MaliciousContracts.sol +0 -247
- package/test/helpers/REVEmpty721Config.sol +0 -45
- package/test/mock/MockBuybackCashOutRecorder.sol +0 -84
- package/test/mock/MockBuybackDataHook.sol +0 -112
- package/test/mock/MockBuybackDataHookMintPath.sol +0 -68
- package/test/mock/MockSuckerRegistry.sol +0 -17
- package/test/regression/TestBurnPermissionRequired.t.sol +0 -294
- package/test/regression/TestCashOutBuybackFeeLeak.t.sol +0 -232
- package/test/regression/TestCrossRevnetLiquidation.t.sol +0 -255
- package/test/regression/TestCumulativeLoanCounter.t.sol +0 -361
- package/test/regression/TestLiquidateGapHandling.t.sol +0 -394
- package/test/regression/TestZeroPriceFeed.t.sol +0 -422
package/CHANGELOG.md
CHANGED
|
@@ -52,8 +52,8 @@ This file describes the verified change from `revnet-core-v5` to the current `re
|
|
|
52
52
|
- `IREVDeployer.deployFor(...)` now has overloads that return `(uint256, IJB721TiersHook)`.
|
|
53
53
|
- `IREVDeployer.BUYBACK_HOOK()`, `LOANS()`, and `OWNER()` are explicit v6 surface area.
|
|
54
54
|
- `IREVOwner` is a new interface and runtime counterpart to the deployer.
|
|
55
|
-
- `IREVHiddenTokens` is a new interface for temporary token hiding (burn to exclude from totalSupply, re-mint on reveal).
|
|
56
|
-
- `REVHiddenTokens` is a new standalone contract that lets holders temporarily hide tokens
|
|
55
|
+
- `IREVHiddenTokens` is a new interface for temporary token hiding (burn to exclude from live totalSupply, re-mint on reveal).
|
|
56
|
+
- `REVHiddenTokens` is a new standalone contract that lets holders temporarily hide tokens from visible/governance supply while `REVOwner` and `REVLoans` keep hidden balances in economic denominators.
|
|
57
57
|
- The old caller-supplied `REVBuybackHookConfig` path is no longer part of the deployer interface.
|
|
58
58
|
|
|
59
59
|
## Breaking ABI changes
|
package/README.md
CHANGED
|
@@ -19,7 +19,8 @@ This package provides:
|
|
|
19
19
|
- a deployer that launches Revnets and stores their long-lived configuration
|
|
20
20
|
- a runtime hook that mediates pay, cash-out, mint-permission, and delayed-cash-out behavior
|
|
21
21
|
- a loan system that burns token collateral on borrow and remints on repayment
|
|
22
|
-
- a hidden-token system that temporarily removes tokens from visible supply
|
|
22
|
+
- a hidden-token system that temporarily removes tokens from visible supply while preserving economic claim
|
|
23
|
+
denominators
|
|
23
24
|
|
|
24
25
|
It also composes with the 721 hook stack, buyback hook, router terminal, Croptop, and suckers where needed.
|
|
25
26
|
|
|
@@ -32,7 +33,7 @@ Use this repo when the product is a treasury-backed network with encoded stage t
|
|
|
32
33
|
| `REVDeployer` | Launches and configures Revnets, stages, split operators, and optional auxiliary features. |
|
|
33
34
|
| `REVOwner` | Runtime data-hook and cash-out-hook surface used by active Revnets. |
|
|
34
35
|
| `REVLoans` | Loan surface that lets users borrow against Revnet tokens with burned collateral and NFT loan positions. |
|
|
35
|
-
| `REVHiddenTokens` | Lets token holders temporarily hide tokens
|
|
36
|
+
| `REVHiddenTokens` | Lets token holders temporarily hide tokens from visible/governance supply until reveal, while cash-out and loan denominators still count hidden supply. |
|
|
36
37
|
|
|
37
38
|
## Mental Model
|
|
38
39
|
|
|
@@ -71,7 +72,7 @@ Most mistakes come from assuming a deploy-time parameter can be changed later or
|
|
|
71
72
|
2. `test/REVLoans.invariants.t.sol`
|
|
72
73
|
3. `test/TestLongTailEconomics.t.sol`
|
|
73
74
|
4. `test/fork/TestLoanBorrowFork.t.sol`
|
|
74
|
-
5. `test/audit/
|
|
75
|
+
5. `test/audit/PhantomSurplusTerminal.t.sol`
|
|
75
76
|
|
|
76
77
|
## Install
|
|
77
78
|
|
|
@@ -83,16 +84,14 @@ npm install @rev-net/core-v6
|
|
|
83
84
|
|
|
84
85
|
```bash
|
|
85
86
|
npm install
|
|
86
|
-
forge build
|
|
87
|
-
forge test
|
|
87
|
+
forge build --deny notes
|
|
88
|
+
forge test --deny notes
|
|
88
89
|
```
|
|
89
90
|
|
|
90
91
|
Useful scripts:
|
|
91
92
|
|
|
92
93
|
- `npm run deploy:mainnets`
|
|
93
94
|
- `npm run deploy:testnets`
|
|
94
|
-
- `npm run deploy:mainnets:1_1`
|
|
95
|
-
- `npm run deploy:testnets:1_1`
|
|
96
95
|
|
|
97
96
|
## Deployment Notes
|
|
98
97
|
|
package/foundry.toml
CHANGED
package/package.json
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rev-net/core-v6",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.39",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/rev-net/revnet-core-v6"
|
|
8
8
|
},
|
|
9
|
+
"files": [
|
|
10
|
+
"CHANGELOG.md",
|
|
11
|
+
"foundry.toml",
|
|
12
|
+
"references/",
|
|
13
|
+
"remappings.txt",
|
|
14
|
+
"script/Deploy.s.sol",
|
|
15
|
+
"script/helpers/",
|
|
16
|
+
"src/"
|
|
17
|
+
],
|
|
9
18
|
"engines": {
|
|
10
19
|
"node": ">=20.0.0"
|
|
11
20
|
},
|
|
@@ -13,26 +22,24 @@
|
|
|
13
22
|
"test": "forge test",
|
|
14
23
|
"coverage": "forge coverage --match-path \"./src/*.sol\" --report lcov --report summary",
|
|
15
24
|
"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
25
|
"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
26
|
"artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'revnet-core-v6'"
|
|
20
27
|
},
|
|
21
28
|
"dependencies": {
|
|
22
|
-
"@bananapus/721-hook-v6": "
|
|
23
|
-
"@bananapus/buyback-hook-v6": "
|
|
24
|
-
"@bananapus/core-v6": "
|
|
25
|
-
"@bananapus/ownable-v6": "
|
|
26
|
-
"@bananapus/permission-ids-v6": "
|
|
27
|
-
"@bananapus/router-terminal-v6": "
|
|
28
|
-
"@bananapus/suckers-v6": "
|
|
29
|
-
"@croptop/core-v6": "
|
|
30
|
-
"@openzeppelin/contracts": "
|
|
31
|
-
"@uniswap/
|
|
32
|
-
"@uniswap/v4-periphery": "^1.0.3"
|
|
29
|
+
"@bananapus/721-hook-v6": "0.0.43",
|
|
30
|
+
"@bananapus/buyback-hook-v6": "0.0.37",
|
|
31
|
+
"@bananapus/core-v6": "0.0.39",
|
|
32
|
+
"@bananapus/ownable-v6": "0.0.24",
|
|
33
|
+
"@bananapus/permission-ids-v6": "0.0.22",
|
|
34
|
+
"@bananapus/router-terminal-v6": "0.0.36",
|
|
35
|
+
"@bananapus/suckers-v6": "0.0.33",
|
|
36
|
+
"@croptop/core-v6": "0.0.39",
|
|
37
|
+
"@openzeppelin/contracts": "5.6.1",
|
|
38
|
+
"@uniswap/permit2": "github:Uniswap/permit2#cc56ad0f3439c502c246fc5cfcc3db92bb8b7219"
|
|
33
39
|
},
|
|
34
40
|
"devDependencies": {
|
|
35
|
-
"@bananapus/address-registry-v6": "
|
|
36
|
-
"@sphinx-labs/plugins": "
|
|
41
|
+
"@bananapus/address-registry-v6": "0.0.25",
|
|
42
|
+
"@sphinx-labs/plugins": "0.33.3",
|
|
43
|
+
"@uniswap/v4-core": "1.0.2"
|
|
37
44
|
}
|
|
38
45
|
}
|
package/references/operations.md
CHANGED
|
@@ -143,7 +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.
|
|
146
|
+
22. **Hidden tokens are economic, not cosmetic.** Hiding burns visible tokens and lowers visible/governance supply until reveal. Cash-out and loan denominators still include hidden balances because they are recoverable claims.
|
|
147
147
|
|
|
148
148
|
### NATIVE_TOKEN Accounting on Non-ETH Chains
|
|
149
149
|
|
package/references/runtime.md
CHANGED
|
@@ -102,6 +102,6 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
|
|
|
102
102
|
|
|
103
103
|
| Function | Permissions | What it does |
|
|
104
104
|
|----------|------------|-------------|
|
|
105
|
-
| `REVHiddenTokens.hideTokensOf(revnetId, tokenCount, holder)` | Holder only. The holder must either be allowlisted or personally hold `HIDE_TOKENS`. | Burns visible tokens, increases hidden balance, and lowers visible supply. |
|
|
105
|
+
| `REVHiddenTokens.hideTokensOf(revnetId, tokenCount, holder)` | Holder only. The holder must either be allowlisted or personally hold `HIDE_TOKENS`. | Burns visible tokens, increases hidden balance, and lowers visible supply. Cash-out and loan denominators still include the hidden balance while it is revealable. |
|
|
106
106
|
| `REVHiddenTokens.revealTokensOf(revnetId, tokenCount, holder)` | Holder only | Re-mints previously hidden tokens back to the holder and reduces hidden balance. |
|
|
107
107
|
| `REVHiddenTokens.setTokenHidingAllowedFor(revnetId, holder, isAllowed)` | Operator with `HIDE_TOKENS` | Allows or revokes a holder's ability to hide their own tokens. |
|
package/script/Deploy.s.sol
CHANGED
|
@@ -289,14 +289,16 @@ contract DeployScript is Script, Sphinx {
|
|
|
289
289
|
if (block.chainid == 1 || block.chainid == 11_155_111) {
|
|
290
290
|
suckerDeployerConfigurations = new JBSuckerDeployerConfig[](3);
|
|
291
291
|
// OP
|
|
292
|
-
suckerDeployerConfigurations[0] =
|
|
293
|
-
|
|
292
|
+
suckerDeployerConfigurations[0] = JBSuckerDeployerConfig({
|
|
293
|
+
deployer: suckers.optimismDeployer, peer: bytes32(0), mappings: tokenMappings
|
|
294
|
+
});
|
|
294
295
|
|
|
295
296
|
suckerDeployerConfigurations[1] =
|
|
296
|
-
JBSuckerDeployerConfig({deployer: suckers.baseDeployer, mappings: tokenMappings});
|
|
297
|
+
JBSuckerDeployerConfig({deployer: suckers.baseDeployer, peer: bytes32(0), mappings: tokenMappings});
|
|
297
298
|
|
|
298
|
-
suckerDeployerConfigurations[2] =
|
|
299
|
-
|
|
299
|
+
suckerDeployerConfigurations[2] = JBSuckerDeployerConfig({
|
|
300
|
+
deployer: suckers.arbitrumDeployer, peer: bytes32(0), mappings: tokenMappings
|
|
301
|
+
});
|
|
300
302
|
} else {
|
|
301
303
|
suckerDeployerConfigurations = new JBSuckerDeployerConfig[](1);
|
|
302
304
|
// L2 -> Mainnet
|
|
@@ -304,6 +306,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
304
306
|
deployer: address(suckers.optimismDeployer) != address(0)
|
|
305
307
|
? suckers.optimismDeployer
|
|
306
308
|
: address(suckers.baseDeployer) != address(0) ? suckers.baseDeployer : suckers.arbitrumDeployer,
|
|
309
|
+
peer: bytes32(0),
|
|
307
310
|
mappings: tokenMappings
|
|
308
311
|
});
|
|
309
312
|
|
|
@@ -493,8 +496,8 @@ contract DeployScript is Script, Sphinx {
|
|
|
493
496
|
directory: core.controller.DIRECTORY(),
|
|
494
497
|
feeRevnetId: FEE_PROJECT_ID,
|
|
495
498
|
suckerRegistry: suckers.registry,
|
|
496
|
-
loans:
|
|
497
|
-
hiddenTokens:
|
|
499
|
+
loans: revloans,
|
|
500
|
+
hiddenTokens: revHiddenTokens
|
|
498
501
|
});
|
|
499
502
|
|
|
500
503
|
// Deploy REVDeployer with the REVLoans, buyback hook, and REVOwner addresses.
|
|
@@ -510,7 +513,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
510
513
|
hook.hook_deployer,
|
|
511
514
|
croptop.publisher,
|
|
512
515
|
IJBBuybackHookRegistry(address(buybackHook.registry)),
|
|
513
|
-
|
|
516
|
+
revloans,
|
|
514
517
|
TRUSTED_FORWARDER,
|
|
515
518
|
address(revOwner)
|
|
516
519
|
)
|
|
@@ -527,7 +530,7 @@ contract DeployScript is Script, Sphinx {
|
|
|
527
530
|
hookDeployer: hook.hook_deployer,
|
|
528
531
|
publisher: croptop.publisher,
|
|
529
532
|
buybackHook: IJBBuybackHookRegistry(address(buybackHook.registry)),
|
|
530
|
-
loans:
|
|
533
|
+
loans: revloans,
|
|
531
534
|
trustedForwarder: TRUSTED_FORWARDER,
|
|
532
535
|
owner: address(revOwner)
|
|
533
536
|
});
|
package/src/REVDeployer.sol
CHANGED
|
@@ -22,6 +22,7 @@ import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
|
22
22
|
import {JBRulesetConfig} from "@bananapus/core-v6/src/structs/JBRulesetConfig.sol";
|
|
23
23
|
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
24
24
|
import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
|
|
25
|
+
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
25
26
|
import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
|
|
26
27
|
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
27
28
|
import {IJBSuckerRegistry} from "@bananapus/suckers-v6/src/interfaces/IJBSuckerRegistry.sol";
|
|
@@ -33,6 +34,7 @@ import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Recei
|
|
|
33
34
|
import {mulDiv, sqrt} from "@prb/math/src/Common.sol";
|
|
34
35
|
|
|
35
36
|
import {IREVDeployer} from "./interfaces/IREVDeployer.sol";
|
|
37
|
+
import {IREVLoans} from "./interfaces/IREVLoans.sol";
|
|
36
38
|
import {REVOwner} from "./REVOwner.sol";
|
|
37
39
|
import {REVAutoIssuance} from "./structs/REVAutoIssuance.sol";
|
|
38
40
|
import {REVConfig} from "./structs/REVConfig.sol";
|
|
@@ -110,7 +112,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
110
112
|
/// @notice The loan contract used by all revnets.
|
|
111
113
|
/// @dev Revnets can offer loans to their participants, collateralized by their tokens.
|
|
112
114
|
/// Participants can borrow up to the current cash out value of their tokens.
|
|
113
|
-
|
|
115
|
+
IREVLoans public immutable override LOANS;
|
|
114
116
|
|
|
115
117
|
/// @notice The runtime data hook contract that handles pay and cash out callbacks for revnets.
|
|
116
118
|
/// @dev Set as `dataHook` in each revnet's ruleset metadata. Implements `IJBRulesetDataHook` and `IJBCashOutHook`.
|
|
@@ -178,7 +180,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
178
180
|
IJB721TiersHookDeployer hookDeployer,
|
|
179
181
|
CTPublisher publisher,
|
|
180
182
|
IJBBuybackHookRegistry buybackHook,
|
|
181
|
-
|
|
183
|
+
IREVLoans loans,
|
|
182
184
|
address trustedForwarder,
|
|
183
185
|
address owner
|
|
184
186
|
)
|
|
@@ -193,20 +195,14 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
193
195
|
HOOK_DEPLOYER = hookDeployer;
|
|
194
196
|
PUBLISHER = publisher;
|
|
195
197
|
BUYBACK_HOOK = buybackHook;
|
|
196
|
-
// slither-disable-next-line missing-zero-check
|
|
197
198
|
LOANS = loans;
|
|
198
199
|
// slither-disable-next-line missing-zero-check
|
|
199
200
|
OWNER = owner;
|
|
200
201
|
|
|
201
|
-
// Give the sucker registry permission to map tokens for all revnets.
|
|
202
|
-
_setPermission({
|
|
203
|
-
operator: address(SUCKER_REGISTRY), revnetId: 0, permissionId: JBPermissionIds.MAP_SUCKER_TOKEN
|
|
204
|
-
});
|
|
205
|
-
|
|
206
202
|
// Give the loan contract permission to use the surplus allowance of all revnets.
|
|
207
203
|
// Uses wildcard revnetId=0 intentionally — the loan contract is a singleton shared by all revnets,
|
|
208
204
|
// and each revnet's surplus allowance limits already constrain how much can be drawn.
|
|
209
|
-
_setPermission({operator: LOANS, revnetId: 0, permissionId: JBPermissionIds.USE_ALLOWANCE});
|
|
205
|
+
_setPermission({operator: address(LOANS), revnetId: 0, permissionId: JBPermissionIds.USE_ALLOWANCE});
|
|
210
206
|
|
|
211
207
|
// Give the buyback hook (registry) permission to configure pools on all revnets.
|
|
212
208
|
_setPermission({operator: address(BUYBACK_HOOK), revnetId: 0, permissionId: JBPermissionIds.SET_BUYBACK_POOL});
|
|
@@ -356,12 +352,6 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
356
352
|
});
|
|
357
353
|
}
|
|
358
354
|
|
|
359
|
-
/// @notice Returns the next project ID.
|
|
360
|
-
/// @return nextProjectId The next project ID.
|
|
361
|
-
function _nextProjectId() internal view returns (uint256) {
|
|
362
|
-
return PROJECTS.count() + 1;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
355
|
/// @notice Returns the permissions that the split operator should be granted for a revnet.
|
|
366
356
|
/// @param revnetId The ID of the revnet to get split operator permissions for.
|
|
367
357
|
/// @return allOperatorPermissions The permissions that the split operator should be granted for the revnet,
|
|
@@ -375,22 +365,21 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
375
365
|
uint256[] memory customSplitOperatorPermissionIndexes = _extraOperatorPermissions[revnetId];
|
|
376
366
|
|
|
377
367
|
// Make the array that merges the default and custom operator permissions.
|
|
378
|
-
allOperatorPermissions = new uint256[](
|
|
368
|
+
allOperatorPermissions = new uint256[](10 + customSplitOperatorPermissionIndexes.length);
|
|
379
369
|
allOperatorPermissions[0] = JBPermissionIds.SET_SPLIT_GROUPS;
|
|
380
370
|
allOperatorPermissions[1] = JBPermissionIds.SET_BUYBACK_POOL;
|
|
381
371
|
allOperatorPermissions[2] = JBPermissionIds.SET_BUYBACK_TWAP;
|
|
382
372
|
allOperatorPermissions[3] = JBPermissionIds.SET_PROJECT_URI;
|
|
383
|
-
allOperatorPermissions[4] = JBPermissionIds.
|
|
384
|
-
allOperatorPermissions[5] = JBPermissionIds.
|
|
385
|
-
allOperatorPermissions[6] = JBPermissionIds.
|
|
386
|
-
allOperatorPermissions[7] = JBPermissionIds.
|
|
387
|
-
allOperatorPermissions[8] = JBPermissionIds.
|
|
388
|
-
allOperatorPermissions[9] = JBPermissionIds.
|
|
389
|
-
allOperatorPermissions[10] = JBPermissionIds.HIDE_TOKENS;
|
|
373
|
+
allOperatorPermissions[4] = JBPermissionIds.SUCKER_SAFETY;
|
|
374
|
+
allOperatorPermissions[5] = JBPermissionIds.SET_BUYBACK_HOOK;
|
|
375
|
+
allOperatorPermissions[6] = JBPermissionIds.SET_ROUTER_TERMINAL;
|
|
376
|
+
allOperatorPermissions[7] = JBPermissionIds.SET_TOKEN_METADATA;
|
|
377
|
+
allOperatorPermissions[8] = JBPermissionIds.SIGN_FOR_ERC20;
|
|
378
|
+
allOperatorPermissions[9] = JBPermissionIds.HIDE_TOKENS;
|
|
390
379
|
|
|
391
380
|
// Copy the custom permissions into the array.
|
|
392
381
|
for (uint256 i; i < customSplitOperatorPermissionIndexes.length;) {
|
|
393
|
-
allOperatorPermissions[
|
|
382
|
+
allOperatorPermissions[10 + i] = customSplitOperatorPermissionIndexes[i];
|
|
394
383
|
unchecked {
|
|
395
384
|
++i;
|
|
396
385
|
}
|
|
@@ -510,6 +499,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
510
499
|
/// @param allowedPosts Restrictions on which croptop posts are allowed on the revnet's ERC-721 tiers.
|
|
511
500
|
/// @return revnetId The ID of the newly created revnet.
|
|
512
501
|
/// @return hook The address of the tiered ERC-721 hook that was deployed for the revnet.
|
|
502
|
+
// The deployment flow makes external setup calls, but any observed state is revnet-scoped and reverts atomically.
|
|
503
|
+
// slither-disable-next-line reentrancy-benign
|
|
513
504
|
function deployFor(
|
|
514
505
|
uint256 revnetId,
|
|
515
506
|
REVConfig calldata configuration,
|
|
@@ -525,9 +516,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
525
516
|
// Keep a reference to the revnet ID which was passed in.
|
|
526
517
|
bool shouldDeployNewRevnet = revnetId == 0;
|
|
527
518
|
|
|
528
|
-
// If the caller is deploying a new revnet,
|
|
529
|
-
|
|
530
|
-
if (shouldDeployNewRevnet) revnetId = _nextProjectId();
|
|
519
|
+
// If the caller is deploying a new revnet, reserve its project ID before deriving hook/sucker config.
|
|
520
|
+
if (shouldDeployNewRevnet) revnetId = PROJECTS.createFor(address(this));
|
|
531
521
|
|
|
532
522
|
// Deploy the revnet with the specified tiered ERC-721 hook and croptop posting criteria.
|
|
533
523
|
hook = _deploy721RevnetFor({
|
|
@@ -544,6 +534,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
544
534
|
}
|
|
545
535
|
|
|
546
536
|
/// @inheritdoc IREVDeployer
|
|
537
|
+
// The deployment flow makes external setup calls, but any observed state is revnet-scoped and reverts atomically.
|
|
538
|
+
// slither-disable-next-line reentrancy-benign
|
|
547
539
|
function deployFor(
|
|
548
540
|
uint256 revnetId,
|
|
549
541
|
REVConfig calldata configuration,
|
|
@@ -555,7 +547,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
555
547
|
returns (uint256, IJB721TiersHook hook)
|
|
556
548
|
{
|
|
557
549
|
bool shouldDeployNewRevnet = revnetId == 0;
|
|
558
|
-
if (shouldDeployNewRevnet) revnetId =
|
|
550
|
+
if (shouldDeployNewRevnet) revnetId = PROJECTS.createFor(address(this));
|
|
559
551
|
|
|
560
552
|
// Deploy the revnet (project, rulesets, ERC-20, suckers, etc.).
|
|
561
553
|
bytes32 encodedConfigurationHash = _deployRevnetFor({
|
|
@@ -583,6 +575,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
583
575
|
REVOwner(OWNER).setTiered721HookOf({revnetId: revnetId, hook: hook});
|
|
584
576
|
|
|
585
577
|
// Grant the split operator all 721 permissions (no prevent* flags for default config).
|
|
578
|
+
// These permission IDs are only consumed by `_setSplitOperatorOf` below, after revnet setup has either
|
|
579
|
+
// completed or reverted atomically.
|
|
586
580
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.ADJUST_721_TIERS);
|
|
587
581
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_METADATA);
|
|
588
582
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.MINT_721);
|
|
@@ -656,6 +650,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
656
650
|
//*********************************************************************//
|
|
657
651
|
|
|
658
652
|
/// @notice Deploy a revnet which sells tiered ERC-721s and (optionally) allows croptop posts to its ERC-721 tiers.
|
|
653
|
+
// The helper performs external hook/post setup after core revnet setup; any failure reverts the whole deployment.
|
|
654
|
+
// slither-disable-next-line reentrancy-benign
|
|
659
655
|
function _deploy721RevnetFor(
|
|
660
656
|
uint256 revnetId,
|
|
661
657
|
bool shouldDeployNewRevnet,
|
|
@@ -706,6 +702,9 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
706
702
|
// Store the tiered ERC-721 hook in the owner contract.
|
|
707
703
|
REVOwner(OWNER).setTiered721HookOf({revnetId: revnetId, hook: hook});
|
|
708
704
|
|
|
705
|
+
// These permission IDs are only consumed by `_setSplitOperatorOf` below, after revnet setup has either
|
|
706
|
+
// completed or reverted atomically.
|
|
707
|
+
|
|
709
708
|
// Give the split operator permission to add and remove tiers unless prevented.
|
|
710
709
|
if (!tiered721HookConfiguration.preventSplitOperatorAdjustingTiers) {
|
|
711
710
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.ADJUST_721_TIERS);
|
|
@@ -773,8 +772,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
773
772
|
/// uninitialized.
|
|
774
773
|
/// - The project's JBProjects NFT is permanently transferred to this contract. This is irreversible.
|
|
775
774
|
/// @param revnetId The ID of the Juicebox project to initialize as a revnet. Send 0 to deploy a new revnet.
|
|
776
|
-
/// @param shouldDeployNewRevnet Whether
|
|
777
|
-
/// revnet.
|
|
775
|
+
/// @param shouldDeployNewRevnet Whether the revnet ID was reserved by this deployment call, or the caller is
|
|
776
|
+
/// converting an existing Juicebox project into a revnet.
|
|
778
777
|
/// @param configuration Core revnet configuration. See `REVConfig`.
|
|
779
778
|
/// @param terminalConfigurations The terminals to set up for the revnet. Used for payments and cash outs.
|
|
780
779
|
/// @param suckerDeploymentConfiguration The suckers to set up for the revnet. Suckers facilitate cross-chain
|
|
@@ -795,43 +794,37 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
795
794
|
(rulesetConfigurations, encodedConfigurationHash) = _makeRulesetConfigurations({
|
|
796
795
|
revnetId: revnetId, configuration: configuration, terminalConfigurations: terminalConfigurations
|
|
797
796
|
});
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
// slither-disable-next-line incorrect-equality,reentrancy-benign,reentrancy-events
|
|
802
|
-
assert(
|
|
803
|
-
CONTROLLER.launchProjectFor({
|
|
804
|
-
owner: address(this),
|
|
805
|
-
projectUri: configuration.description.uri,
|
|
806
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
807
|
-
terminalConfigurations: terminalConfigurations,
|
|
808
|
-
memo: ""
|
|
809
|
-
}) == revnetId
|
|
810
|
-
);
|
|
811
|
-
} else {
|
|
797
|
+
|
|
798
|
+
address owner;
|
|
799
|
+
if (!shouldDeployNewRevnet) {
|
|
812
800
|
// Keep a reference to the Juicebox project's owner.
|
|
813
|
-
|
|
801
|
+
owner = PROJECTS.ownerOf(revnetId);
|
|
814
802
|
|
|
815
803
|
// Make sure the caller is the owner of the Juicebox project.
|
|
816
804
|
if (_msgSender() != owner) revert REVDeployer_Unauthorized(revnetId, _msgSender());
|
|
805
|
+
}
|
|
817
806
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
// Launch the revnet rulesets for the pre-existing project.
|
|
823
|
-
// slither-disable-next-line unused-return
|
|
824
|
-
CONTROLLER.launchRulesetsFor({
|
|
825
|
-
projectId: revnetId,
|
|
826
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
827
|
-
terminalConfigurations: terminalConfigurations,
|
|
828
|
-
memo: ""
|
|
829
|
-
});
|
|
807
|
+
// Store the hash before setup callbacks so reentrant readers cannot observe a zero configuration hash. Any
|
|
808
|
+
// subsequent revert rolls this write back.
|
|
809
|
+
hashedEncodedConfigurationOf[revnetId] = encodedConfigurationHash;
|
|
830
810
|
|
|
831
|
-
|
|
832
|
-
|
|
811
|
+
if (!shouldDeployNewRevnet) {
|
|
812
|
+
// Initialize the existing Juicebox project as a revnet by transferring the `JBProjects` NFT to this
|
|
813
|
+
// deployer. This is irreversible.
|
|
814
|
+
// slither-disable-next-line reentrancy-benign
|
|
815
|
+
IERC721(PROJECTS).safeTransferFrom({from: owner, to: address(this), tokenId: revnetId});
|
|
833
816
|
}
|
|
834
817
|
|
|
818
|
+
// Launch the revnet rulesets for the reserved or pre-existing blank project.
|
|
819
|
+
// slither-disable-next-line unused-return
|
|
820
|
+
CONTROLLER.launchRulesetsFor({
|
|
821
|
+
projectId: revnetId,
|
|
822
|
+
projectUri: configuration.description.uri,
|
|
823
|
+
rulesetConfigurations: rulesetConfigurations,
|
|
824
|
+
terminalConfigurations: terminalConfigurations,
|
|
825
|
+
memo: ""
|
|
826
|
+
});
|
|
827
|
+
|
|
835
828
|
// Store the cash out delay of the revnet if its stages are already in progress.
|
|
836
829
|
// This prevents cash out liquidity/arbitrage issues for existing revnets which
|
|
837
830
|
// are deploying to a new chain.
|
|
@@ -875,9 +868,6 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
875
868
|
});
|
|
876
869
|
}
|
|
877
870
|
|
|
878
|
-
// Store the hashed encoded configuration.
|
|
879
|
-
hashedEncodedConfigurationOf[revnetId] = encodedConfigurationHash;
|
|
880
|
-
|
|
881
871
|
emit DeployRevnet({
|
|
882
872
|
revnetId: revnetId,
|
|
883
873
|
configuration: configuration,
|
|
@@ -908,7 +898,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
908
898
|
caller: _msgSender()
|
|
909
899
|
});
|
|
910
900
|
|
|
911
|
-
//
|
|
901
|
+
// Include the caller so two revnets with identical configuration and user salt cannot collide. Same-address
|
|
902
|
+
// cross-chain deployment still works when the same operator calls this helper on each chain.
|
|
912
903
|
// slither-disable-next-line unused-return
|
|
913
904
|
suckers = SUCKER_REGISTRY.deploySuckersFor({
|
|
914
905
|
projectId: revnetId,
|
|
@@ -1014,7 +1005,10 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
1014
1005
|
fundAccessLimitGroups: fundAccessLimitGroups
|
|
1015
1006
|
});
|
|
1016
1007
|
|
|
1017
|
-
// Add the stage's
|
|
1008
|
+
// Add the stage's immutable economics to the byte-encoded configuration. `extraMetadata` is Juicebox
|
|
1009
|
+
// ruleset metadata forwarded to the revnet data hook, so it remains part of the revnet identity.
|
|
1010
|
+
// Reserved-token split recipients and individual weights are intentionally excluded below: the split
|
|
1011
|
+
// limit (`splitPercent`) is the economic commitment, while split routing can change over time.
|
|
1018
1012
|
encodedConfiguration = abi.encode(
|
|
1019
1013
|
encodedConfiguration,
|
|
1020
1014
|
// Use the effective start time (normalized from 0 to block.timestamp for the first stage).
|
|
@@ -1024,7 +1018,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
1024
1018
|
stageConfiguration.initialIssuance,
|
|
1025
1019
|
stageConfiguration.issuanceCutFrequency,
|
|
1026
1020
|
stageConfiguration.issuanceCutPercent,
|
|
1027
|
-
stageConfiguration.cashOutTaxRate
|
|
1021
|
+
stageConfiguration.cashOutTaxRate,
|
|
1022
|
+
stageConfiguration.extraMetadata
|
|
1028
1023
|
);
|
|
1029
1024
|
|
|
1030
1025
|
// Add each auto-mint to the byte-encoded representation.
|
package/src/REVHiddenTokens.sol
CHANGED
|
@@ -13,8 +13,8 @@ import {Context} from "@openzeppelin/contracts/utils/Context.sol";
|
|
|
13
13
|
import {IREVHiddenTokens} from "./interfaces/IREVHiddenTokens.sol";
|
|
14
14
|
|
|
15
15
|
/// @notice Allows authorized operators to hide (burn) revnet tokens on behalf of holders, excluding them from
|
|
16
|
-
/// governance weight. Hidden tokens are burned from circulating supply,
|
|
17
|
-
///
|
|
16
|
+
/// governance weight. Hidden tokens are burned from live circulating supply, but `REVOwner` and `REVLoans` add the
|
|
17
|
+
/// hidden supply back into their economic denominators while those tokens remain revealable.
|
|
18
18
|
/// Hidden tokens can be revealed (re-minted) at any time.
|
|
19
19
|
contract REVHiddenTokens is ERC2771Context, JBPermissioned, IREVHiddenTokens {
|
|
20
20
|
//*********************************************************************//
|