@rev-net/core-v6 0.0.57 → 0.0.61

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.
@@ -12,6 +12,7 @@ import {IJBPermissioned} from "@bananapus/core-v6/src/interfaces/IJBPermissioned
12
12
  import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
13
13
  import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
14
14
  import {IJBRulesetApprovalHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetApprovalHook.sol";
15
+ import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
15
16
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
16
17
  import {JBSplitGroupIds} from "@bananapus/core-v6/src/libraries/JBSplitGroupIds.sol";
17
18
  import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
@@ -22,7 +23,6 @@ import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
22
23
  import {JBRulesetConfig} from "@bananapus/core-v6/src/structs/JBRulesetConfig.sol";
23
24
  import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
24
25
  import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
25
- import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
26
26
  import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
27
27
  import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
28
28
  import {IJBSuckerRegistry} from "@bananapus/suckers-v6/src/interfaces/IJBSuckerRegistry.sol";
@@ -115,6 +115,9 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
115
115
  /// Participants can borrow up to the current cash out value of their tokens.
116
116
  IREVLoans public immutable override LOANS;
117
117
 
118
+ /// @notice The canonical terminal that holds revnet treasury balances.
119
+ IJBTerminal public immutable override MULTI_TERMINAL;
120
+
118
121
  /// @notice The runtime data hook contract that handles pay and cash out callbacks for revnets.
119
122
  /// @dev Set as `dataHook` in each revnet's ruleset metadata. Implements `IJBRulesetDataHook` and `IJBCashOutHook`.
120
123
  address public immutable override OWNER;
@@ -128,6 +131,10 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
128
131
  /// @notice Manages the publishing of ERC-721 posts to revnet's tiered ERC-721 hooks.
129
132
  CTPublisher public immutable override PUBLISHER;
130
133
 
134
+ /// @notice The canonical router terminal registry installed as a project terminal for alternate payment routes.
135
+ /// @dev Deployments pass the router terminal registry here, not the underlying router terminal implementation.
136
+ IJBTerminal public immutable override ROUTER_TERMINAL_REGISTRY;
137
+
131
138
  /// @notice Deploys and tracks suckers for revnets.
132
139
  IJBSuckerRegistry public immutable override SUCKER_REGISTRY;
133
140
 
@@ -165,6 +172,10 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
165
172
  //*********************************************************************//
166
173
 
167
174
  /// @param controller The controller to use for launching and operating the Juicebox projects which will be revnets.
175
+ /// @param multiTerminal The canonical terminal that holds revnet treasury balances. Assumed to be a valid
176
+ /// deployment-time dependency.
177
+ /// @param routerTerminalRegistry The canonical router terminal registry used for alternate payment routes. Assumed
178
+ /// to be a valid deployment-time dependency.
168
179
  /// @param suckerRegistry The registry to use for deploying and tracking each revnet's suckers.
169
180
  /// @param feeRevnetId The Juicebox project ID of the revnet that will receive fees.
170
181
  /// @param hookDeployer The deployer to use for revnet's tiered ERC-721 hooks.
@@ -175,6 +186,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
175
186
  /// @param owner The runtime data hook contract (REVOwner) that handles pay and cash out callbacks.
176
187
  constructor(
177
188
  IJBController controller,
189
+ IJBTerminal multiTerminal,
190
+ IJBTerminal routerTerminalRegistry,
178
191
  IJBSuckerRegistry suckerRegistry,
179
192
  uint256 feeRevnetId,
180
193
  IJB721TiersHookDeployer hookDeployer,
@@ -190,6 +203,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
190
203
  DIRECTORY = controller.DIRECTORY();
191
204
  PROJECTS = controller.PROJECTS();
192
205
  PERMISSIONS = IJBPermissioned(address(CONTROLLER)).PERMISSIONS();
206
+ MULTI_TERMINAL = multiTerminal;
207
+ ROUTER_TERMINAL_REGISTRY = routerTerminalRegistry;
193
208
  SUCKER_REGISTRY = suckerRegistry;
194
209
  FEE_REVNET_ID = feeRevnetId;
195
210
  HOOK_DEPLOYER = hookDeployer;
@@ -259,49 +274,32 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
259
274
  }
260
275
 
261
276
  /// @notice Initialize fund access limits for the loan contract.
262
- /// @dev Returns an unlimited surplus allowance for each terminal+token pair derived from the terminal
263
- /// configurations.
264
- /// @param terminalConfigurations The terminals to set up for the revnet.
277
+ /// @dev Returns an unlimited surplus allowance for each accepted token in the canonical multi terminal.
278
+ /// @param accountingContextsToAccept The accounting contexts the canonical multi terminal should accept.
265
279
  /// @return fundAccessLimitGroups The fund access limit groups for the loans.
266
- function _makeLoanFundAccessLimits(JBTerminalConfig[] calldata terminalConfigurations)
280
+ function _makeLoanFundAccessLimits(JBAccountingContext[] calldata accountingContextsToAccept)
267
281
  internal
268
- pure
282
+ view
269
283
  returns (JBFundAccessLimitGroup[] memory fundAccessLimitGroups)
270
284
  {
271
- // Count the total number of accounting contexts across all terminals.
272
- uint256 count;
273
- for (uint256 i; i < terminalConfigurations.length;) {
274
- count += terminalConfigurations[i].accountingContextsToAccept.length;
275
- unchecked {
276
- ++i;
277
- }
278
- }
279
-
280
285
  // Initialize the fund access limit groups.
281
- fundAccessLimitGroups = new JBFundAccessLimitGroup[](count);
286
+ fundAccessLimitGroups = new JBFundAccessLimitGroup[](accountingContextsToAccept.length);
282
287
 
283
288
  // Set up the fund access limits.
284
- uint256 index;
285
- for (uint256 i; i < terminalConfigurations.length;) {
286
- JBTerminalConfig calldata terminalConfiguration = terminalConfigurations[i];
287
- for (uint256 j; j < terminalConfiguration.accountingContextsToAccept.length;) {
288
- JBAccountingContext calldata accountingContext = terminalConfiguration.accountingContextsToAccept[j];
289
-
290
- // Set up an unlimited allowance for the loan contract to use.
291
- JBCurrencyAmount[] memory loanAllowances = new JBCurrencyAmount[](1);
292
- loanAllowances[0] = JBCurrencyAmount({currency: accountingContext.currency, amount: type(uint224).max});
293
-
294
- // Set up the fund access limits for the loans.
295
- fundAccessLimitGroups[index++] = JBFundAccessLimitGroup({
296
- terminal: address(terminalConfiguration.terminal),
297
- token: accountingContext.token,
298
- payoutLimits: new JBCurrencyAmount[](0),
299
- surplusAllowances: loanAllowances
300
- });
301
- unchecked {
302
- ++j;
303
- }
304
- }
289
+ for (uint256 i; i < accountingContextsToAccept.length;) {
290
+ JBAccountingContext calldata accountingContext = accountingContextsToAccept[i];
291
+
292
+ // Set up an unlimited allowance for the loan contract to use.
293
+ JBCurrencyAmount[] memory loanAllowances = new JBCurrencyAmount[](1);
294
+ loanAllowances[0] = JBCurrencyAmount({currency: accountingContext.currency, amount: type(uint224).max});
295
+
296
+ // Set up the fund access limits for the loans.
297
+ fundAccessLimitGroups[i] = JBFundAccessLimitGroup({
298
+ terminal: address(MULTI_TERMINAL),
299
+ token: accountingContext.token,
300
+ payoutLimits: new JBCurrencyAmount[](0),
301
+ surplusAllowances: loanAllowances
302
+ });
305
303
  unchecked {
306
304
  ++i;
307
305
  }
@@ -353,6 +351,26 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
353
351
  });
354
352
  }
355
353
 
354
+ /// @notice Build the canonical terminal configuration used by every revnet.
355
+ /// @dev `MULTI_TERMINAL` accepts the revnet's accounting contexts and owns the treasury/loan accounting surface.
356
+ /// `ROUTER_TERMINAL_REGISTRY` is registered without accounting contexts so users can pay through the router path
357
+ /// without letting callers choose arbitrary terminals or loan sources. The deployer is constructed with distinct
358
+ /// addresses in the two slots; reusing the same address would be rejected by the directory's duplicate check.
359
+ /// @param accountingContextsToAccept The accounting contexts the canonical multi terminal should accept.
360
+ /// @return terminalConfigurations The canonical terminal configuration for the revnet.
361
+ function _makeTerminalConfigurations(JBAccountingContext[] calldata accountingContextsToAccept)
362
+ internal
363
+ view
364
+ returns (JBTerminalConfig[] memory terminalConfigurations)
365
+ {
366
+ terminalConfigurations = new JBTerminalConfig[](2);
367
+ terminalConfigurations[0] =
368
+ JBTerminalConfig({terminal: MULTI_TERMINAL, accountingContextsToAccept: accountingContextsToAccept});
369
+ terminalConfigurations[1] = JBTerminalConfig({
370
+ terminal: ROUTER_TERMINAL_REGISTRY, accountingContextsToAccept: new JBAccountingContext[](0)
371
+ });
372
+ }
373
+
356
374
  /// @notice Returns the permissions that the operator should have for a revnet.
357
375
  /// @param revnetId The ID of the revnet to look up.
358
376
  /// @return allOperatorPermissions The permissions the operator should have for the revnet,
@@ -415,10 +433,12 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
415
433
  sqrtPriceX96 = uint160(1 << 96);
416
434
  } else if (normalizedTerminalToken < projectToken) {
417
435
  // token0 = terminal, token1 = project → price = issuance / terminalTokenUnit
418
- sqrtPriceX96 = uint160(sqrt(mulDiv(uint256(initialIssuance), 1 << 192, terminalTokenUnit)));
436
+ sqrtPriceX96 =
437
+ uint160(sqrt(mulDiv({x: uint256(initialIssuance), y: 1 << 192, denominator: terminalTokenUnit})));
419
438
  } else {
420
439
  // token0 = project, token1 = terminal → price = terminalTokenUnit / issuance
421
- sqrtPriceX96 = uint160(sqrt(mulDiv(terminalTokenUnit, 1 << 192, uint256(initialIssuance))));
440
+ sqrtPriceX96 =
441
+ uint160(sqrt(mulDiv({x: terminalTokenUnit, y: 1 << 192, denominator: uint256(initialIssuance)})));
422
442
  }
