@rev-net/core-v6 0.0.11 → 0.0.12

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.
Files changed (49) hide show
  1. package/ADMINISTRATION.md +7 -7
  2. package/ARCHITECTURE.md +11 -11
  3. package/README.md +7 -4
  4. package/RISKS.md +2 -2
  5. package/SKILLS.md +8 -10
  6. package/STYLE_GUIDE.md +14 -1
  7. package/package.json +9 -9
  8. package/script/Deploy.s.sol +85 -35
  9. package/script/helpers/RevnetCoreDeploymentLib.sol +12 -5
  10. package/src/REVDeployer.sol +121 -129
  11. package/src/REVLoans.sol +14 -13
  12. package/src/interfaces/IREVDeployer.sol +25 -22
  13. package/src/structs/REVDeploy721TiersHookConfig.sol +12 -14
  14. package/test/REV.integrations.t.sol +17 -8
  15. package/test/REVAutoIssuanceFuzz.t.sol +9 -4
  16. package/test/REVDeployerRegressions.t.sol +13 -6
  17. package/test/REVInvincibility.t.sol +26 -12
  18. package/test/REVLifecycle.t.sol +9 -4
  19. package/test/REVLoans.invariants.t.sol +13 -6
  20. package/test/REVLoansAttacks.t.sol +12 -5
  21. package/test/REVLoansFeeRecovery.t.sol +12 -5
  22. package/test/REVLoansFindings.t.sol +16 -7
  23. package/test/REVLoansRegressions.t.sol +9 -4
  24. package/test/REVLoansSourced.t.sol +24 -11
  25. package/test/REVLoansUnSourced.t.sol +13 -6
  26. package/test/TestBurnHeldTokens.t.sol +16 -7
  27. package/test/TestCEIPattern.t.sol +12 -5
  28. package/test/TestCashOutCallerValidation.t.sol +12 -5
  29. package/test/TestConversionDocumentation.t.sol +25 -9
  30. package/test/TestCrossSourceReallocation.t.sol +12 -5
  31. package/test/TestEmptyBuybackSpecs.t.sol +23 -8
  32. package/test/TestFlashLoanSurplus.t.sol +12 -5
  33. package/test/TestHookArrayOOB.t.sol +19 -10
  34. package/test/TestLiquidationBehavior.t.sol +12 -5
  35. package/test/TestLowFindings.t.sol +16 -7
  36. package/test/TestMixedFixes.t.sol +16 -7
  37. package/test/TestSplitWeightAdjustment.t.sol +29 -12
  38. package/test/TestSplitWeightE2E.t.sol +24 -16
  39. package/test/TestSplitWeightFork.t.sol +20 -14
  40. package/test/TestStageTransitionBorrowable.t.sol +15 -5
  41. package/test/TestSwapTerminalPermission.t.sol +15 -5
  42. package/test/TestUint112Overflow.t.sol +12 -5
  43. package/test/TestZeroRepayment.t.sol +12 -5
  44. package/test/fork/ForkTestBase.sol +20 -14
  45. package/test/fork/TestCashOutFork.t.sol +8 -2
  46. package/test/fork/TestLoanCrossRulesetFork.t.sol +8 -2
  47. package/test/helpers/REVEmpty721Config.sol +45 -0
  48. package/test/regression/TestCumulativeLoanCounter.t.sol +12 -5
  49. package/test/regression/TestLiquidateGapHandling.t.sol +12 -5
@@ -276,7 +276,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
276
276
  }
277
277
 
278
278
  // Get a reference to the number of tokens being used to pay the fee (out of the total being cashed out).
279
- uint256 feeCashOutCount = mulDiv(context.cashOutCount, FEE, JBConstants.MAX_FEE);
279
+ uint256 feeCashOutCount = mulDiv({x: context.cashOutCount, y: FEE, denominator: JBConstants.MAX_FEE});
280
280
  uint256 nonFeeCashOutCount = context.cashOutCount - feeCashOutCount;
281
281
 
282
282
  // Keep a reference to the amount claimable with non-fee tokens.
@@ -353,7 +353,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
353
353
  if (projectAmount == 0) {
354
354
  weight = 0;
355
355
  } else if (projectAmount < context.amount.value) {
356
- weight = mulDiv(weight, projectAmount, context.amount.value);
356
+ weight = mulDiv({x: weight, y: projectAmount, denominator: context.amount.value});
357
357
  }
