@rev-net/core-v6 0.0.29 → 0.0.31
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 +19 -9
- package/ARCHITECTURE.md +3 -0
- package/AUDIT_INSTRUCTIONS.md +11 -1
- package/CHANGELOG.md +26 -0
- package/README.md +1 -0
- package/RISKS.md +28 -4
- package/SKILLS.md +2 -1
- package/USER_JOURNEYS.md +28 -3
- package/package.json +8 -8
- package/references/operations.md +1 -1
- package/script/Deploy.s.sol +26 -4
- package/src/REVDeployer.sol +4 -2
- package/src/REVHiddenTokens.sol +149 -0
- package/src/REVLoans.sol +192 -199
- package/src/REVOwner.sol +51 -14
- package/src/interfaces/IREVHiddenTokens.sol +53 -0
- package/src/interfaces/IREVLoans.sol +8 -6
- package/test/REV.integrations.t.sol +12 -2
- package/test/REVAutoIssuanceFuzz.t.sol +12 -2
- package/test/REVDeployerRegressions.t.sol +14 -3
- package/test/REVInvincibility.t.sol +27 -8
- package/test/REVInvincibilityHandler.sol +1 -1
- package/test/REVLifecycle.t.sol +14 -3
- package/test/REVLoans.invariants.t.sol +15 -4
- package/test/REVLoansAttacks.t.sol +19 -7
- package/test/REVLoansFeeRecovery.t.sol +24 -13
- package/test/REVLoansFindings.t.sol +16 -5
- package/test/REVLoansRegressions.t.sol +15 -4
- package/test/REVLoansSourceFeeRecovery.t.sol +16 -5
- package/test/REVLoansSourced.t.sol +60 -25
- package/test/REVLoansUnSourced.t.sol +15 -4
- package/test/TestBurnHeldTokens.t.sol +14 -3
- package/test/TestCEIPattern.t.sol +19 -7
- package/test/TestCashOutCallerValidation.t.sol +15 -4
- package/test/TestConversionDocumentation.t.sol +14 -3
- package/test/TestCrossCurrencyReclaim.t.sol +14 -3
- package/test/TestCrossSourceReallocation.t.sol +15 -4
- package/test/TestERC2771MetaTx.t.sol +18 -5
- package/test/TestEmptyBuybackSpecs.t.sol +14 -3
- package/test/TestFlashLoanSurplus.t.sol +15 -4
- package/test/TestHiddenTokens.t.sol +431 -0
- package/test/TestHookArrayOOB.t.sol +14 -3
- package/test/TestLiquidationBehavior.t.sol +16 -5
- package/test/TestLoanSourceRotation.t.sol +20 -7
- package/test/TestLoansCashOutDelay.t.sol +18 -7
- package/test/TestLongTailEconomics.t.sol +14 -3
- package/test/TestLowFindings.t.sol +25 -9
- package/test/TestMixedFixes.t.sol +19 -8
- package/test/TestPermit2Signatures.t.sol +15 -4
- package/test/TestReallocationSandwich.t.sol +16 -4
- package/test/TestRevnetRegressions.t.sol +16 -5
- package/test/TestSplitWeightAdjustment.t.sol +16 -4
- package/test/TestSplitWeightE2E.t.sol +18 -4
- package/test/TestSplitWeightFork.t.sol +16 -3
- package/test/TestStageTransitionBorrowable.t.sol +14 -3
- package/test/TestSwapTerminalPermission.t.sol +14 -3
- package/test/TestUint112Overflow.t.sol +15 -4
- package/test/TestZeroAmountLoanGuard.t.sol +15 -4
- package/test/TestZeroRepayment.t.sol +15 -4
- package/test/audit/CodexPhantomSurplusTerminal.t.sol +367 -0
- package/test/audit/LoanIdOverflowGuard.t.sol +16 -5
- package/test/audit/NemesisOperatorDelegation.t.sol +289 -0
- package/test/fork/ForkTestBase.sol +18 -4
- package/test/fork/TestLoanBorrowFork.t.sol +2 -1
- package/test/fork/TestLoanERC20Fork.t.sol +4 -2
- package/test/fork/TestLoanTransferFork.t.sol +12 -2
- package/test/helpers/MaliciousContracts.sol +1 -1
- package/test/mock/MockBuybackCashOutRecorder.sol +2 -0
- package/test/mock/MockBuybackDataHook.sol +3 -1
- package/test/mock/MockBuybackDataHookMintPath.sol +2 -0
- package/test/mock/MockSuckerRegistry.sol +17 -0
- package/test/regression/TestBurnPermissionRequired.t.sol +16 -5
- package/test/regression/TestCashOutBuybackFeeLeak.t.sol +16 -3
- package/test/regression/TestCrossRevnetLiquidation.t.sol +14 -3
- package/test/regression/TestCumulativeLoanCounter.t.sol +15 -4
- package/test/regression/TestLiquidateGapHandling.t.sol +15 -4
- package/test/regression/TestZeroPriceFeed.t.sol +17 -6
|
@@ -36,11 +36,14 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
|
|
|
36
36
|
import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
|
|
37
37
|
import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
|
|
38
38
|
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
39
|
+
import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
|
|
40
|
+
import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
|
|
39
41
|
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
40
42
|
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
41
43
|
import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
|
|
42
44
|
import {REVOwner} from "../src/REVOwner.sol";
|
|
43
45
|
import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
|
|
46
|
+
import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
|
|
44
47
|
|
|
45
48
|
/// @notice Tests for PR #13: cross-source reallocation prevention.
|
|
46
49
|
contract TestCrossSourceReallocation is TestBaseWorkflow {
|
|
@@ -86,7 +89,14 @@ contract TestCrossSourceReallocation is TestBaseWorkflow {
|
|
|
86
89
|
SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
|
|
87
90
|
HOOK_STORE = new JB721TiersHookStore();
|
|
88
91
|
EXAMPLE_HOOK = new JB721TiersHook(
|
|
89
|
-
jbDirectory(),
|
|
92
|
+
jbDirectory(),
|
|
93
|
+
jbPermissions(),
|
|
94
|
+
jbPrices(),
|
|
95
|
+
jbRulesets(),
|
|
96
|
+
HOOK_STORE,
|
|
97
|
+
jbSplits(),
|
|
98
|
+
IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
|
|
99
|
+
multisig()
|
|
90
100
|
);
|
|
91
101
|
ADDRESS_REGISTRY = new JBAddressRegistry();
|
|
92
102
|
HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
|
|
@@ -99,7 +109,7 @@ contract TestCrossSourceReallocation is TestBaseWorkflow {
|
|
|
99
109
|
.addPriceFeedFor(0, uint32(uint160(address(TOKEN))), uint32(uint160(JBConstants.NATIVE_TOKEN)), priceFeed);
|
|
100
110
|
LOANS_CONTRACT = new REVLoans({
|
|
101
111
|
controller: jbController(),
|
|
102
|
-
|
|
112
|
+
suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
|
|
103
113
|
revId: FEE_PROJECT_ID,
|
|
104
114
|
owner: address(this),
|
|
105
115
|
permit2: permit2(),
|
|
@@ -110,7 +120,8 @@ contract TestCrossSourceReallocation is TestBaseWorkflow {
|
|
|
110
120
|
jbDirectory(),
|
|
111
121
|
FEE_PROJECT_ID,
|
|
112
122
|
SUCKER_REGISTRY,
|
|
113
|
-
address(LOANS_CONTRACT)
|
|
123
|
+
address(LOANS_CONTRACT),
|
|
124
|
+
address(0)
|
|
114
125
|
);
|
|
115
126
|
|
|
116
127
|
REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
|
|
@@ -246,7 +257,7 @@ contract TestCrossSourceReallocation is TestBaseWorkflow {
|
|
|
246
257
|
);
|
|
247
258
|
REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
|
|
248
259
|
vm.prank(user);
|
|
249
|
-
(loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee);
|
|
260
|
+
(loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee, user);
|
|
250
261
|
}
|
|
251
262
|
|
|
252
263
|
/// @notice Reallocating with the same source (token + terminal) should succeed.
|
|
@@ -38,6 +38,8 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
|
|
|
38
38
|
import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
|
|
39
39
|
import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
|
|
40
40
|
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
41
|
+
import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
|
|
42
|
+
import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
|
|
41
43
|
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
42
44
|
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
43
45
|
import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
|
|
@@ -45,6 +47,7 @@ import {ERC2771Forwarder} from "@openzeppelin/contracts/metatx/ERC2771Forwarder.
|
|
|
45
47
|
import {ERC2771ForwarderMock, ForwardRequest} from "@bananapus/core-v6/test/mock/ERC2771ForwarderMock.sol";
|
|
46
48
|
import {REVOwner} from "../src/REVOwner.sol";
|
|
47
49
|
import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
|
|
50
|
+
import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
|
|
48
51
|
|
|
49
52
|
struct MetaTxProjectConfig {
|
|
50
53
|
REVConfig configuration;
|
|
@@ -275,7 +278,14 @@ contract TestERC2771MetaTx is TestBaseWorkflow {
|
|
|
275
278
|
SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
|
|
276
279
|
HOOK_STORE = new JB721TiersHookStore();
|
|
277
280
|
EXAMPLE_HOOK = new JB721TiersHook(
|
|
278
|
-
jbDirectory(),
|
|
281
|
+
jbDirectory(),
|
|
282
|
+
jbPermissions(),
|
|
283
|
+
jbPrices(),
|
|
284
|
+
jbRulesets(),
|
|
285
|
+
HOOK_STORE,
|
|
286
|
+
jbSplits(),
|
|
287
|
+
IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
|
|
288
|
+
multisig()
|
|
279
289
|
);
|
|
280
290
|
ADDRESS_REGISTRY = new JBAddressRegistry();
|
|
281
291
|
HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
|
|
@@ -291,7 +301,7 @@ contract TestERC2771MetaTx is TestBaseWorkflow {
|
|
|
291
301
|
// Deploy LOANS_CONTRACT with the forwarder as trusted forwarder.
|
|
292
302
|
LOANS_CONTRACT = new REVLoans({
|
|
293
303
|
controller: jbController(),
|
|
294
|
-
|
|
304
|
+
suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
|
|
295
305
|
revId: FEE_PROJECT_ID,
|
|
296
306
|
owner: address(this),
|
|
297
307
|
permit2: permit2(),
|
|
@@ -303,7 +313,8 @@ contract TestERC2771MetaTx is TestBaseWorkflow {
|
|
|
303
313
|
jbDirectory(),
|
|
304
314
|
FEE_PROJECT_ID,
|
|
305
315
|
SUCKER_REGISTRY,
|
|
306
|
-
address(LOANS_CONTRACT)
|
|
316
|
+
address(LOANS_CONTRACT),
|
|
317
|
+
address(0)
|
|
307
318
|
);
|
|
308
319
|
|
|
309
320
|
REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
|
|
@@ -400,7 +411,8 @@ contract TestERC2771MetaTx is TestBaseWorkflow {
|
|
|
400
411
|
0, // minBorrowAmount
|
|
401
412
|
tokenCount,
|
|
402
413
|
payable(signerAddr),
|
|
403
|
-
uint256(25) // MIN_PREPAID_FEE_PERCENT
|
|
414
|
+
uint256(25), // MIN_PREPAID_FEE_PERCENT
|
|
415
|
+
signerAddr // holder
|
|
404
416
|
);
|
|
405
417
|
|
|
406
418
|
// Build the forwarded request signed by the signer.
|
|
@@ -448,7 +460,8 @@ contract TestERC2771MetaTx is TestBaseWorkflow {
|
|
|
448
460
|
REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
|
|
449
461
|
|
|
450
462
|
vm.prank(signerAddr);
|
|
451
|
-
(uint256 loanId,) =
|
|
463
|
+
(uint256 loanId,) =
|
|
464
|
+
LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(signerAddr), 25, signerAddr);
|
|
452
465
|
|
|
453
466
|
REVLoan memory loan = LOANS_CONTRACT.loanOf(loanId);
|
|
454
467
|
assertTrue(loan.amount > 0, "Loan should exist");
|
|
@@ -31,6 +31,8 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
|
|
|
31
31
|
import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
|
|
32
32
|
import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
|
|
33
33
|
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
34
|
+
import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
|
|
35
|
+
import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
|
|
34
36
|
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
35
37
|
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
36
38
|
import {JBBeforePayRecordedContext} from "@bananapus/core-v6/src/structs/JBBeforePayRecordedContext.sol";
|
|
@@ -39,6 +41,7 @@ import {JBTokenAmount} from "@bananapus/core-v6/src/structs/JBTokenAmount.sol";
|
|
|
39
41
|
import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
|
|
40
42
|
import {REVOwner} from "../src/REVOwner.sol";
|
|
41
43
|
import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
|
|
44
|
+
import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
|
|
42
45
|
|
|
43
46
|
/// @notice Regression tests for the empty buyback hook specifications fix.
|
|
44
47
|
/// When JBBuybackHook determines minting is cheaper than swapping, it returns an empty
|
|
@@ -82,7 +85,14 @@ contract TestEmptyBuybackSpecs is TestBaseWorkflow {
|
|
|
82
85
|
SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
|
|
83
86
|
HOOK_STORE = new JB721TiersHookStore();
|
|
84
87
|
EXAMPLE_HOOK = new JB721TiersHook(
|
|
85
|
-
jbDirectory(),
|
|
88
|
+
jbDirectory(),
|
|
89
|
+
jbPermissions(),
|
|
90
|
+
jbPrices(),
|
|
91
|
+
jbRulesets(),
|
|
92
|
+
HOOK_STORE,
|
|
93
|
+
jbSplits(),
|
|
94
|
+
IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
|
|
95
|
+
multisig()
|
|
86
96
|
);
|
|
87
97
|
ADDRESS_REGISTRY = new JBAddressRegistry();
|
|
88
98
|
HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
|
|
@@ -90,7 +100,7 @@ contract TestEmptyBuybackSpecs is TestBaseWorkflow {
|
|
|
90
100
|
MOCK_BUYBACK_MINT_PATH = new MockBuybackDataHookMintPath();
|
|
91
101
|
LOANS_CONTRACT = new REVLoans({
|
|
92
102
|
controller: jbController(),
|
|
93
|
-
|
|
103
|
+
suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
|
|
94
104
|
revId: FEE_PROJECT_ID,
|
|
95
105
|
owner: address(this),
|
|
96
106
|
permit2: permit2(),
|
|
@@ -101,7 +111,8 @@ contract TestEmptyBuybackSpecs is TestBaseWorkflow {
|
|
|
101
111
|
jbDirectory(),
|
|
102
112
|
FEE_PROJECT_ID,
|
|
103
113
|
SUCKER_REGISTRY,
|
|
104
|
-
address(LOANS_CONTRACT)
|
|
114
|
+
address(LOANS_CONTRACT),
|
|
115
|
+
address(0)
|
|
105
116
|
);
|
|
106
117
|
|
|
107
118
|
REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
|
|
@@ -36,10 +36,13 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
|
|
|
36
36
|
import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
|
|
37
37
|
import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
|
|
38
38
|
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
39
|
+
import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
|
|
40
|
+
import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
|
|
39
41
|
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
40
42
|
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
41
43
|
import {REVOwner} from "../src/REVOwner.sol";
|
|
42
44
|
import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
|
|
45
|
+
import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
|
|
43
46
|
|
|
44
47
|
/// @notice Tests showing that flash loan surplus manipulation is economically unprofitable.
|
|
45
48
|
contract TestFlashLoanSurplus is TestBaseWorkflow {
|
|
@@ -89,7 +92,14 @@ contract TestFlashLoanSurplus is TestBaseWorkflow {
|
|
|
89
92
|
SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
|
|
90
93
|
HOOK_STORE = new JB721TiersHookStore();
|
|
91
94
|
EXAMPLE_HOOK = new JB721TiersHook(
|
|
92
|
-
jbDirectory(),
|
|
95
|
+
jbDirectory(),
|
|
96
|
+
jbPermissions(),
|
|
97
|
+
jbPrices(),
|
|
98
|
+
jbRulesets(),
|
|
99
|
+
HOOK_STORE,
|
|
100
|
+
jbSplits(),
|
|
101
|
+
IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
|
|
102
|
+
multisig()
|
|
93
103
|
);
|
|
94
104
|
ADDRESS_REGISTRY = new JBAddressRegistry();
|
|
95
105
|
HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
|
|
@@ -102,7 +112,7 @@ contract TestFlashLoanSurplus is TestBaseWorkflow {
|
|
|
102
112
|
.addPriceFeedFor(0, uint32(uint160(address(TOKEN))), uint32(uint160(JBConstants.NATIVE_TOKEN)), priceFeed);
|
|
103
113
|
LOANS_CONTRACT = new REVLoans({
|
|
104
114
|
controller: jbController(),
|
|
105
|
-
|
|
115
|
+
suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
|
|
106
116
|
revId: FEE_PROJECT_ID,
|
|
107
117
|
owner: address(this),
|
|
108
118
|
permit2: permit2(),
|
|
@@ -113,7 +123,8 @@ contract TestFlashLoanSurplus is TestBaseWorkflow {
|
|
|
113
123
|
jbDirectory(),
|
|
114
124
|
FEE_PROJECT_ID,
|
|
115
125
|
SUCKER_REGISTRY,
|
|
116
|
-
address(LOANS_CONTRACT)
|
|
126
|
+
address(LOANS_CONTRACT),
|
|
127
|
+
address(0)
|
|
117
128
|
);
|
|
118
129
|
|
|
119
130
|
REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
|
|
@@ -250,7 +261,7 @@ contract TestFlashLoanSurplus is TestBaseWorkflow {
|
|
|
250
261
|
);
|
|
251
262
|
REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
|
|
252
263
|
vm.prank(user);
|
|
253
|
-
(loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee);
|
|
264
|
+
(loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee, user);
|
|
254
265
|
}
|
|
255
266
|
|
|
256
267
|
/// @notice Donate ETH via addToBalanceOf, then borrow. The donation costs more than the extra borrowable amount.
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.28;
|
|
3
|
+
|
|
4
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
5
|
+
import "forge-std/Test.sol";
|
|
6
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
7
|
+
import /* {*} from */ "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
8
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
9
|
+
import /* {*} from */ "./../src/REVDeployer.sol";
|
|
10
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
11
|
+
import "@croptop/core-v6/src/CTPublisher.sol";
|
|
12
|
+
import {MockBuybackDataHook} from "./mock/MockBuybackDataHook.sol";
|
|
13
|
+
import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
|
|
14
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
15
|
+
import "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
|
|
16
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
17
|
+
import "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
|
|
18
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
19
|
+
import "@bananapus/suckers-v6/script/helpers/SuckerDeploymentLib.sol";
|
|
20
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
21
|
+
import "@croptop/core-v6/script/helpers/CroptopDeploymentLib.sol";
|
|
22
|
+
// forge-lint: disable-next-line(unaliased-plain-import)
|
|
23
|
+
import "@bananapus/router-terminal-v6/script/helpers/RouterTerminalDeploymentLib.sol";
|
|
24
|
+
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
25
|
+
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
26
|
+
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
27
|
+
import {JBPermissionsData} from "@bananapus/core-v6/src/structs/JBPermissionsData.sol";
|
|
28
|
+
import {MockERC20} from "@bananapus/core-v6/test/mock/MockERC20.sol";
|
|
29
|
+
import {REVLoans} from "../src/REVLoans.sol";
|
|
30
|
+
import {REVHiddenTokens} from "../src/REVHiddenTokens.sol";
|
|
31
|
+
import {IREVHiddenTokens} from "../src/interfaces/IREVHiddenTokens.sol";
|
|
32
|
+
import {REVStageConfig, REVAutoIssuance} from "../src/structs/REVStageConfig.sol";
|
|
33
|
+
import {REVDescription} from "../src/structs/REVDescription.sol";
|
|
34
|
+
import {IREVLoans} from "./../src/interfaces/IREVLoans.sol";
|
|
35
|
+
import {JBSuckerDeployerConfig} from "@bananapus/suckers-v6/src/structs/JBSuckerDeployerConfig.sol";
|
|
36
|
+
import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
|
|
37
|
+
import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
|
|
38
|
+
import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
|
|
39
|
+
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
40
|
+
import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
|
|
41
|
+
import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
|
|
42
|
+
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
43
|
+
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
44
|
+
import {REVOwner} from "../src/REVOwner.sol";
|
|
45
|
+
import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
|
|
46
|
+
import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
|
|
47
|
+
|
|
48
|
+
/// @notice Tests for the standalone REVHiddenTokens contract.
|
|
49
|
+
contract TestHiddenTokens is TestBaseWorkflow {
|
|
50
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
51
|
+
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
52
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
53
|
+
bytes32 ERC20_SALT = "REV_TOKEN";
|
|
54
|
+
|
|
55
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
56
|
+
REVDeployer REV_DEPLOYER;
|
|
57
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
58
|
+
REVOwner REV_OWNER;
|
|
59
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
60
|
+
JB721TiersHook EXAMPLE_HOOK;
|
|
61
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
62
|
+
IJB721TiersHookDeployer HOOK_DEPLOYER;
|
|
63
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
64
|
+
IJB721TiersHookStore HOOK_STORE;
|
|
65
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
66
|
+
IJBAddressRegistry ADDRESS_REGISTRY;
|
|
67
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
68
|
+
IREVLoans LOANS_CONTRACT;
|
|
69
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
70
|
+
REVHiddenTokens HIDDEN_TOKENS;
|
|
71
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
72
|
+
IJBSuckerRegistry SUCKER_REGISTRY;
|
|
73
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
74
|
+
CTPublisher PUBLISHER;
|
|
75
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
76
|
+
MockBuybackDataHook MOCK_BUYBACK;
|
|
77
|
+
|
|
78
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
79
|
+
uint256 FEE_PROJECT_ID;
|
|
80
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
81
|
+
uint256 REVNET_ID;
|
|
82
|
+
|
|
83
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
84
|
+
address USER = makeAddr("user");
|
|
85
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
86
|
+
address BENEFICIARY = makeAddr("beneficiary");
|
|
87
|
+
|
|
88
|
+
address private constant TRUSTED_FORWARDER = 0xB2b5841DBeF766d4b521221732F9B618fCf34A87;
|
|
89
|
+
|
|
90
|
+
function setUp() public override {
|
|
91
|
+
super.setUp();
|
|
92
|
+
FEE_PROJECT_ID = jbProjects().createFor(multisig());
|
|
93
|
+
SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
|
|
94
|
+
HOOK_STORE = new JB721TiersHookStore();
|
|
95
|
+
EXAMPLE_HOOK = new JB721TiersHook(
|
|
96
|
+
jbDirectory(),
|
|
97
|
+
jbPermissions(),
|
|
98
|
+
jbPrices(),
|
|
99
|
+
jbRulesets(),
|
|
100
|
+
HOOK_STORE,
|
|
101
|
+
jbSplits(),
|
|
102
|
+
IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
|
|
103
|
+
multisig()
|
|
104
|
+
);
|
|
105
|
+
ADDRESS_REGISTRY = new JBAddressRegistry();
|
|
106
|
+
HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
|
|
107
|
+
PUBLISHER = new CTPublisher(jbDirectory(), jbPermissions(), FEE_PROJECT_ID, multisig());
|
|
108
|
+
MOCK_BUYBACK = new MockBuybackDataHook();
|
|
109
|
+
|
|
110
|
+
LOANS_CONTRACT = new REVLoans({
|
|
111
|
+
controller: jbController(),
|
|
112
|
+
suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
|
|
113
|
+
revId: FEE_PROJECT_ID,
|
|
114
|
+
owner: address(this),
|
|
115
|
+
permit2: permit2(),
|
|
116
|
+
trustedForwarder: TRUSTED_FORWARDER
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
HIDDEN_TOKENS = new REVHiddenTokens(jbController(), TRUSTED_FORWARDER);
|
|
120
|
+
|
|
121
|
+
REV_OWNER = new REVOwner(
|
|
122
|
+
IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
|
|
123
|
+
jbDirectory(),
|
|
124
|
+
FEE_PROJECT_ID,
|
|
125
|
+
SUCKER_REGISTRY,
|
|
126
|
+
address(LOANS_CONTRACT),
|
|
127
|
+
address(HIDDEN_TOKENS)
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
|
|
131
|
+
jbController(),
|
|
132
|
+
SUCKER_REGISTRY,
|
|
133
|
+
FEE_PROJECT_ID,
|
|
134
|
+
HOOK_DEPLOYER,
|
|
135
|
+
PUBLISHER,
|
|
136
|
+
IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
|
|
137
|
+
address(LOANS_CONTRACT),
|
|
138
|
+
TRUSTED_FORWARDER,
|
|
139
|
+
address(REV_OWNER)
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
REV_OWNER.setDeployer(REV_DEPLOYER);
|
|
143
|
+
|
|
144
|
+
vm.prank(multisig());
|
|
145
|
+
jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
|
|
146
|
+
_deployFeeProject();
|
|
147
|
+
REVNET_ID = _deployRevnet();
|
|
148
|
+
vm.deal(USER, 100e18);
|
|
149
|
+
_grantBurnPermission(USER, REVNET_ID);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ──────────────────── Test: Hiding reduces totalSupply
|
|
153
|
+
// ────────────────────
|
|
154
|
+
|
|
155
|
+
function test_hideTokens_reducesTotalSupply() public {
|
|
156
|
+
// Pay to get tokens.
|
|
157
|
+
uint256 payAmount = 10e18;
|
|
158
|
+
vm.prank(USER);
|
|
159
|
+
jbMultiTerminal().pay{value: payAmount}({
|
|
160
|
+
projectId: REVNET_ID,
|
|
161
|
+
token: JBConstants.NATIVE_TOKEN,
|
|
162
|
+
amount: payAmount,
|
|
163
|
+
beneficiary: USER,
|
|
164
|
+
minReturnedTokens: 0,
|
|
165
|
+
memo: "",
|
|
166
|
+
metadata: ""
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
uint256 userTokens = jbController().TOKENS().totalBalanceOf(USER, REVNET_ID);
|
|
170
|
+
assertGt(userTokens, 0, "User should have tokens after paying");
|
|
171
|
+
|
|
172
|
+
uint256 totalSupplyBefore = jbController().TOKENS().totalSupplyOf(REVNET_ID);
|
|
173
|
+
|
|
174
|
+
// Hide half the tokens.
|
|
175
|
+
uint256 hideCount = userTokens / 2;
|
|
176
|
+
vm.prank(USER);
|
|
177
|
+
HIDDEN_TOKENS.hideTokensOf(REVNET_ID, hideCount, USER);
|
|
178
|
+
|
|
179
|
+
uint256 totalSupplyAfter = jbController().TOKENS().totalSupplyOf(REVNET_ID);
|
|
180
|
+
assertEq(totalSupplyAfter, totalSupplyBefore - hideCount, "Total supply should decrease by hidden amount");
|
|
181
|
+
assertEq(HIDDEN_TOKENS.hiddenBalanceOf(USER, REVNET_ID), hideCount, "Hidden balance should match");
|
|
182
|
+
assertEq(HIDDEN_TOKENS.totalHiddenOf(REVNET_ID), hideCount, "Total hidden should match");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ──────────────────── Test: Revealing restores tokens
|
|
186
|
+
// ────────────────────
|
|
187
|
+
|
|
188
|
+
function test_revealTokens_restoresTokens() public {
|
|
189
|
+
// Pay to get tokens.
|
|
190
|
+
uint256 payAmount = 10e18;
|
|
191
|
+
vm.prank(USER);
|
|
192
|
+
jbMultiTerminal().pay{value: payAmount}({
|
|
193
|
+
projectId: REVNET_ID,
|
|
194
|
+
token: JBConstants.NATIVE_TOKEN,
|
|
195
|
+
amount: payAmount,
|
|
196
|
+
beneficiary: USER,
|
|
197
|
+
minReturnedTokens: 0,
|
|
198
|
+
memo: "",
|
|
199
|
+
metadata: ""
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
uint256 userTokensBefore = jbController().TOKENS().totalBalanceOf(USER, REVNET_ID);
|
|
203
|
+
uint256 totalSupplyBefore = jbController().TOKENS().totalSupplyOf(REVNET_ID);
|
|
204
|
+
|
|
205
|
+
// Hide tokens.
|
|
206
|
+
uint256 hideCount = userTokensBefore / 2;
|
|
207
|
+
vm.prank(USER);
|
|
208
|
+
HIDDEN_TOKENS.hideTokensOf(REVNET_ID, hideCount, USER);
|
|
209
|
+
|
|
210
|
+
// Reveal tokens to beneficiary.
|
|
211
|
+
vm.prank(USER);
|
|
212
|
+
HIDDEN_TOKENS.revealTokensOf(REVNET_ID, hideCount, BENEFICIARY, USER);
|
|
213
|
+
|
|
214
|
+
uint256 totalSupplyAfter = jbController().TOKENS().totalSupplyOf(REVNET_ID);
|
|
215
|
+
assertEq(totalSupplyAfter, totalSupplyBefore, "Total supply should be restored");
|
|
216
|
+
assertEq(HIDDEN_TOKENS.hiddenBalanceOf(USER, REVNET_ID), 0, "Hidden balance should be zero");
|
|
217
|
+
assertEq(HIDDEN_TOKENS.totalHiddenOf(REVNET_ID), 0, "Total hidden should be zero");
|
|
218
|
+
assertEq(
|
|
219
|
+
jbController().TOKENS().totalBalanceOf(BENEFICIARY, REVNET_ID),
|
|
220
|
+
hideCount,
|
|
221
|
+
"Beneficiary should receive tokens"
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ──────────────────── Test: Insufficient hidden balance reverts
|
|
226
|
+
// ────────────────────
|
|
227
|
+
|
|
228
|
+
function test_revealTokens_revertsOnInsufficientBalance() public {
|
|
229
|
+
// Pay to get tokens.
|
|
230
|
+
uint256 payAmount = 10e18;
|
|
231
|
+
vm.prank(USER);
|
|
232
|
+
jbMultiTerminal().pay{value: payAmount}({
|
|
233
|
+
projectId: REVNET_ID,
|
|
234
|
+
token: JBConstants.NATIVE_TOKEN,
|
|
235
|
+
amount: payAmount,
|
|
236
|
+
beneficiary: USER,
|
|
237
|
+
minReturnedTokens: 0,
|
|
238
|
+
memo: "",
|
|
239
|
+
metadata: ""
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
uint256 userTokens = jbController().TOKENS().totalBalanceOf(USER, REVNET_ID);
|
|
243
|
+
uint256 hideCount = userTokens / 4;
|
|
244
|
+
|
|
245
|
+
// Hide some tokens.
|
|
246
|
+
vm.prank(USER);
|
|
247
|
+
HIDDEN_TOKENS.hideTokensOf(REVNET_ID, hideCount, USER);
|
|
248
|
+
|
|
249
|
+
// Try to reveal more than hidden — should revert.
|
|
250
|
+
vm.prank(USER);
|
|
251
|
+
vm.expectRevert(
|
|
252
|
+
abi.encodeWithSelector(
|
|
253
|
+
REVHiddenTokens.REVHiddenTokens_InsufficientHiddenBalance.selector, hideCount, hideCount + 1
|
|
254
|
+
)
|
|
255
|
+
);
|
|
256
|
+
HIDDEN_TOKENS.revealTokensOf(REVNET_ID, hideCount + 1, USER, USER);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// ──────────────────── Test: Hidden tokens inflate cash out rate
|
|
260
|
+
// ────────────────────
|
|
261
|
+
|
|
262
|
+
function test_hiddenTokens_inflateCashOutRate() public {
|
|
263
|
+
// Pay to get tokens for 2 users.
|
|
264
|
+
uint256 payAmount = 10e18;
|
|
265
|
+
vm.prank(USER);
|
|
266
|
+
jbMultiTerminal().pay{value: payAmount}({
|
|
267
|
+
projectId: REVNET_ID,
|
|
268
|
+
token: JBConstants.NATIVE_TOKEN,
|
|
269
|
+
amount: payAmount,
|
|
270
|
+
beneficiary: USER,
|
|
271
|
+
minReturnedTokens: 0,
|
|
272
|
+
memo: "",
|
|
273
|
+
metadata: ""
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
uint256 userTokens = jbController().TOKENS().totalBalanceOf(USER, REVNET_ID);
|
|
277
|
+
|
|
278
|
+
// Hide half the user's tokens.
|
|
279
|
+
uint256 hideCount = userTokens / 2;
|
|
280
|
+
vm.prank(USER);
|
|
281
|
+
HIDDEN_TOKENS.hideTokensOf(REVNET_ID, hideCount, USER);
|
|
282
|
+
|
|
283
|
+
// The remaining tokens now represent a larger share of totalSupply.
|
|
284
|
+
uint256 totalSupply = jbController().TOKENS().totalSupplyOf(REVNET_ID);
|
|
285
|
+
uint256 remainingBalance = jbController().TOKENS().totalBalanceOf(USER, REVNET_ID);
|
|
286
|
+
assertEq(remainingBalance, userTokens - hideCount, "Remaining balance should be half");
|
|
287
|
+
assertEq(totalSupply, userTokens - hideCount, "Total supply should equal remaining balance");
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ──────────────────── Test: Events emitted correctly
|
|
291
|
+
// ────────────────────
|
|
292
|
+
|
|
293
|
+
function test_hideTokens_emitsEvent() public {
|
|
294
|
+
uint256 payAmount = 10e18;
|
|
295
|
+
vm.prank(USER);
|
|
296
|
+
jbMultiTerminal().pay{value: payAmount}({
|
|
297
|
+
projectId: REVNET_ID,
|
|
298
|
+
token: JBConstants.NATIVE_TOKEN,
|
|
299
|
+
amount: payAmount,
|
|
300
|
+
beneficiary: USER,
|
|
301
|
+
minReturnedTokens: 0,
|
|
302
|
+
memo: "",
|
|
303
|
+
metadata: ""
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
uint256 userTokens = jbController().TOKENS().totalBalanceOf(USER, REVNET_ID);
|
|
307
|
+
|
|
308
|
+
vm.prank(USER);
|
|
309
|
+
vm.expectEmit(true, false, false, true);
|
|
310
|
+
emit IREVHiddenTokens.HideTokens(REVNET_ID, userTokens, USER, USER);
|
|
311
|
+
HIDDEN_TOKENS.hideTokensOf(REVNET_ID, userTokens, USER);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function test_revealTokens_emitsEvent() public {
|
|
315
|
+
uint256 payAmount = 10e18;
|
|
316
|
+
vm.prank(USER);
|
|
317
|
+
jbMultiTerminal().pay{value: payAmount}({
|
|
318
|
+
projectId: REVNET_ID,
|
|
319
|
+
token: JBConstants.NATIVE_TOKEN,
|
|
320
|
+
amount: payAmount,
|
|
321
|
+
beneficiary: USER,
|
|
322
|
+
minReturnedTokens: 0,
|
|
323
|
+
memo: "",
|
|
324
|
+
metadata: ""
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
uint256 userTokens = jbController().TOKENS().totalBalanceOf(USER, REVNET_ID);
|
|
328
|
+
|
|
329
|
+
vm.prank(USER);
|
|
330
|
+
HIDDEN_TOKENS.hideTokensOf(REVNET_ID, userTokens, USER);
|
|
331
|
+
|
|
332
|
+
vm.prank(USER);
|
|
333
|
+
vm.expectEmit(true, false, false, true);
|
|
334
|
+
emit IREVHiddenTokens.RevealTokens(REVNET_ID, userTokens, BENEFICIARY, USER, USER);
|
|
335
|
+
HIDDEN_TOKENS.revealTokensOf(REVNET_ID, userTokens, BENEFICIARY, USER);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// ──────────────────── Internal helpers
|
|
339
|
+
// ────────────────────
|
|
340
|
+
|
|
341
|
+
function _grantBurnPermission(address account, uint256 revnetId) internal {
|
|
342
|
+
uint8[] memory permissionIds = new uint8[](1);
|
|
343
|
+
permissionIds[0] = JBPermissionIds.BURN_TOKENS;
|
|
344
|
+
JBPermissionsData memory permissionsData = JBPermissionsData({
|
|
345
|
+
operator: address(HIDDEN_TOKENS),
|
|
346
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
347
|
+
projectId: uint56(revnetId),
|
|
348
|
+
permissionIds: permissionIds
|
|
349
|
+
});
|
|
350
|
+
vm.prank(account);
|
|
351
|
+
jbPermissions().setPermissionsFor(account, permissionsData);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function _deployFeeProject() internal {
|
|
355
|
+
JBAccountingContext[] memory acc = new JBAccountingContext[](1);
|
|
356
|
+
acc[0] = JBAccountingContext({
|
|
357
|
+
token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
358
|
+
});
|
|
359
|
+
JBTerminalConfig[] memory tc = new JBTerminalConfig[](1);
|
|
360
|
+
tc[0] = JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: acc});
|
|
361
|
+
REVStageConfig[] memory stages = new REVStageConfig[](1);
|
|
362
|
+
stages[0] = REVStageConfig({
|
|
363
|
+
startsAtOrAfter: uint48(block.timestamp),
|
|
364
|
+
autoIssuances: new REVAutoIssuance[](0),
|
|
365
|
+
splitPercent: 0,
|
|
366
|
+
splits: new JBSplit[](0),
|
|
367
|
+
initialIssuance: uint112(1000e18),
|
|
368
|
+
issuanceCutFrequency: 0,
|
|
369
|
+
issuanceCutPercent: 0,
|
|
370
|
+
cashOutTaxRate: 0,
|
|
371
|
+
extraMetadata: 0
|
|
372
|
+
});
|
|
373
|
+
// forge-lint: disable-next-line(named-struct-fields)
|
|
374
|
+
REVConfig memory feeConfig = REVConfig({
|
|
375
|
+
description: REVDescription("Fee Revnet", "FEE", "", ERC20_SALT),
|
|
376
|
+
baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
377
|
+
splitOperator: multisig(),
|
|
378
|
+
stageConfigurations: stages
|
|
379
|
+
});
|
|
380
|
+
vm.prank(multisig());
|
|
381
|
+
REV_DEPLOYER.deployFor({
|
|
382
|
+
revnetId: FEE_PROJECT_ID,
|
|
383
|
+
configuration: feeConfig,
|
|
384
|
+
terminalConfigurations: tc,
|
|
385
|
+
suckerDeploymentConfiguration: REVSuckerDeploymentConfig({
|
|
386
|
+
deployerConfigurations: new JBSuckerDeployerConfig[](0), salt: keccak256("FEE")
|
|
387
|
+
}),
|
|
388
|
+
tiered721HookConfiguration: REVEmpty721Config.empty721Config(uint32(uint160(JBConstants.NATIVE_TOKEN))),
|
|
389
|
+
allowedPosts: REVEmpty721Config.emptyAllowedPosts()
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function _deployRevnet() internal returns (uint256) {
|
|
394
|
+
JBAccountingContext[] memory acc = new JBAccountingContext[](1);
|
|
395
|
+
acc[0] = JBAccountingContext({
|
|
396
|
+
token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
397
|
+
});
|
|
398
|
+
JBTerminalConfig[] memory tc = new JBTerminalConfig[](1);
|
|
399
|
+
tc[0] = JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: acc});
|
|
400
|
+
REVStageConfig[] memory stages = new REVStageConfig[](1);
|
|
401
|
+
stages[0] = REVStageConfig({
|
|
402
|
+
startsAtOrAfter: uint48(block.timestamp),
|
|
403
|
+
autoIssuances: new REVAutoIssuance[](0),
|
|
404
|
+
splitPercent: 0,
|
|
405
|
+
splits: new JBSplit[](0),
|
|
406
|
+
initialIssuance: uint112(1000e18),
|
|
407
|
+
issuanceCutFrequency: 0,
|
|
408
|
+
issuanceCutPercent: 0,
|
|
409
|
+
cashOutTaxRate: 5000, // 50% cash out tax rate
|
|
410
|
+
extraMetadata: 0
|
|
411
|
+
});
|
|
412
|
+
// forge-lint: disable-next-line(named-struct-fields)
|
|
413
|
+
REVConfig memory revConfig = REVConfig({
|
|
414
|
+
description: REVDescription("Test Revnet", "TEST", "", bytes32("TEST_TOKEN")),
|
|
415
|
+
baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
416
|
+
splitOperator: multisig(),
|
|
417
|
+
stageConfigurations: stages
|
|
418
|
+
});
|
|
419
|
+
(uint256 revnetId,) = REV_DEPLOYER.deployFor({
|
|
420
|
+
revnetId: 0,
|
|
421
|
+
configuration: revConfig,
|
|
422
|
+
terminalConfigurations: tc,
|
|
423
|
+
suckerDeploymentConfiguration: REVSuckerDeploymentConfig({
|
|
424
|
+
deployerConfigurations: new JBSuckerDeployerConfig[](0), salt: keccak256("NANA")
|
|
425
|
+
}),
|
|
426
|
+
tiered721HookConfiguration: REVEmpty721Config.empty721Config(uint32(uint160(JBConstants.NATIVE_TOKEN))),
|
|
427
|
+
allowedPosts: REVEmpty721Config.emptyAllowedPosts()
|
|
428
|
+
});
|
|
429
|
+
return revnetId;
|
|
430
|
+
}
|
|
431
|
+
}
|