423
443
  }
424
444
 
@@ -510,7 +530,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
510
530
  /// REVDeployer, and the project becomes subject to immutable revnet rules. This cannot be undone.
511
531
  /// @param revnetId The ID of the Juicebox project to initialize as a revnet. Send 0 to deploy a new revnet.
512
532
  /// @param configuration Core revnet configuration. See `REVConfig`.
513
- /// @param terminalConfigurations The terminals to set up for the revnet.
533
+ /// @param accountingContextsToAccept The accounting contexts the canonical multi terminal should accept.
514
534
  /// @param suckerDeploymentConfiguration The suckers to set up for cross-chain token transfers.
515
535
  /// @param tiered721HookConfiguration How to configure the tiered ERC-721 hook for the revnet.
516
536
  /// @param allowedPosts Restrictions on which croptop posts to allow on the revnet's ERC-721 tiers.
@@ -520,7 +540,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
520
540
  function deployFor(
521
541
  uint256 revnetId,
522
542
  REVConfig calldata configuration,
523
- JBTerminalConfig[] calldata terminalConfigurations,
543
+ JBAccountingContext[] calldata accountingContextsToAccept,
524
544
  REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
525
545
  REVDeploy721TiersHookConfig calldata tiered721HookConfiguration,
526
546
  REVCroptopAllowedPost[] calldata allowedPosts
@@ -540,7 +560,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
540
560
  revnetId: revnetId,
541
561
  shouldDeployNewRevnet: shouldDeployNewRevnet,
542
562
  configuration: configuration,
543
- terminalConfigurations: terminalConfigurations,
563
+ accountingContextsToAccept: accountingContextsToAccept,
544
564
  suckerDeploymentConfiguration: suckerDeploymentConfiguration,
545
565
  tiered721HookConfiguration: tiered721HookConfiguration,
546
566
  allowedPosts: allowedPosts
@@ -554,7 +574,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
554
574
  function deployFor(
555
575
  uint256 revnetId,
556
576
  REVConfig calldata configuration,
557
- JBTerminalConfig[] calldata terminalConfigurations,
577
+ JBAccountingContext[] calldata accountingContextsToAccept,
558
578
  REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
559
579
  )
560
580
  external
@@ -569,7 +589,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
569
589
  revnetId: revnetId,
570
590
  shouldDeployNewRevnet: shouldDeployNewRevnet,
571
591
  configuration: configuration,
572
- terminalConfigurations: terminalConfigurations,
592
+ accountingContextsToAccept: accountingContextsToAccept,
573
593
  suckerDeploymentConfiguration: suckerDeploymentConfiguration
574
594
  });