358
358
 
359
359
  // Merge hook specifications: 721 hook spec first, then buyback hook spec.
@@ -565,7 +565,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
565
565
  uint256[] memory customSplitOperatorPermissionIndexes = _extraOperatorPermissions[revnetId];
566
566
 
567
567
  // Make the array that merges the default and custom operator permissions.
568
- allOperatorPermissions = new uint256[](8 + customSplitOperatorPermissionIndexes.length);
568
+ allOperatorPermissions = new uint256[](9 + customSplitOperatorPermissionIndexes.length);
569
569
  allOperatorPermissions[0] = JBPermissionIds.SET_SPLIT_GROUPS;
570
570
  allOperatorPermissions[1] = JBPermissionIds.SET_BUYBACK_POOL;
571
571
  allOperatorPermissions[2] = JBPermissionIds.SET_BUYBACK_TWAP;
@@ -574,10 +574,11 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
574
574
  allOperatorPermissions[5] = JBPermissionIds.SUCKER_SAFETY;
575
575
  allOperatorPermissions[6] = JBPermissionIds.SET_BUYBACK_HOOK;
576
576
  allOperatorPermissions[7] = JBPermissionIds.SET_ROUTER_TERMINAL;
577
+ allOperatorPermissions[8] = JBPermissionIds.SET_TOKEN_METADATA;
577
578
 
578
579
  // Copy the custom permissions into the array.
579
580
  for (uint256 i; i < customSplitOperatorPermissionIndexes.length; i++) {
580
- allOperatorPermissions[8 + i] = customSplitOperatorPermissionIndexes[i];
581
+ allOperatorPermissions[9 + i] = customSplitOperatorPermissionIndexes[i];
581
582
  }
582
583
  }
583
584
 
@@ -691,16 +692,21 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
691
692
  /// @param terminalConfigurations The terminals to set up for the revnet. Used for payments and cash outs.
692
693
  /// @param suckerDeploymentConfiguration The suckers to set up for the revnet. Suckers facilitate cross-chain
693
694
  /// token transfers between peer revnets on different networks.
695
+ /// @param tiered721HookConfiguration How to set up the tiered ERC-721 hook for the revnet.
696
+ /// @param allowedPosts Restrictions on which croptop posts are allowed on the revnet's ERC-721 tiers.
694
697
  /// @return revnetId The ID of the newly created revnet.
698
+ /// @return hook The address of the tiered ERC-721 hook that was deployed for the revnet.
695
699
  function deployFor(
696
700
  uint256 revnetId,
697
701
  REVConfig calldata configuration,
698
702
  JBTerminalConfig[] calldata terminalConfigurations,
699
- REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
703
+ REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
704
+ REVDeploy721TiersHookConfig calldata tiered721HookConfiguration,
705
+ REVCroptopAllowedPost[] calldata allowedPosts
700
706
  )
701
707
  external
702
708
  override
