@rev-net/core-v6 0.0.11 → 0.0.13
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 +7 -7
- package/ARCHITECTURE.md +11 -11
- package/AUDIT_INSTRUCTIONS.md +295 -0
- package/CHANGE_LOG.md +316 -0
- package/README.md +9 -6
- package/RISKS.md +180 -35
- package/SKILLS.md +9 -11
- package/STYLE_GUIDE.md +14 -1
- package/USER_JOURNEYS.md +489 -0
- package/package.json +9 -9
- package/script/Deploy.s.sol +124 -40
- package/script/helpers/RevnetCoreDeploymentLib.sol +19 -6
- package/src/REVDeployer.sol +183 -175
- package/src/REVLoans.sol +65 -28
- package/src/interfaces/IREVDeployer.sol +25 -23
- package/src/structs/REV721TiersHookFlags.sol +1 -0
- package/src/structs/REVAutoIssuance.sol +1 -0
- package/src/structs/REVBaseline721HookConfig.sol +1 -0
- package/src/structs/REVConfig.sol +1 -0
- package/src/structs/REVCroptopAllowedPost.sol +1 -0
- package/src/structs/REVDeploy721TiersHookConfig.sol +13 -14
- package/src/structs/REVDescription.sol +1 -0
- package/src/structs/REVLoan.sol +1 -0
- package/src/structs/REVLoanSource.sol +1 -0
- package/src/structs/REVStageConfig.sol +1 -0
- package/src/structs/REVSuckerDeploymentConfig.sol +1 -0
- package/test/REV.integrations.t.sol +148 -19
- package/test/REVAutoIssuanceFuzz.t.sol +31 -6
- package/test/REVDeployerRegressions.t.sol +47 -9
- package/test/REVInvincibility.t.sol +83 -19
- package/test/REVInvincibilityHandler.sol +29 -0
- package/test/REVLifecycle.t.sol +36 -6
- package/test/REVLoans.invariants.t.sol +64 -10
- package/test/REVLoansAttacks.t.sol +54 -9
- package/test/REVLoansFeeRecovery.t.sol +61 -15
- package/test/REVLoansFindings.t.sol +42 -9
- package/test/REVLoansRegressions.t.sol +33 -6
- package/test/REVLoansSourceFeeRecovery.t.sol +491 -0
- package/test/REVLoansSourced.t.sol +79 -17
- package/test/REVLoansUnSourced.t.sol +61 -10
- package/test/TestBurnHeldTokens.t.sol +47 -11
- package/test/TestCEIPattern.t.sol +37 -6
- package/test/TestCashOutCallerValidation.t.sol +41 -8
- package/test/TestConversionDocumentation.t.sol +50 -13
- package/test/TestCrossCurrencyReclaim.t.sol +584 -0
- package/test/TestCrossSourceReallocation.t.sol +37 -6
- package/test/TestERC2771MetaTx.t.sol +557 -0
- package/test/TestEmptyBuybackSpecs.t.sol +45 -10
- package/test/TestFlashLoanSurplus.t.sol +39 -7
- package/test/TestHookArrayOOB.t.sol +42 -13
- package/test/TestLiquidationBehavior.t.sol +37 -7
- package/test/TestLoanSourceRotation.t.sol +525 -0
- package/test/TestLongTailEconomics.t.sol +651 -0
- package/test/TestLowFindings.t.sol +80 -8
- package/test/TestMixedFixes.t.sol +43 -9
- package/test/TestPermit2Signatures.t.sol +657 -0
- package/test/TestReallocationSandwich.t.sol +384 -0
- package/test/TestRevnetRegressions.t.sol +324 -0
- package/test/TestSplitWeightAdjustment.t.sol +52 -13
- package/test/TestSplitWeightE2E.t.sol +53 -18
- package/test/TestSplitWeightFork.t.sol +66 -21
- package/test/TestStageTransitionBorrowable.t.sol +38 -6
- package/test/TestSwapTerminalPermission.t.sol +37 -7
- package/test/TestUint112Overflow.t.sol +39 -6
- package/test/TestZeroRepayment.t.sol +37 -6
- package/test/fork/ForkTestBase.sol +66 -17
- package/test/fork/TestCashOutFork.t.sol +9 -3
- package/test/fork/TestLoanBorrowFork.t.sol +1 -0
- package/test/fork/TestLoanCrossRulesetFork.t.sol +11 -3
- package/test/fork/TestLoanLiquidationFork.t.sol +1 -0
- package/test/fork/TestLoanReallocateFork.t.sol +1 -0
- package/test/fork/TestLoanRepayFork.t.sol +1 -0
- package/test/fork/TestLoanTransferFork.t.sol +133 -0
- package/test/fork/TestSplitWeightFork.t.sol +3 -0
- package/test/helpers/REVEmpty721Config.sol +46 -0
- package/test/mock/MockBuybackDataHook.sol +1 -0
- package/test/regression/TestBurnPermissionRequired.t.sol +267 -0
- package/test/regression/TestCrossRevnetLiquidation.t.sol +228 -0
- package/test/regression/TestCumulativeLoanCounter.t.sol +38 -8
- package/test/regression/TestLiquidateGapHandling.t.sol +40 -8
- package/test/regression/TestZeroPriceFeed.t.sol +396 -0
package/src/REVDeployer.sol
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity 0.8.26;
|
|
3
3
|
|
|
4
|
-
import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
|
|
5
|
-
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
6
|
-
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
7
|
-
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|
8
|
-
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
|
|
9
|
-
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
10
4
|
import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
|
|
11
5
|
import {IJB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookDeployer.sol";
|
|
12
6
|
import {JB721TiersHookFlags} from "@bananapus/721-hook-v6/src/structs/JB721TiersHookFlags.sol";
|
|
@@ -15,13 +9,11 @@ import {IJBBuybackHookRegistry} from "@bananapus/buyback-hook-v6/src/interfaces/
|
|
|
15
9
|
import {IJBCashOutHook} from "@bananapus/core-v6/src/interfaces/IJBCashOutHook.sol";
|
|
16
10
|
import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
17
11
|
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
18
|
-
import {IJBPayHook} from "@bananapus/core-v6/src/interfaces/IJBPayHook.sol";
|
|
19
12
|
import {IJBPermissioned} from "@bananapus/core-v6/src/interfaces/IJBPermissioned.sol";
|
|
20
13
|
import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
|
|
21
14
|
import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
|
|
22
15
|
import {IJBRulesetApprovalHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetApprovalHook.sol";
|
|
23
16
|
import {IJBRulesetDataHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetDataHook.sol";
|
|
24
|
-
import {IJBSplitHook} from "@bananapus/core-v6/src/interfaces/IJBSplitHook.sol";
|
|
25
17
|
import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
|
|
26
18
|
import {JBCashOuts} from "@bananapus/core-v6/src/libraries/JBCashOuts.sol";
|
|
27
19
|
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
@@ -38,14 +30,18 @@ import {JBPermissionsData} from "@bananapus/core-v6/src/structs/JBPermissionsDat
|
|
|
38
30
|
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
39
31
|
import {JBRulesetConfig} from "@bananapus/core-v6/src/structs/JBRulesetConfig.sol";
|
|
40
32
|
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
41
|
-
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
42
|
-
import {JBTokenAmount} from "@bananapus/core-v6/src/structs/JBTokenAmount.sol";
|
|
43
33
|
import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
|
|
44
34
|
import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
|
|
45
35
|
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
46
36
|
import {IJBSuckerRegistry} from "@bananapus/suckers-v6/src/interfaces/IJBSuckerRegistry.sol";
|
|
47
37
|
import {CTPublisher} from "@croptop/core-v6/src/CTPublisher.sol";
|
|
48
38
|
import {CTAllowedPost} from "@croptop/core-v6/src/structs/CTAllowedPost.sol";
|
|
39
|
+
import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
|
|
40
|
+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
41
|
+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
42
|
+
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|
43
|
+
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
|
|
44
|
+
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
49
45
|
|
|
50
46
|
import {IREVDeployer} from "./interfaces/IREVDeployer.sol";
|
|
51
47
|
import {REVAutoIssuance} from "./structs/REVAutoIssuance.sol";
|
|
@@ -224,6 +220,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
224
220
|
});
|
|
225
221
|
|
|
226
222
|
// Give the loan contract permission to use the surplus allowance of all revnets.
|
|
223
|
+
// Uses wildcard revnetId=0 intentionally — the loan contract is a singleton shared by all revnets,
|
|
224
|
+
// and each revnet's surplus allowance limits already constrain how much can be drawn.
|
|
227
225
|
_setPermission({operator: LOANS, revnetId: 0, permissionId: JBPermissionIds.USE_ALLOWANCE});
|
|
228
226
|
|
|
229
227
|
// Give the buyback hook (registry) permission to configure pools on all revnets.
|
|
@@ -255,6 +253,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
255
253
|
)
|
|
256
254
|
{
|
|
257
255
|
// If the cash out is from a sucker, return the full cash out amount without taxes or fees.
|
|
256
|
+
// This relies on the sucker registry to only contain trusted sucker contracts deployed via
|
|
257
|
+
// the registry's own deploySuckersFor flow — external addresses cannot register as suckers.
|
|
258
258
|
if (_isSuckerOf({revnetId: context.projectId, addr: context.holder})) {
|
|
259
259
|
return (0, context.cashOutCount, context.totalSupply, hookSpecifications);
|
|
260
260
|
}
|
|
@@ -270,13 +270,16 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
270
270
|
// Get the terminal that will receive the cash out fee.
|
|
271
271
|
IJBTerminal feeTerminal = DIRECTORY.primaryTerminalOf({projectId: FEE_REVNET_ID, token: context.surplus.token});
|
|
272
272
|
|
|
273
|
-
// If there's no cash out tax (100% cash out tax rate),
|
|
274
|
-
|
|
273
|
+
// If there's no cash out tax (100% cash out tax rate), if there's no fee terminal, or if the beneficiary is
|
|
274
|
+
// feeless (e.g. the router terminal routing value between projects), do not charge a fee.
|
|
275
|
+
if (context.cashOutTaxRate == 0 || address(feeTerminal) == address(0) || context.beneficiaryIsFeeless) {
|
|
275
276
|
return (context.cashOutTaxRate, context.cashOutCount, context.totalSupply, hookSpecifications);
|
|
276
277
|
}
|
|
277
278
|
|
|
278
279
|
// Get a reference to the number of tokens being used to pay the fee (out of the total being cashed out).
|
|
279
|
-
|
|
280
|
+
// Micro cash outs (< 40 wei at 2.5% fee) round feeCashOutCount to zero, bypassing the fee.
|
|
281
|
+
// Economically insignificant: the gas cost of the transaction far exceeds the bypassed fee. No fix needed.
|
|
282
|
+
uint256 feeCashOutCount = mulDiv({x: context.cashOutCount, y: FEE, denominator: JBConstants.MAX_FEE});
|
|
280
283
|
uint256 nonFeeCashOutCount = context.cashOutCount - feeCashOutCount;
|
|
281
284
|
|
|
282
285
|
// Keep a reference to the amount claimable with non-fee tokens.
|
|
@@ -353,7 +356,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
353
356
|
if (projectAmount == 0) {
|
|
354
357
|
weight = 0;
|
|
355
358
|
} else if (projectAmount < context.amount.value) {
|
|
356
|
-
weight = mulDiv(weight, projectAmount, context.amount.value);
|
|
359
|
+
weight = mulDiv({x: weight, y: projectAmount, denominator: context.amount.value});
|
|
357
360
|
}
|
|
358
361
|
|
|
359
362
|
// Merge hook specifications: 721 hook spec first, then buyback hook spec.
|
|
@@ -483,26 +486,6 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
483
486
|
}
|
|
484
487
|
}
|
|
485
488
|
|
|
486
|
-
/// @notice Try to initialize a Uniswap V4 buyback pool for a terminal token at a generic 1:1 price.
|
|
487
|
-
/// @dev Called after the ERC-20 token is deployed so the pool can be initialized in the PoolManager.
|
|
488
|
-
/// Silently catches failures (e.g., if the pool is already initialized).
|
|
489
|
-
/// @param revnetId The ID of the revnet.
|
|
490
|
-
/// @param terminalToken The terminal token to initialize a buyback pool for.
|
|
491
|
-
function _tryInitializeBuybackPoolFor(uint256 revnetId, address terminalToken) internal {
|
|
492
|
-
// Try to initialize the pool at a generic 1:1 sqrtPriceX96 and configure the buyback hook.
|
|
493
|
-
// The buyback hook constructs the PoolKey internally from the project token, terminal token, and pool params.
|
|
494
|
-
// slither-disable-next-line calls-loop
|
|
495
|
-
try BUYBACK_HOOK.initializePoolFor({
|
|
496
|
-
projectId: revnetId,
|
|
497
|
-
fee: DEFAULT_BUYBACK_POOL_FEE,
|
|
498
|
-
tickSpacing: DEFAULT_BUYBACK_TICK_SPACING,
|
|
499
|
-
twapWindow: DEFAULT_BUYBACK_TWAP_WINDOW,
|
|
500
|
-
terminalToken: terminalToken,
|
|
501
|
-
sqrtPriceX96: uint160(1 << 96)
|
|
502
|
-
}) {}
|
|
503
|
-
catch {} // Pool may already be initialized — that's OK.
|
|
504
|
-
}
|
|
505
|
-
|
|
506
489
|
/// @notice Make a ruleset configuration for a revnet's stage.
|
|
507
490
|
/// @param baseCurrency The base currency of the revnet.
|
|
508
491
|
/// @param stageConfiguration The stage configuration to make a ruleset for.
|
|
@@ -565,7 +548,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
565
548
|
uint256[] memory customSplitOperatorPermissionIndexes = _extraOperatorPermissions[revnetId];
|
|
566
549
|
|
|
567
550
|
// Make the array that merges the default and custom operator permissions.
|
|
568
|
-
allOperatorPermissions = new uint256[](
|
|
551
|
+
allOperatorPermissions = new uint256[](9 + customSplitOperatorPermissionIndexes.length);
|
|
569
552
|
allOperatorPermissions[0] = JBPermissionIds.SET_SPLIT_GROUPS;
|
|
570
553
|
allOperatorPermissions[1] = JBPermissionIds.SET_BUYBACK_POOL;
|
|
571
554
|
allOperatorPermissions[2] = JBPermissionIds.SET_BUYBACK_TWAP;
|
|
@@ -574,13 +557,34 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
574
557
|
allOperatorPermissions[5] = JBPermissionIds.SUCKER_SAFETY;
|
|
575
558
|
allOperatorPermissions[6] = JBPermissionIds.SET_BUYBACK_HOOK;
|
|
576
559
|
allOperatorPermissions[7] = JBPermissionIds.SET_ROUTER_TERMINAL;
|
|
560
|
+
allOperatorPermissions[8] = JBPermissionIds.SET_TOKEN_METADATA;
|
|
577
561
|
|
|
578
562
|
// Copy the custom permissions into the array.
|
|
579
563
|
for (uint256 i; i < customSplitOperatorPermissionIndexes.length; i++) {
|
|
580
|
-
allOperatorPermissions[
|
|
564
|
+
allOperatorPermissions[9 + i] = customSplitOperatorPermissionIndexes[i];
|
|
581
565
|
}
|
|
582
566
|
}
|
|
583
567
|
|
|
568
|
+
/// @notice Try to initialize a Uniswap V4 buyback pool for a terminal token at a generic 1:1 price.
|
|
569
|
+
/// @dev Called after the ERC-20 token is deployed so the pool can be initialized in the PoolManager.
|
|
570
|
+
/// Silently catches failures (e.g., if the pool is already initialized).
|
|
571
|
+
/// @param revnetId The ID of the revnet.
|
|
572
|
+
/// @param terminalToken The terminal token to initialize a buyback pool for.
|
|
573
|
+
function _tryInitializeBuybackPoolFor(uint256 revnetId, address terminalToken) internal {
|
|
574
|
+
// Try to initialize the pool at a generic 1:1 sqrtPriceX96 and configure the buyback hook.
|
|
575
|
+
// The buyback hook constructs the PoolKey internally from the project token, terminal token, and pool params.
|
|
576
|
+
// slither-disable-next-line calls-loop
|
|
577
|
+
try BUYBACK_HOOK.initializePoolFor({
|
|
578
|
+
projectId: revnetId,
|
|
579
|
+
fee: DEFAULT_BUYBACK_POOL_FEE,
|
|
580
|
+
tickSpacing: DEFAULT_BUYBACK_TICK_SPACING,
|
|
581
|
+
twapWindow: DEFAULT_BUYBACK_TWAP_WINDOW,
|
|
582
|
+
terminalToken: terminalToken,
|
|
583
|
+
sqrtPriceX96: uint160(1 << 96)
|
|
584
|
+
}) {}
|
|
585
|
+
catch {} // Pool may already be initialized — that's OK.
|
|
586
|
+
}
|
|
587
|
+
|
|
584
588
|
//*********************************************************************//
|
|
585
589
|
// --------------------- external transactions ----------------------- //
|
|
586
590
|
//*********************************************************************//
|
|
@@ -648,7 +652,13 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
648
652
|
/// @param stageId The ID of the stage auto-mint tokens are available from.
|
|
649
653
|
/// @param beneficiary The address to auto-mint tokens to.
|
|
650
654
|
function autoIssueFor(uint256 revnetId, uint256 stageId, address beneficiary) external override {
|
|
651
|
-
// Get
|
|
655
|
+
// Get the ruleset for the stage to check if it has started.
|
|
656
|
+
// Stage IDs are `block.timestamp + i` where `i` is the stage index. These match real JB ruleset IDs
|
|
657
|
+
// because JBRulesets assigns IDs the same way: `latestId >= block.timestamp ? latestId + 1 : block.timestamp`
|
|
658
|
+
// (see JBRulesets.sol L172). When all stages are queued in a single deployFor() call, the sequential
|
|
659
|
+
// IDs `block.timestamp`, `block.timestamp + 1`, ... exactly correspond to the JB-assigned ruleset IDs.
|
|
660
|
+
// The returned `ruleset.start` contains the derived start time (from `deriveStartFrom` using the stage's
|
|
661
|
+
// `mustStartAtOrAfter`), NOT the queue timestamp — so the timing guard correctly blocks early claims.
|
|
652
662
|
// slither-disable-next-line unused-return
|
|
653
663
|
(JBRuleset memory ruleset,) = CONTROLLER.getRulesetOf({projectId: revnetId, rulesetId: stageId});
|
|
654
664
|
|
|
@@ -677,6 +687,17 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
677
687
|
});
|
|
678
688
|
}
|
|
679
689
|
|
|
690
|
+
/// @notice Burn any of a revnet's tokens held by this contract.
|
|
691
|
+
/// @dev Project tokens can end up here from reserved token distribution when splits don't sum to 100%.
|
|
692
|
+
/// @param revnetId The ID of the revnet whose tokens should be burned.
|
|
693
|
+
function burnHeldTokensOf(uint256 revnetId) external override {
|
|
694
|
+
uint256 balance = CONTROLLER.TOKENS().totalBalanceOf({holder: address(this), projectId: revnetId});
|
|
695
|
+
if (balance == 0) revert REVDeployer_NothingToBurn();
|
|
696
|
+
CONTROLLER.burnTokensOf({holder: address(this), projectId: revnetId, tokenCount: balance, memo: ""});
|
|
697
|
+
// slither-disable-next-line reentrancy-events
|
|
698
|
+
emit BurnHeldTokens(revnetId, balance, _msgSender());
|
|
699
|
+
}
|
|
700
|
+
|
|
680
701
|
/// @notice Launch a revnet, or initialize an existing Juicebox project as a revnet.
|
|
681
702
|
/// @dev When initializing an existing project (revnetId != 0):
|
|
682
703
|
/// - The project must not yet have a controller or rulesets. `JBController.launchRulesetsFor` enforces this —
|
|
@@ -691,16 +712,21 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
691
712
|
/// @param terminalConfigurations The terminals to set up for the revnet. Used for payments and cash outs.
|
|
692
713
|
/// @param suckerDeploymentConfiguration The suckers to set up for the revnet. Suckers facilitate cross-chain
|
|
693
714
|
/// token transfers between peer revnets on different networks.
|
|
715
|
+
/// @param tiered721HookConfiguration How to set up the tiered ERC-721 hook for the revnet.
|
|
716
|
+
/// @param allowedPosts Restrictions on which croptop posts are allowed on the revnet's ERC-721 tiers.
|
|
694
717
|
/// @return revnetId The ID of the newly created revnet.
|
|
718
|
+
/// @return hook The address of the tiered ERC-721 hook that was deployed for the revnet.
|
|
695
719
|
function deployFor(
|
|
696
720
|
uint256 revnetId,
|
|
697
721
|
REVConfig calldata configuration,
|
|
698
722
|
JBTerminalConfig[] calldata terminalConfigurations,
|
|
699
|
-
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
|
|
723
|
+
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
|
|
724
|
+
REVDeploy721TiersHookConfig calldata tiered721HookConfiguration,
|
|
725
|
+
REVCroptopAllowedPost[] calldata allowedPosts
|
|
700
726
|
)
|
|
701
727
|
external
|
|
702
728
|
override
|
|
703
|
-
returns (uint256)
|
|
729
|
+
returns (uint256, IJB721TiersHook hook)
|
|
704
730
|
{
|
|
705
731
|
// Keep a reference to the revnet ID which was passed in.
|
|
706
732
|
bool shouldDeployNewRevnet = revnetId == 0;
|
|
@@ -709,34 +735,69 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
709
735
|
// (which will be 1 greater than the current count).
|
|
710
736
|
if (shouldDeployNewRevnet) revnetId = _nextProjectId();
|
|
711
737
|
|
|
712
|
-
//
|
|
713
|
-
|
|
714
|
-
revnetId: revnetId, configuration: configuration, terminalConfigurations: terminalConfigurations
|
|
715
|
-
});
|
|
716
|
-
|
|
717
|
-
// Deploy the revnet.
|
|
718
|
-
_deployRevnetFor({
|
|
738
|
+
// Deploy the revnet with the specified tiered ERC-721 hook and croptop posting criteria.
|
|
739
|
+
hook = _deploy721RevnetFor({
|
|
719
740
|
revnetId: revnetId,
|
|
720
741
|
shouldDeployNewRevnet: shouldDeployNewRevnet,
|
|
721
742
|
configuration: configuration,
|
|
722
743
|
terminalConfigurations: terminalConfigurations,
|
|
723
744
|
suckerDeploymentConfiguration: suckerDeploymentConfiguration,
|
|
724
|
-
|
|
725
|
-
|
|
745
|
+
tiered721HookConfiguration: tiered721HookConfiguration,
|
|
746
|
+
allowedPosts: allowedPosts
|
|
726
747
|
});
|
|
727
748
|
|
|
728
|
-
return revnetId;
|
|
749
|
+
return (revnetId, hook);
|
|
729
750
|
}
|
|
730
751
|
|
|
731
|
-
/// @
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
752
|
+
/// @inheritdoc IREVDeployer
|
|
753
|
+
function deployFor(
|
|
754
|
+
uint256 revnetId,
|
|
755
|
+
REVConfig calldata configuration,
|
|
756
|
+
JBTerminalConfig[] calldata terminalConfigurations,
|
|
757
|
+
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
|
|
758
|
+
)
|
|
759
|
+
external
|
|
760
|
+
override
|
|
761
|
+
returns (uint256, IJB721TiersHook hook)
|
|
762
|
+
{
|
|
763
|
+
bool shouldDeployNewRevnet = revnetId == 0;
|
|
764
|
+
if (shouldDeployNewRevnet) revnetId = _nextProjectId();
|
|
765
|
+
|
|
766
|
+
// Deploy the revnet (project, rulesets, ERC-20, suckers, etc.).
|
|
767
|
+
bytes32 encodedConfigurationHash = _deployRevnetFor({
|
|
768
|
+
revnetId: revnetId,
|
|
769
|
+
shouldDeployNewRevnet: shouldDeployNewRevnet,
|
|
770
|
+
configuration: configuration,
|
|
771
|
+
terminalConfigurations: terminalConfigurations,
|
|
772
|
+
suckerDeploymentConfiguration: suckerDeploymentConfiguration
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
// Deploy a default empty 721 hook for the revnet.
|
|
776
|
+
{
|
|
777
|
+
JBDeploy721TiersHookConfig memory deployConfig;
|
|
778
|
+
deployConfig.tiersConfig.currency = configuration.baseCurrency;
|
|
779
|
+
deployConfig.tiersConfig.decimals = 18;
|
|
780
|
+
|
|
781
|
+
hook = HOOK_DEPLOYER.deployHookFor({
|
|
782
|
+
projectId: revnetId,
|
|
783
|
+
deployTiersHookConfig: deployConfig,
|
|
784
|
+
salt: keccak256(abi.encode(bytes32(0), encodedConfigurationHash, _msgSender()))
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// Store the tiered ERC-721 hook.
|
|
789
|
+
tiered721HookOf[revnetId] = hook;
|
|
790
|
+
|
|
791
|
+
// Grant the split operator all 721 permissions (no prevent* flags for default config).
|
|
792
|
+
_extraOperatorPermissions[revnetId].push(JBPermissionIds.ADJUST_721_TIERS);
|
|
793
|
+
_extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_METADATA);
|
|
794
|
+
_extraOperatorPermissions[revnetId].push(JBPermissionIds.MINT_721);
|
|
795
|
+
_extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_DISCOUNT_PERCENT);
|
|
796
|
+
|
|
797
|
+
// Give the split operator their permissions (base + 721 extras).
|
|
798
|
+
_setSplitOperatorOf({revnetId: revnetId, operator: configuration.splitOperator});
|
|
799
|
+
|
|
800
|
+
return (revnetId, hook);
|
|
740
801
|
}
|
|
741
802
|
|
|
742
803
|
/// @notice Deploy new suckers for an existing revnet.
|
|
@@ -775,51 +836,6 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
775
836
|
});
|
|
776
837
|
}
|
|
777
838
|
|
|
778
|
-
/// @notice Launch a revnet which sells tiered ERC-721s and (optionally) allows croptop posts to its ERC-721 tiers.
|
|
779
|
-
/// @dev When initializing an existing project (revnetId != 0), the project must be blank (no controller or
|
|
780
|
-
/// rulesets). The initialization is irreversible. See `deployFor` documentation for full details.
|
|
781
|
-
/// @param revnetId The ID of the Juicebox project to initialize as a revnet. Send 0 to deploy a new revnet.
|
|
782
|
-
/// @param configuration Core revnet configuration. See `REVConfig`.
|
|
783
|
-
/// @param terminalConfigurations The terminals to set up for the revnet. Used for payments and cash outs.
|
|
784
|
-
/// @param suckerDeploymentConfiguration The suckers to set up for the revnet. Suckers facilitate cross-chain
|
|
785
|
-
/// token transfers between peer revnets on different networks.
|
|
786
|
-
/// @param tiered721HookConfiguration How to set up the tiered ERC-721 hook for the revnet.
|
|
787
|
-
/// @param allowedPosts Restrictions on which croptop posts are allowed on the revnet's ERC-721 tiers.
|
|
788
|
-
/// @return revnetId The ID of the newly created revnet.
|
|
789
|
-
/// @return hook The address of the tiered ERC-721 hook that was deployed for the revnet.
|
|
790
|
-
function deployWith721sFor(
|
|
791
|
-
uint256 revnetId,
|
|
792
|
-
REVConfig calldata configuration,
|
|
793
|
-
JBTerminalConfig[] calldata terminalConfigurations,
|
|
794
|
-
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
|
|
795
|
-
REVDeploy721TiersHookConfig calldata tiered721HookConfiguration,
|
|
796
|
-
REVCroptopAllowedPost[] calldata allowedPosts
|
|
797
|
-
)
|
|
798
|
-
external
|
|
799
|
-
override
|
|
800
|
-
returns (uint256, IJB721TiersHook hook)
|
|
801
|
-
{
|
|
802
|
-
// Keep a reference to the revnet ID which was passed in.
|
|
803
|
-
bool shouldDeployNewRevnet = revnetId == 0;
|
|
804
|
-
|
|
805
|
-
// If the caller is deploying a new revnet, calculate its ID
|
|
806
|
-
// (which will be 1 greater than the current count).
|
|
807
|
-
if (shouldDeployNewRevnet) revnetId = _nextProjectId();
|
|
808
|
-
|
|
809
|
-
// Deploy the revnet with the specified tiered ERC-721 hook and croptop posting criteria.
|
|
810
|
-
hook = _deploy721RevnetFor({
|
|
811
|
-
revnetId: revnetId,
|
|
812
|
-
shouldDeployNewRevnet: shouldDeployNewRevnet,
|
|
813
|
-
configuration: configuration,
|
|
814
|
-
terminalConfigurations: terminalConfigurations,
|
|
815
|
-
suckerDeploymentConfiguration: suckerDeploymentConfiguration,
|
|
816
|
-
tiered721HookConfiguration: tiered721HookConfiguration,
|
|
817
|
-
allowedPosts: allowedPosts
|
|
818
|
-
});
|
|
819
|
-
|
|
820
|
-
return (revnetId, hook);
|
|
821
|
-
}
|
|
822
|
-
|
|
823
839
|
/// @notice Change a revnet's split operator.
|
|
824
840
|
/// @dev Only a revnet's current split operator can set a new split operator.
|
|
825
841
|
/// @param revnetId The ID of the revnet to set the split operator of.
|
|
@@ -852,91 +868,86 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
852
868
|
function _beforeTransferTo(address to, address token, uint256 amount) internal returns (uint256) {
|
|
853
869
|
// If the token is the native token, no allowance needed.
|
|
854
870
|
if (token == JBConstants.NATIVE_TOKEN) return amount;
|
|
855
|
-
IERC20(token).safeIncreaseAllowance(to, amount);
|
|
871
|
+
IERC20(token).safeIncreaseAllowance({spender: to, value: amount});
|
|
856
872
|
return 0;
|
|
857
873
|
}
|
|
858
874
|
|
|
859
875
|
/// @notice Deploy a revnet which sells tiered ERC-721s and (optionally) allows croptop posts to its ERC-721 tiers.
|
|
860
|
-
/// @param revnetId The ID of the Juicebox project to turn into a revnet. Send 0 to deploy a new revnet.
|
|
861
|
-
/// @param shouldDeployNewRevnet Whether to deploy a new revnet or convert an existing Juicebox project into a
|
|
862
|
-
/// revnet.
|
|
863
|
-
/// @param configuration Core revnet configuration. See `REVConfig`.
|
|
864
|
-
/// @param terminalConfigurations The terminals to set up for the revnet. Used for payments and cash outs.
|
|
865
|
-
/// @param suckerDeploymentConfiguration The suckers to set up for the revnet. Suckers facilitate cross-chain
|
|
866
|
-
/// token transfers between peer revnets on different networks.
|
|
867
|
-
/// @param tiered721HookConfiguration How to set up the tiered ERC-721 hook for the revnet.
|
|
868
|
-
/// @param allowedPosts Restrictions on which croptop posts are allowed on the revnet's ERC-721 tiers.
|
|
869
|
-
/// @return hook The address of the tiered ERC-721 hook that was deployed for the revnet.
|
|
870
876
|
function _deploy721RevnetFor(
|
|
871
877
|
uint256 revnetId,
|
|
872
878
|
bool shouldDeployNewRevnet,
|
|
873
879
|
REVConfig calldata configuration,
|
|
874
880
|
JBTerminalConfig[] calldata terminalConfigurations,
|
|
875
881
|
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
|
|
876
|
-
REVDeploy721TiersHookConfig
|
|
877
|
-
REVCroptopAllowedPost[]
|
|
882
|
+
REVDeploy721TiersHookConfig memory tiered721HookConfiguration,
|
|
883
|
+
REVCroptopAllowedPost[] memory allowedPosts
|
|
878
884
|
)
|
|
879
885
|
internal
|
|
880
886
|
returns (IJB721TiersHook hook)
|
|
881
887
|
{
|
|
882
|
-
//
|
|
883
|
-
|
|
884
|
-
revnetId: revnetId,
|
|
888
|
+
// Deploy the revnet (project, rulesets, ERC-20, suckers, etc.).
|
|
889
|
+
bytes32 encodedConfigurationHash = _deployRevnetFor({
|
|
890
|
+
revnetId: revnetId,
|
|
891
|
+
shouldDeployNewRevnet: shouldDeployNewRevnet,
|
|
892
|
+
configuration: configuration,
|
|
893
|
+
terminalConfigurations: terminalConfigurations,
|
|
894
|
+
suckerDeploymentConfiguration: suckerDeploymentConfiguration
|
|
885
895
|
});
|
|
886
896
|
|
|
887
897
|
// Convert the REVBaseline721HookConfig to JBDeploy721TiersHookConfig, forcing issueTokensForSplits to false.
|
|
888
898
|
// Revnets do their own weight adjustment for splits, so the 721 hook must not also adjust.
|
|
889
|
-
JBDeploy721TiersHookConfig memory hookConfig = JBDeploy721TiersHookConfig({
|
|
890
|
-
name: tiered721HookConfiguration.baseline721HookConfiguration.name,
|
|
891
|
-
symbol: tiered721HookConfiguration.baseline721HookConfiguration.symbol,
|
|
892
|
-
baseUri: tiered721HookConfiguration.baseline721HookConfiguration.baseUri,
|
|
893
|
-
tokenUriResolver: tiered721HookConfiguration.baseline721HookConfiguration.tokenUriResolver,
|
|
894
|
-
contractUri: tiered721HookConfiguration.baseline721HookConfiguration.contractUri,
|
|
895
|
-
tiersConfig: tiered721HookConfiguration.baseline721HookConfiguration.tiersConfig,
|
|
896
|
-
reserveBeneficiary: tiered721HookConfiguration.baseline721HookConfiguration.reserveBeneficiary,
|
|
897
|
-
flags: JB721TiersHookFlags({
|
|
898
|
-
noNewTiersWithReserves: tiered721HookConfiguration.baseline721HookConfiguration.flags
|
|
899
|
-
.noNewTiersWithReserves,
|
|
900
|
-
noNewTiersWithVotes: tiered721HookConfiguration.baseline721HookConfiguration.flags.noNewTiersWithVotes,
|
|
901
|
-
noNewTiersWithOwnerMinting: tiered721HookConfiguration.baseline721HookConfiguration.flags
|
|
902
|
-
.noNewTiersWithOwnerMinting,
|
|
903
|
-
preventOverspending: tiered721HookConfiguration.baseline721HookConfiguration.flags.preventOverspending,
|
|
904
|
-
issueTokensForSplits: false
|
|
905
|
-
})
|
|
906
|
-
});
|
|
907
|
-
|
|
908
|
-
// Deploy the tiered ERC-721 hook contract.
|
|
909
|
-
// slither-disable-next-line reentrancy-benign
|
|
910
899
|
hook = HOOK_DEPLOYER.deployHookFor({
|
|
911
900
|
projectId: revnetId,
|
|
912
|
-
deployTiersHookConfig:
|
|
901
|
+
deployTiersHookConfig: JBDeploy721TiersHookConfig({
|
|
902
|
+
name: tiered721HookConfiguration.baseline721HookConfiguration.name,
|
|
903
|
+
symbol: tiered721HookConfiguration.baseline721HookConfiguration.symbol,
|
|
904
|
+
baseUri: tiered721HookConfiguration.baseline721HookConfiguration.baseUri,
|
|
905
|
+
tokenUriResolver: tiered721HookConfiguration.baseline721HookConfiguration.tokenUriResolver,
|
|
906
|
+
contractUri: tiered721HookConfiguration.baseline721HookConfiguration.contractUri,
|
|
907
|
+
tiersConfig: tiered721HookConfiguration.baseline721HookConfiguration.tiersConfig,
|
|
908
|
+
reserveBeneficiary: tiered721HookConfiguration.baseline721HookConfiguration.reserveBeneficiary,
|
|
909
|
+
flags: JB721TiersHookFlags({
|
|
910
|
+
noNewTiersWithReserves: tiered721HookConfiguration.baseline721HookConfiguration.flags
|
|
911
|
+
.noNewTiersWithReserves,
|
|
912
|
+
noNewTiersWithVotes: tiered721HookConfiguration.baseline721HookConfiguration.flags
|
|
913
|
+
.noNewTiersWithVotes,
|
|
914
|
+
noNewTiersWithOwnerMinting: tiered721HookConfiguration.baseline721HookConfiguration.flags
|
|
915
|
+
.noNewTiersWithOwnerMinting,
|
|
916
|
+
preventOverspending: tiered721HookConfiguration.baseline721HookConfiguration.flags
|
|
917
|
+
.preventOverspending,
|
|
918
|
+
issueTokensForSplits: false
|
|
919
|
+
})
|
|
920
|
+
}),
|
|
913
921
|
salt: keccak256(abi.encode(tiered721HookConfiguration.salt, encodedConfigurationHash, _msgSender()))
|
|
914
922
|
});
|
|
915
923
|
|
|
916
924
|
// Store the tiered ERC-721 hook.
|
|
917
925
|
tiered721HookOf[revnetId] = hook;
|
|
918
926
|
|
|
919
|
-
//
|
|
920
|
-
if (tiered721HookConfiguration.
|
|
927
|
+
// Give the split operator permission to add and remove tiers unless prevented.
|
|
928
|
+
if (!tiered721HookConfiguration.preventSplitOperatorAdjustingTiers) {
|
|
921
929
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.ADJUST_721_TIERS);
|
|
922
930
|
}
|
|
923
931
|
|
|
924
|
-
//
|
|
925
|
-
if (tiered721HookConfiguration.
|
|
932
|
+
// Give the split operator permission to set ERC-721 tier metadata unless prevented.
|
|
933
|
+
if (!tiered721HookConfiguration.preventSplitOperatorUpdatingMetadata) {
|
|
926
934
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_METADATA);
|
|
927
935
|
}
|
|
928
936
|
|
|
929
|
-
//
|
|
930
|
-
// from tiers with `allowOwnerMint` set to true.
|
|
931
|
-
if (tiered721HookConfiguration.
|
|
937
|
+
// Give the split operator permission to mint ERC-721s (without a payment)
|
|
938
|
+
// from tiers with `allowOwnerMint` set to true, unless prevented.
|
|
939
|
+
if (!tiered721HookConfiguration.preventSplitOperatorMinting) {
|
|
932
940
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.MINT_721);
|
|
933
941
|
}
|
|
934
942
|
|
|
935
|
-
//
|
|
936
|
-
if (tiered721HookConfiguration.
|
|
943
|
+
// Give the split operator permission to increase the discount of a tier unless prevented.
|
|
944
|
+
if (!tiered721HookConfiguration.preventSplitOperatorIncreasingDiscountPercent) {
|
|
937
945
|
_extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_DISCOUNT_PERCENT);
|
|
938
946
|
}
|
|
939
947
|
|
|
948
|
+
// Give the split operator their permissions (base + 721 extras).
|
|
949
|
+
_setSplitOperatorOf({revnetId: revnetId, operator: configuration.splitOperator});
|
|
950
|
+
|
|
940
951
|
// If there are posts to allow, configure them.
|
|
941
952
|
if (allowedPosts.length != 0) {
|
|
942
953
|
// Keep a reference to the formatted allowed posts.
|
|
@@ -945,7 +956,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
945
956
|
// Iterate through each post to add it to the formatted list.
|
|
946
957
|
for (uint256 i; i < allowedPosts.length; i++) {
|
|
947
958
|
// Set the post being iterated on.
|
|
948
|
-
REVCroptopAllowedPost
|
|
959
|
+
REVCroptopAllowedPost memory post = allowedPosts[i];
|
|
949
960
|
|
|
950
961
|
// Set the formatted post.
|
|
951
962
|
formattedAllowedPosts[i] = CTAllowedPost({
|
|
@@ -967,16 +978,6 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
967
978
|
operator: address(PUBLISHER), revnetId: revnetId, permissionId: JBPermissionIds.ADJUST_721_TIERS
|
|
968
979
|
});
|
|
969
980
|
}
|
|
970
|
-
|
|
971
|
-
_deployRevnetFor({
|
|
972
|
-
revnetId: revnetId,
|
|
973
|
-
shouldDeployNewRevnet: shouldDeployNewRevnet,
|
|
974
|
-
configuration: configuration,
|
|
975
|
-
terminalConfigurations: terminalConfigurations,
|
|
976
|
-
suckerDeploymentConfiguration: suckerDeploymentConfiguration,
|
|
977
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
978
|
-
encodedConfigurationHash: encodedConfigurationHash
|
|
979
|
-
});
|
|
980
981
|
}
|
|
981
982
|
|
|
982
983
|
/// @notice Deploy a revnet, or initialize an existing Juicebox project as a revnet.
|
|
@@ -993,21 +994,22 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
993
994
|
/// @param terminalConfigurations The terminals to set up for the revnet. Used for payments and cash outs.
|
|
994
995
|
/// @param suckerDeploymentConfiguration The suckers to set up for the revnet. Suckers facilitate cross-chain
|
|
995
996
|
/// token transfers between peer revnets on different networks.
|
|
996
|
-
/// @
|
|
997
|
-
/// @param encodedConfigurationHash A hash that represents the revnet's configuration.
|
|
998
|
-
/// See `_makeRulesetConfigurations(…)` for encoding details. Clients can read the encoded configuration
|
|
999
|
-
/// from the `DeployRevnet` event emitted by this contract.
|
|
997
|
+
/// @return encodedConfigurationHash A hash that represents the revnet's configuration.
|
|
1000
998
|
function _deployRevnetFor(
|
|
1001
999
|
uint256 revnetId,
|
|
1002
1000
|
bool shouldDeployNewRevnet,
|
|
1003
1001
|
REVConfig calldata configuration,
|
|
1004
1002
|
JBTerminalConfig[] calldata terminalConfigurations,
|
|
1005
|
-
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
|
|
1006
|
-
JBRulesetConfig[] memory rulesetConfigurations,
|
|
1007
|
-
bytes32 encodedConfigurationHash
|
|
1003
|
+
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
|
|
1008
1004
|
)
|
|
1009
1005
|
internal
|
|
1006
|
+
returns (bytes32 encodedConfigurationHash)
|
|
1010
1007
|
{
|
|
1008
|
+
// Normalize and encode the configurations.
|
|
1009
|
+
JBRulesetConfig[] memory rulesetConfigurations;
|
|
1010
|
+
(rulesetConfigurations, encodedConfigurationHash) = _makeRulesetConfigurations({
|
|
1011
|
+
revnetId: revnetId, configuration: configuration, terminalConfigurations: terminalConfigurations
|
|
1012
|
+
});
|
|
1011
1013
|
if (shouldDeployNewRevnet) {
|
|
1012
1014
|
// If we're deploying a new revnet, launch a Juicebox project for it.
|
|
1013
1015
|
// Sanity check that we deployed the `revnetId` that we expected to deploy.
|
|
@@ -1064,13 +1066,12 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
1064
1066
|
JBTerminalConfig calldata terminalConfiguration = terminalConfigurations[i];
|
|
1065
1067
|
for (uint256 j; j < terminalConfiguration.accountingContextsToAccept.length; j++) {
|
|
1066
1068
|
// slither-disable-next-line calls-loop
|
|
1067
|
-
_tryInitializeBuybackPoolFor(
|
|
1069
|
+
_tryInitializeBuybackPoolFor({
|
|
1070
|
+
revnetId: revnetId, terminalToken: terminalConfiguration.accountingContextsToAccept[j].token
|
|
1071
|
+
});
|
|
1068
1072
|
}
|
|
1069
1073
|
}
|
|
1070
1074
|
|
|
1071
|
-
// Give the split operator their permissions.
|
|
1072
|
-
_setSplitOperatorOf({revnetId: revnetId, operator: configuration.splitOperator});
|
|
1073
|
-
|
|
1074
1075
|
// Deploy the suckers (if applicable).
|
|
1075
1076
|
if (suckerDeploymentConfiguration.salt != bytes32(0)) {
|
|
1076
1077
|
_deploySuckersFor({
|
|
@@ -1130,6 +1131,9 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
1130
1131
|
/// of collateral) or lower issuance weight (reducing the surplus-per-token ratio). Borrowers should monitor
|
|
1131
1132
|
/// upcoming stage transitions and adjust their positions accordingly, as loans that fall below their required
|
|
1132
1133
|
/// collateralization may become eligible for liquidation.
|
|
1134
|
+
/// @dev `cashOutTaxRate` changes at stage boundaries may allow users to cash out just before a rate increase.
|
|
1135
|
+
/// This is accepted behavior — the arbitrage window is bounded by the ruleset design, and all stages are
|
|
1136
|
+
/// configured immutably at deployment time.
|
|
1133
1137
|
/// @param revnetId The ID of the revnet to make rulesets for.
|
|
1134
1138
|
/// @param configuration The configuration containing the revnet's stages.
|
|
1135
1139
|
/// @param terminalConfigurations The terminals to set up for the revnet. Used for payments and cash outs.
|
|
@@ -1237,8 +1241,11 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
1237
1241
|
});
|
|
1238
1242
|
|
|
1239
1243
|
// Store the amount of tokens that can be auto-minted on this chain during this stage.
|
|
1240
|
-
// The
|
|
1241
|
-
//
|
|
1244
|
+
// The stage ID is `block.timestamp + i`. This matches the ruleset ID that JBRulesets assigns
|
|
1245
|
+
// because JBRulesets uses `latestId >= block.timestamp ? latestId + 1 : block.timestamp`
|
|
1246
|
+
// (JBRulesets.sol L172), producing the same sequential IDs when all stages are queued in one tx.
|
|
1247
|
+
// `autoIssueFor` later calls `getRulesetOf(revnetId, stageId)` — the returned `ruleset.start`
|
|
1248
|
+
// is the derived start time (not the queue time), so the timing guard works correctly.
|
|
1242
1249
|
// slither-disable-next-line reentrancy-benign
|
|
1243
1250
|
amountToAutoIssue[revnetId][block.timestamp + i][autoIssuance.beneficiary] += autoIssuance.count;
|
|
1244
1251
|
}
|
|
@@ -1296,7 +1303,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
1296
1303
|
{
|
|
1297
1304
|
// Set up the permission data.
|
|
1298
1305
|
JBPermissionsData memory permissionData =
|
|
1299
|
-
|
|
1306
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
1307
|
+
JBPermissionsData({operator: operator, projectId: uint64(revnetId), permissionIds: permissionIds});
|
|
1300
1308
|
|
|
1301
1309
|
// Set the permissions.
|
|
1302
1310
|
PERMISSIONS.setPermissionsFor({account: account, permissionsData: permissionData});
|