575
595
 
@@ -667,7 +687,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
667
687
  uint256 revnetId,
668
688
  bool shouldDeployNewRevnet,
669
689
  REVConfig calldata configuration,
670
- JBTerminalConfig[] calldata terminalConfigurations,
690
+ JBAccountingContext[] calldata accountingContextsToAccept,
671
691
  REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
672
692
  REVDeploy721TiersHookConfig memory tiered721HookConfiguration,
673
693
  REVCroptopAllowedPost[] memory allowedPosts
@@ -680,7 +700,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
680
700
  revnetId: revnetId,
681
701
  shouldDeployNewRevnet: shouldDeployNewRevnet,
682
702
  configuration: configuration,
683
- terminalConfigurations: terminalConfigurations,
703
+ accountingContextsToAccept: accountingContextsToAccept,
684
704
  suckerDeploymentConfiguration: suckerDeploymentConfiguration
685
705
  });
686
706
 
@@ -786,14 +806,14 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
786
806
  /// @param shouldDeployNewRevnet Whether the revnet ID was reserved by this deployment call, or the caller is
787
807
  /// converting an existing Juicebox project into a revnet.
788
808
  /// @param configuration Core revnet configuration. See `REVConfig`.
789
- /// @param terminalConfigurations The terminals to set up for the revnet.
809
+ /// @param accountingContextsToAccept The accounting contexts the canonical multi terminal should accept.
790
810
  /// @param suckerDeploymentConfiguration The suckers to set up for cross-chain token transfers.