703
- returns (uint256)
709
+ returns (uint256, IJB721TiersHook hook)
704
710
  {
705
711
  // Keep a reference to the revnet ID which was passed in.
706
712
  bool shouldDeployNewRevnet = revnetId == 0;
@@ -709,23 +715,69 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
709
715
  // (which will be 1 greater than the current count).
710
716
  if (shouldDeployNewRevnet) revnetId = _nextProjectId();
711
717
 
712
- // Normalize and encode the configurations.
713
- (JBRulesetConfig[] memory rulesetConfigurations, bytes32 encodedConfigurationHash) = _makeRulesetConfigurations({
714
- revnetId: revnetId, configuration: configuration, terminalConfigurations: terminalConfigurations
718
+ // Deploy the revnet with the specified tiered ERC-721 hook and croptop posting criteria.
719
+ hook = _deploy721RevnetFor({
720
+ revnetId: revnetId,
721
+ shouldDeployNewRevnet: shouldDeployNewRevnet,
722
+ configuration: configuration,
723
+ terminalConfigurations: terminalConfigurations,
724
+ suckerDeploymentConfiguration: suckerDeploymentConfiguration,
725
+ tiered721HookConfiguration: tiered721HookConfiguration,
726
+ allowedPosts: allowedPosts
715
727
  });
716
728
 
717
- // Deploy the revnet.
718
- _deployRevnetFor({
729
+ return (revnetId, hook);
730
+ }
731
+
732
+ /// @inheritdoc IREVDeployer
733
+ function deployFor(
734
+ uint256 revnetId,
735
+ REVConfig calldata configuration,
736
+ JBTerminalConfig[] calldata terminalConfigurations,
737
+ REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
738
+ )
739
+ external
740
+ override
741
+ returns (uint256, IJB721TiersHook hook)
742
+ {
743
+ bool shouldDeployNewRevnet = revnetId == 0;
744
+ if (shouldDeployNewRevnet) revnetId = _nextProjectId();
745
+
746
+ // Deploy the revnet (project, rulesets, ERC-20, suckers, etc.).
747
+ bytes32 encodedConfigurationHash = _deployRevnetFor({
719
748
  revnetId: revnetId,
720
749
  shouldDeployNewRevnet: shouldDeployNewRevnet,
721
750
  configuration: configuration,
722
751
  terminalConfigurations: terminalConfigurations,
723
- suckerDeploymentConfiguration: suckerDeploymentConfiguration,
724
- rulesetConfigurations: rulesetConfigurations,
725
- encodedConfigurationHash: encodedConfigurationHash
752
+ suckerDeploymentConfiguration: suckerDeploymentConfiguration
726
753
  });
727
754
 
728
- return revnetId;
755
+ // Deploy a default empty 721 hook for the revnet.
756
+ {
757
+ JBDeploy721TiersHookConfig memory deployConfig;
758
+ deployConfig.tiersConfig.currency = configuration.baseCurrency;
759
+ deployConfig.tiersConfig.decimals = 18;
760
+
761
+ hook = HOOK_DEPLOYER.deployHookFor({
762
+ projectId: revnetId,
763
+ deployTiersHookConfig: deployConfig,
764
+ salt: keccak256(abi.encode(bytes32(0), encodedConfigurationHash, _msgSender()))
765
+ });
766
+ }
767
+
768
+ // Store the tiered ERC-721 hook.
769
+ tiered721HookOf[revnetId] = hook;
770
+
771
+ // Grant the split operator all 721 permissions (no prevent* flags for default config).
772
+ _extraOperatorPermissions[revnetId].push(JBPermissionIds.ADJUST_721_TIERS);
773
+ _extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_METADATA);
774
+ _extraOperatorPermissions[revnetId].push(JBPermissionIds.MINT_721);
775
+ _extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_DISCOUNT_PERCENT);
776
+
777
+ // Give the split operator their permissions (base + 721 extras).
778
+ _setSplitOperatorOf({revnetId: revnetId, operator: configuration.splitOperator});
779
+
780
+ return (revnetId, hook);
729
781
  }
730
782
 
731
783
  /// @notice Burn any of a revnet's tokens held by this contract.
@@ -775,51 +827,6 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
775
827
  });
776
828
  }
777
829
 
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
830
  /// @notice Change a revnet's split operator.
824
831
  /// @dev Only a revnet's current split operator can set a new split operator.
825
832
  /// @param revnetId The ID of the revnet to set the split operator of.
@@ -852,91 +859,86 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
852
859
  function _beforeTransferTo(address to, address token, uint256 amount) internal returns (uint256) {
853
860
  // If the token is the native token, no allowance needed.
854
861
  if (token == JBConstants.NATIVE_TOKEN) return amount;
855
- IERC20(token).safeIncreaseAllowance(to, amount);
862
+ IERC20(token).safeIncreaseAllowance({spender: to, value: amount});
856
863
  return 0;
857
864
  }
858
865
 
859
866
  /// @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
867
  function _deploy721RevnetFor(
871
868
  uint256 revnetId,
872
869
  bool shouldDeployNewRevnet,
873
870
  REVConfig calldata configuration,
874
871
  JBTerminalConfig[] calldata terminalConfigurations,
875
872
  REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
876
- REVDeploy721TiersHookConfig calldata tiered721HookConfiguration,
877
- REVCroptopAllowedPost[] calldata allowedPosts
873
+ REVDeploy721TiersHookConfig memory tiered721HookConfiguration,
874
+ REVCroptopAllowedPost[] memory allowedPosts
878
875
  )
879
876
  internal
880
877
  returns (IJB721TiersHook hook)
881
878
  {
882
- // Normalize and encode the configurations.
883
- (JBRulesetConfig[] memory rulesetConfigurations, bytes32 encodedConfigurationHash) = _makeRulesetConfigurations({
884
- revnetId: revnetId, configuration: configuration, terminalConfigurations: terminalConfigurations
879
+ // Deploy the revnet (project, rulesets, ERC-20, suckers, etc.).
880
+ bytes32 encodedConfigurationHash = _deployRevnetFor({
881
+ revnetId: revnetId,
882
+ shouldDeployNewRevnet: shouldDeployNewRevnet,
883
+ configuration: configuration,
884
+ terminalConfigurations: terminalConfigurations,
885
+ suckerDeploymentConfiguration: suckerDeploymentConfiguration
885
886
  });
886
887
 
887
888
  // Convert the REVBaseline721HookConfig to JBDeploy721TiersHookConfig, forcing issueTokensForSplits to false.
888
889
  // 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
890
  hook = HOOK_DEPLOYER.deployHookFor({
911
891
  projectId: revnetId,
912
- deployTiersHookConfig: hookConfig,
892
+ deployTiersHookConfig: JBDeploy721TiersHookConfig({
893
+ name: tiered721HookConfiguration.baseline721HookConfiguration.name,
894
+ symbol: tiered721HookConfiguration.baseline721HookConfiguration.symbol,
895
+ baseUri: tiered721HookConfiguration.baseline721HookConfiguration.baseUri,
896
+ tokenUriResolver: tiered721HookConfiguration.baseline721HookConfiguration.tokenUriResolver,
897
+ contractUri: tiered721HookConfiguration.baseline721HookConfiguration.contractUri,
898
+ tiersConfig: tiered721HookConfiguration.baseline721HookConfiguration.tiersConfig,
899
+ reserveBeneficiary: tiered721HookConfiguration.baseline721HookConfiguration.reserveBeneficiary,
900
+ flags: JB721TiersHookFlags({
901
+ noNewTiersWithReserves: tiered721HookConfiguration.baseline721HookConfiguration.flags
902
+ .noNewTiersWithReserves,
903
+ noNewTiersWithVotes: tiered721HookConfiguration.baseline721HookConfiguration.flags
904
+ .noNewTiersWithVotes,
905
+ noNewTiersWithOwnerMinting: tiered721HookConfiguration.baseline721HookConfiguration.flags
906
+ .noNewTiersWithOwnerMinting,
907
+ preventOverspending: tiered721HookConfiguration.baseline721HookConfiguration.flags
908
+ .preventOverspending,
909
+ issueTokensForSplits: false
910
+ })
911
+ }),
913
912
  salt: keccak256(abi.encode(tiered721HookConfiguration.salt, encodedConfigurationHash, _msgSender()))
914
913
  });
915
914
 
916
915
  // Store the tiered ERC-721 hook.
917
916
  tiered721HookOf[revnetId] = hook;
918
917
 
919
- // If specified, give the split operator permission to add and remove tiers.
920
- if (tiered721HookConfiguration.splitOperatorCanAdjustTiers) {
918
+ // Give the split operator permission to add and remove tiers unless prevented.
919
+ if (!tiered721HookConfiguration.preventSplitOperatorAdjustingTiers) {
921
920
  _extraOperatorPermissions[revnetId].push(JBPermissionIds.ADJUST_721_TIERS);
922
921
  }
923
922
 
924
- // If specified, give the split operator permission to set ERC-721 tier metadata.
925
- if (tiered721HookConfiguration.splitOperatorCanUpdateMetadata) {
923
+ // Give the split operator permission to set ERC-721 tier metadata unless prevented.
924
+ if (!tiered721HookConfiguration.preventSplitOperatorUpdatingMetadata) {
926
925
  _extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_METADATA);
927
926
  }
928
927
 
929
- // If specified, give the split operator permission to mint ERC-721s (without a payment)
930
- // from tiers with `allowOwnerMint` set to true.
931
- if (tiered721HookConfiguration.splitOperatorCanMint) {
928
+ // Give the split operator permission to mint ERC-721s (without a payment)
929
+ // from tiers with `allowOwnerMint` set to true, unless prevented.
930
+ if (!tiered721HookConfiguration.preventSplitOperatorMinting) {
932
931
  _extraOperatorPermissions[revnetId].push(JBPermissionIds.MINT_721);
933
932
  }
934
933
 
935
- // If specified, give the split operator permission to increase the discount of a tier.
936
- if (tiered721HookConfiguration.splitOperatorCanIncreaseDiscountPercent) {
934
+ // Give the split operator permission to increase the discount of a tier unless prevented.
935
+ if (!tiered721HookConfiguration.preventSplitOperatorIncreasingDiscountPercent) {
937
936
  _extraOperatorPermissions[revnetId].push(JBPermissionIds.SET_721_DISCOUNT_PERCENT);
938
937
  }
939
938
 
939
+ // Give the split operator their permissions (base + 721 extras).
940
+ _setSplitOperatorOf({revnetId: revnetId, operator: configuration.splitOperator});
941
+
940
942
  // If there are posts to allow, configure them.
941
943
  if (allowedPosts.length != 0) {
942
944
  // Keep a reference to the formatted allowed posts.
@@ -945,7 +947,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
945
947
  // Iterate through each post to add it to the formatted list.
946
948
  for (uint256 i; i < allowedPosts.length; i++) {
947
949
  // Set the post being iterated on.
948
- REVCroptopAllowedPost calldata post = allowedPosts[i];
950
+ REVCroptopAllowedPost memory post = allowedPosts[i];
949
951
 
950
952
  // Set the formatted post.
951
953
  formattedAllowedPosts[i] = CTAllowedPost({
@@ -967,16 +969,6 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
967
969
  operator: address(PUBLISHER), revnetId: revnetId, permissionId: JBPermissionIds.ADJUST_721_TIERS
968
970
  });
969
971
  }
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
972
  }
981
973
 
982
974
  /// @notice Deploy a revnet, or initialize an existing Juicebox project as a revnet.
@@ -993,21 +985,22 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
993
985
  /// @param terminalConfigurations The terminals to set up for the revnet. Used for payments and cash outs.
994
986
  /// @param suckerDeploymentConfiguration The suckers to set up for the revnet. Suckers facilitate cross-chain
995
987
  /// token transfers between peer revnets on different networks.
996
- /// @param rulesetConfigurations The rulesets to set up for the revnet.
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.
988
+ /// @return encodedConfigurationHash A hash that represents the revnet's configuration.
1000
989
  function _deployRevnetFor(
1001
990
  uint256 revnetId,
1002
991
  bool shouldDeployNewRevnet,
1003
992
  REVConfig calldata configuration,
1004
993
  JBTerminalConfig[] calldata terminalConfigurations,
1005
- REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
1006
- JBRulesetConfig[] memory rulesetConfigurations,
1007
- bytes32 encodedConfigurationHash
994
+ REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
1008
995
  )
1009
996
  internal
997
+ returns (bytes32 encodedConfigurationHash)
1010
998
  {
999
+ // Normalize and encode the configurations.
1000
+ JBRulesetConfig[] memory rulesetConfigurations;
1001
+ (rulesetConfigurations, encodedConfigurationHash) = _makeRulesetConfigurations({
1002
+ revnetId: revnetId, configuration: configuration, terminalConfigurations: terminalConfigurations
1003
+ });
1011
1004
  if (shouldDeployNewRevnet) {
1012
1005
  // If we're deploying a new revnet, launch a Juicebox project for it.
1013
1006
  // Sanity check that we deployed the `revnetId` that we expected to deploy.
@@ -1064,13 +1057,12 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
1064
1057
  JBTerminalConfig calldata terminalConfiguration = terminalConfigurations[i];
1065
1058
  for (uint256 j; j < terminalConfiguration.accountingContextsToAccept.length; j++) {
1066
1059
  // slither-disable-next-line calls-loop
1067
- _tryInitializeBuybackPoolFor(revnetId, terminalConfiguration.accountingContextsToAccept[j].token);
1060
+ _tryInitializeBuybackPoolFor({
1061
+ revnetId: revnetId, terminalToken: terminalConfiguration.accountingContextsToAccept[j].token
1062
+ });
1068
1063
  }
1069
1064
  }
1070
1065
 
1071
- // Give the split operator their permissions.
1072
- _setSplitOperatorOf({revnetId: revnetId, operator: configuration.splitOperator});
1073
-
1074
1066
  // Deploy the suckers (if applicable).
1075
1067
  if (suckerDeploymentConfiguration.salt != bytes32(0)) {
1076
1068
  _deploySuckersFor({
package/src/REVLoans.sol CHANGED
@@ -255,7 +255,7 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
255
255
  /// @param amount The amount being paid off.
256
256
  /// @return sourceFeeAmount The source fee amount for the loan.
257
257
  function determineSourceFeeAmount(REVLoan memory loan, uint256 amount) public view returns (uint256) {
258
- return _determineSourceFeeAmount(loan, amount);
258
+ return _determineSourceFeeAmount({loan: loan, amount: amount});
259
259
  }
260
260
 
261
261
  /// @notice The revnet ID for the loan with the provided loan ID.
@@ -426,15 +426,15 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
426
426
 
427
427
  uint256 fullSourceFeeAmount = JBFees.feeAmountFrom({
428
428
  amountBeforeFee: loan.amount - prepaid,
429
- feePercent: mulDiv(
430
- timeSinceLoanCreated - loan.prepaidDuration,
431
- JBConstants.MAX_FEE,
432
- LOAN_LIQUIDATION_DURATION - loan.prepaidDuration
433
- )
429
+ feePercent: mulDiv({
430
+ x: timeSinceLoanCreated - loan.prepaidDuration,
431
+ y: JBConstants.MAX_FEE,
432
+ denominator: LOAN_LIQUIDATION_DURATION - loan.prepaidDuration
433
+ })
434
434
  });
435
435
 
436
436
  // Calculate the source fee amount for the amount being paid off.
437
- return mulDiv(fullSourceFeeAmount, amount, loan.amount);
437
+ return mulDiv({x: fullSourceFeeAmount, y: amount, denominator: loan.amount});
438
438
  }
439
439
 
440
440
  /// @notice Generate a ID for a loan given a revnet ID and a loan number within that revnet.
@@ -519,7 +519,7 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
519
519
  decimals: decimals
520
520
  });
521
521
 
522
- borrowedAmount += mulDiv(normalizedTokens, 10 ** decimals, pricePerUnit);
522
+ borrowedAmount += mulDiv({x: normalizedTokens, y: 10 ** decimals, denominator: pricePerUnit});
523
523
  }
524
524
  }
525
525
  }
@@ -558,7 +558,7 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
558
558
  if (collateralCount == 0) revert REVLoans_ZeroCollateralLoanIsInvalid();
559
559
 
560
560
  // Make sure the source terminal is registered in the directory for this revnet.
561
- if (!DIRECTORY.isTerminalOf(revnetId, IJBTerminal(address(source.terminal)))) {
561
+ if (!DIRECTORY.isTerminalOf({projectId: revnetId, terminal: IJBTerminal(address(source.terminal))})) {
562
562
  revert REVLoans_InvalidTerminal(address(source.terminal), revnetId);
563
563
  }
564
564
 
@@ -581,7 +581,8 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
581
581
  loan.source = source;
582
582
  loan.createdAt = uint40(block.timestamp);
583
583
  loan.prepaidFeePercent = uint16(prepaidFeePercent);
584
- loan.prepaidDuration = uint32(mulDiv(prepaidFeePercent, LOAN_LIQUIDATION_DURATION, MAX_PREPAID_FEE_PERCENT));
584
+ loan.prepaidDuration =
585
+ uint32(mulDiv({x: prepaidFeePercent, y: LOAN_LIQUIDATION_DURATION, denominator: MAX_PREPAID_FEE_PERCENT}));
585
586
 
586
587
  // Get the amount of the loan.
587
588
  uint256 borrowAmount = _borrowAmountFrom({loan: loan, revnetId: revnetId, collateralCount: collateralCount});
@@ -794,7 +795,7 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
794
795
  if (repayBorrowAmount == 0 && collateralCountToReturn == 0) revert REVLoans_NothingToRepay();
795
796
 
796
797
  // Keep a reference to the fee that'll be taken.
797
- uint256 sourceFeeAmount = _determineSourceFeeAmount(loan, repayBorrowAmount);
798
+ uint256 sourceFeeAmount = _determineSourceFeeAmount({loan: loan, amount: repayBorrowAmount});
798
799
 
799
800
  // Add the fee to the repay amount.
800
801
  repayBorrowAmount += sourceFeeAmount;
@@ -1093,7 +1094,7 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
1093
1094
  function _beforeTransferTo(address to, address token, uint256 amount) internal returns (uint256) {
1094
1095
  // If the token is the native token, no allowance needed.
1095
1096
  if (token == JBConstants.NATIVE_TOKEN) return amount;
1096
- IERC20(token).safeIncreaseAllowance(to, amount);
1097
+ IERC20(token).safeIncreaseAllowance({spender: to, value: amount});
1097
1098
  return 0;
1098
1099
  }
1099
1100
 
@@ -1342,7 +1343,7 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
1342
1343
  }
1343
1344
 
1344
1345
  // If there's sufficient approval, transfer normally.
1345
- if (IERC20(token).allowance(address(from), address(this)) >= amount) {
1346
+ if (IERC20(token).allowance({owner: address(from), spender: address(this)}) >= amount) {
1346
1347
  return IERC20(token).safeTransferFrom({from: from, to: to, value: amount});
1347
1348
  }
1348
1349
 
@@ -182,52 +182,55 @@ interface IREVDeployer {
182
182
  /// @param revnetId The ID of the revnet whose tokens should be burned.
183
183
  function burnHeldTokensOf(uint256 revnetId) external;
184
184
 
185
- /// @notice Deploy a revnet, or initialize an existing Juicebox project as a revnet.
185
+ /// @notice Deploy a revnet with a tiered ERC-721 hook and optional croptop posting support.
186
+ /// @dev Every revnet gets a 721 hook — pass an empty config if no tiers are needed initially.
186
187
  /// @param revnetId The ID of the Juicebox project to initialize. Send 0 to deploy a new revnet.
187
188
  /// @param configuration Core revnet configuration.
188
189
  /// @param terminalConfigurations The terminals to set up for the revnet.
189
190
  /// @param suckerDeploymentConfiguration The suckers to set up for cross-chain token transfers.
191
+ /// @param tiered721HookConfiguration How to set up the tiered ERC-721 hook for the revnet.
192
+ /// @param allowedPosts Restrictions on which croptop posts are allowed on the revnet's ERC-721 tiers.
190
193
  /// @return The ID of the newly created or initialized revnet.
194
+ /// @return hook The tiered ERC-721 hook that was deployed for the revnet.
191
195
  function deployFor(
192
196
  uint256 revnetId,
193
197
  REVConfig memory configuration,
194
198
  JBTerminalConfig[] memory terminalConfigurations,
195
- REVSuckerDeploymentConfig memory suckerDeploymentConfiguration
196
- )
197
- external
198
- returns (uint256);
199
-
200
- /// @notice Deploy new suckers for an existing revnet.
201
- /// @param revnetId The ID of the revnet to deploy suckers for.
202
- /// @param suckerDeploymentConfiguration The suckers to set up for the revnet.
203
- /// @return suckers The addresses of the deployed suckers.
204
- function deploySuckersFor(
205
- uint256 revnetId,
206
- REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
199
+ REVSuckerDeploymentConfig memory suckerDeploymentConfiguration,
200
+ REVDeploy721TiersHookConfig memory tiered721HookConfiguration,
201
+ REVCroptopAllowedPost[] memory allowedPosts
207
202
  )
208
203
  external
209
- returns (address[] memory suckers);
204
+ returns (uint256, IJB721TiersHook hook);
210
205
 
211
- /// @notice Deploy a revnet with tiered ERC-721s and optional croptop posting support.
206
+ /// @notice Deploy a revnet with a default empty tiered ERC-721 hook.
207
+ /// @dev Convenience overload — constructs an empty 721 config internally and delegates to the 6-arg version.
212
208
  /// @param revnetId The ID of the Juicebox project to initialize. Send 0 to deploy a new revnet.
213
209
  /// @param configuration Core revnet configuration.
214
210
  /// @param terminalConfigurations The terminals to set up for the revnet.
215
211
  /// @param suckerDeploymentConfiguration The suckers to set up for cross-chain token transfers.
216
- /// @param tiered721HookConfiguration How to set up the tiered ERC-721 hook.
217
- /// @param allowedPosts Restrictions on which croptop posts are allowed on the revnet's ERC-721 tiers.
218
212
  /// @return The ID of the newly created or initialized revnet.
219
213
  /// @return hook The tiered ERC-721 hook that was deployed for the revnet.
220
- function deployWith721sFor(
214
+ function deployFor(
221
215
  uint256 revnetId,
222
- REVConfig calldata configuration,
216
+ REVConfig memory configuration,
223
217
  JBTerminalConfig[] memory terminalConfigurations,
224
- REVSuckerDeploymentConfig memory suckerDeploymentConfiguration,
225
- REVDeploy721TiersHookConfig memory tiered721HookConfiguration,
226
- REVCroptopAllowedPost[] memory allowedPosts
218
+ REVSuckerDeploymentConfig memory suckerDeploymentConfiguration
227
219
  )
228
220
  external
229
221
  returns (uint256, IJB721TiersHook hook);
230
222
 
223
+ /// @notice Deploy new suckers for an existing revnet.
224
+ /// @param revnetId The ID of the revnet to deploy suckers for.
225
+ /// @param suckerDeploymentConfiguration The suckers to set up for the revnet.
226
+ /// @return suckers The addresses of the deployed suckers.
227
+ function deploySuckersFor(
228
+ uint256 revnetId,
229
+ REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
230
+ )
231
+ external
232
+ returns (address[] memory suckers);
233
+
231
234
  /// @notice Change a revnet's split operator. Only the current split operator can call this.
232
235
  /// @param revnetId The ID of the revnet.
233
236
  /// @param newSplitOperator The new split operator's address.
@@ -5,21 +5,19 @@ import {REVBaseline721HookConfig} from "./REVBaseline721HookConfig.sol";
5
5
 
6
6
  /// @custom:member baseline721HookConfiguration The baseline config.
7
7
  /// @custom:member salt The salt to base the collection's address on.
8
- /// @custom:member splitOperatorCanAdjustTiers A flag indicating if the revnet's split operator can add tiers and remove
9
- /// tiers if
10
- /// the tier is allowed to be removed
11
- /// @custom:member splitOperatorCanUpdateMetadata A flag indicating if the revnet's split operator can update the 721's
12
- /// metadata.
13
- /// @custom:member splitOperatorCanMint A flag indicating if the revnet's split operator can mint 721's from tiers that
14
- /// allow it.
15
- /// @custom:member splitOperatorCanIncreaseDiscountPercent A flag indicating if the revnet's split operator can increase
16
- /// the
17
- /// discount of a tier.
8
+ /// @custom:member preventSplitOperatorAdjustingTiers A flag indicating if the revnet's split operator should be
9
+ /// prevented from adding tiers and removing tiers that are allowed to be removed.
10
+ /// @custom:member preventSplitOperatorUpdatingMetadata A flag indicating if the revnet's split operator should be
11
+ /// prevented from updating the 721's metadata.
12
+ /// @custom:member preventSplitOperatorMinting A flag indicating if the revnet's split operator should be prevented from
13
+ /// minting 721's from tiers that allow it.
14
+ /// @custom:member preventSplitOperatorIncreasingDiscountPercent A flag indicating if the revnet's split operator should
15
+ /// be prevented from increasing the discount of a tier.
18
16
  struct REVDeploy721TiersHookConfig {
19
17
  REVBaseline721HookConfig baseline721HookConfiguration;
20
18
  bytes32 salt;
21
- bool splitOperatorCanAdjustTiers;
22
- bool splitOperatorCanUpdateMetadata;
23
- bool splitOperatorCanMint;
24
- bool splitOperatorCanIncreaseDiscountPercent;
19
+ bool preventSplitOperatorAdjustingTiers;
20
+ bool preventSplitOperatorUpdatingMetadata;
21
+ bool preventSplitOperatorMinting;
22
+ bool preventSplitOperatorIncreasingDiscountPercent;
25
23
  }