791
811
  /// @return encodedConfigurationHash A hash that represents the revnet's configuration.
792
812
  function _deployRevnetFor(
793
813
  uint256 revnetId,
794
814
  bool shouldDeployNewRevnet,
795
815
  REVConfig calldata configuration,
796
- JBTerminalConfig[] calldata terminalConfigurations,
816
+ JBAccountingContext[] calldata accountingContextsToAccept,
797
817
  REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
798
818
  )
799
819
  internal
@@ -802,9 +822,13 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
802
822
  // Normalize and encode the configurations.
803
823
  JBRulesetConfig[] memory rulesetConfigurations;
804
824
  (rulesetConfigurations, encodedConfigurationHash) = _makeRulesetConfigurations({
805
- revnetId: revnetId, configuration: configuration, terminalConfigurations: terminalConfigurations
825
+ revnetId: revnetId, configuration: configuration, accountingContextsToAccept: accountingContextsToAccept
806
826
  });
807
827
 
828
+ // Build the canonical terminal set from the deployer's immutable terminal choices.
829
+ JBTerminalConfig[] memory terminalConfigurations =
830
+ _makeTerminalConfigurations({accountingContextsToAccept: accountingContextsToAccept});
831
+
808
832
  address owner;
809
833
  if (!shouldDeployNewRevnet) {
810
834
  // Keep a reference to the Juicebox project's owner.
@@ -846,20 +870,14 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
846
870
  salt: keccak256(abi.encode(configuration.description.salt, encodedConfigurationHash, _msgSender()))
847
871
  });
848
872
 
849
- // Now that the ERC-20 exists, initialize buyback pools for each terminal token.
850
- for (uint256 i; i < terminalConfigurations.length;) {
851
- JBTerminalConfig calldata terminalConfiguration = terminalConfigurations[i];
852
- for (uint256 j; j < terminalConfiguration.accountingContextsToAccept.length;) {
853
- _tryInitializeBuybackPoolFor({
854
- revnetId: revnetId,
855
- terminalToken: terminalConfiguration.accountingContextsToAccept[j].token,
856
- terminalTokenDecimals: terminalConfiguration.accountingContextsToAccept[j].decimals,
857
- initialIssuance: configuration.stageConfigurations[0].initialIssuance
858
- });
859
- unchecked {
860
- ++j;
861
- }
862
- }
873
+ // Now that the ERC-20 exists, initialize buyback pools for each accepted treasury token.
874
+ for (uint256 i; i < accountingContextsToAccept.length;) {
875
+ _tryInitializeBuybackPoolFor({
876
+ revnetId: revnetId,
877
+ terminalToken: accountingContextsToAccept[i].token,
878
+ terminalTokenDecimals: accountingContextsToAccept[i].decimals,
879
+ initialIssuance: configuration.stageConfigurations[0].initialIssuance
880
+ });
863
881
  unchecked {
864
882
  ++i;
865
883
  }
@@ -924,13 +942,13 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
924
942
  /// configured immutably at deployment time.
925
943
  /// @param revnetId The ID of the revnet to build rulesets for.
926
944
  /// @param configuration The configuration containing the revnet's stages.
927
- /// @param terminalConfigurations The terminals to set up for the revnet.
945
+ /// @param accountingContextsToAccept The accounting contexts the canonical multi terminal should accept.
928
946
  /// @return rulesetConfigurations A list of ruleset configurations derived from the stages.
929
947
  /// @return encodedConfigurationHash A hash that represents the revnet's configuration.
930
948
  function _makeRulesetConfigurations(
931
949
  uint256 revnetId,
932
950
  REVConfig calldata configuration,
933
- JBTerminalConfig[] calldata terminalConfigurations
951
+ JBAccountingContext[] calldata accountingContextsToAccept
934
952
  )
935
953
  internal
936
954
  returns (JBRulesetConfig[] memory rulesetConfigurations, bytes32 encodedConfigurationHash)
@@ -952,19 +970,9 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
952
970
  configuration.description.salt
953
971
  );
954
972
 
955
- // Include terminal addresses in the hash so cross-chain expansions must use the same terminals.
956
- // Terminal addresses are deterministic across chains. Accounting contexts are excluded because
957
- // token addresses (e.g. USDC) legitimately differ per chain.
958
- for (uint256 i; i < terminalConfigurations.length;) {
959
- encodedConfiguration = abi.encode(encodedConfiguration, terminalConfigurations[i].terminal);
960
- unchecked {
961
- ++i;
962
- }
963
- }
964
-
965
973
  // Initialize fund access limit groups for the loan contract.
966
974
  JBFundAccessLimitGroup[] memory fundAccessLimitGroups =
967
- _makeLoanFundAccessLimits({terminalConfigurations: terminalConfigurations});
975
+ _makeLoanFundAccessLimits({accountingContextsToAccept: accountingContextsToAccept});
968
976
 
969
977
  // Track the previous stage's effective start time for ordering validation.
970
978
  // When stage 0 uses `startsAtOrAfter == 0`, the effective value is `block.timestamp`.