@bananapus/core-v6 0.0.15 → 0.0.17

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 (231) hide show
  1. package/ADMINISTRATION.md +5 -1
  2. package/ARCHITECTURE.md +2 -1
  3. package/AUDIT_INSTRUCTIONS.md +342 -0
  4. package/CHANGE_LOG.md +375 -0
  5. package/README.md +6 -6
  6. package/RISKS.md +171 -50
  7. package/SKILLS.md +11 -6
  8. package/STYLE_GUIDE.md +16 -2
  9. package/USER_JOURNEYS.md +622 -0
  10. package/package.json +2 -2
  11. package/script/Deploy.s.sol +22 -13
  12. package/script/DeployPeriphery.s.sol +76 -52
  13. package/script/helpers/CoreDeploymentLib.sol +83 -35
  14. package/src/JBChainlinkV3PriceFeed.sol +1 -0
  15. package/src/JBController.sol +23 -3
  16. package/src/JBDeadline.sol +3 -0
  17. package/src/JBDirectory.sol +2 -1
  18. package/src/JBERC20.sol +12 -3
  19. package/src/JBFundAccessLimits.sol +12 -2
  20. package/src/JBMultiTerminal.sol +53 -10
  21. package/src/JBPermissions.sol +3 -0
  22. package/src/JBPrices.sol +8 -2
  23. package/src/JBProjects.sol +1 -1
  24. package/src/JBRulesets.sol +14 -0
  25. package/src/JBSplits.sol +14 -5
  26. package/src/JBTerminalStore.sol +57 -47
  27. package/src/JBTokens.sol +43 -4
  28. package/src/interfaces/IJBController.sol +6 -0
  29. package/src/interfaces/IJBPermitTerminal.sol +1 -0
  30. package/src/interfaces/IJBTerminalStore.sol +3 -0
  31. package/src/interfaces/IJBToken.sol +5 -0
  32. package/src/interfaces/IJBTokens.sol +13 -0
  33. package/src/libraries/JBFees.sol +2 -0
  34. package/src/libraries/JBMetadataResolver.sol +24 -7
  35. package/src/libraries/JBRulesetMetadataResolver.sol +21 -21
  36. package/src/structs/JBAccountingContext.sol +1 -0
  37. package/src/structs/JBAfterCashOutRecordedContext.sol +1 -0
  38. package/src/structs/JBAfterPayRecordedContext.sol +1 -0
  39. package/src/structs/JBBeforeCashOutRecordedContext.sol +5 -0
  40. package/src/structs/JBBeforePayRecordedContext.sol +1 -0
  41. package/src/structs/JBCashOutHookSpecification.sol +1 -0
  42. package/src/structs/JBCurrencyAmount.sol +1 -0
  43. package/src/structs/JBFee.sol +1 -0
  44. package/src/structs/JBFundAccessLimitGroup.sol +1 -0
  45. package/src/structs/JBPayHookSpecification.sol +1 -0
  46. package/src/structs/JBPermissionsData.sol +1 -0
  47. package/src/structs/JBRuleset.sol +1 -0
  48. package/src/structs/JBRulesetConfig.sol +1 -0
  49. package/src/structs/JBRulesetMetadata.sol +1 -0
  50. package/src/structs/JBRulesetWeightCache.sol +1 -0
  51. package/src/structs/JBRulesetWithMetadata.sol +1 -0
  52. package/src/structs/JBSingleAllowance.sol +1 -0
  53. package/src/structs/JBSplit.sol +1 -0
  54. package/src/structs/JBSplitGroup.sol +1 -0
  55. package/src/structs/JBSplitHookContext.sol +1 -0
  56. package/src/structs/JBTerminalConfig.sol +1 -0
  57. package/src/structs/JBTokenAmount.sol +1 -0
  58. package/test/ComprehensiveInvariant.t.sol +15 -2
  59. package/test/CoreExploitTests.t.sol +34 -1
  60. package/test/EconomicSimulation.t.sol +10 -2
  61. package/test/EntryPointPermutations.t.sol +17 -3
  62. package/test/FlashLoanAttacks.t.sol +12 -1
  63. package/test/PermissionEscalation.t.sol +53 -10
  64. package/test/RulesetTransitions.t.sol +15 -1
  65. package/test/SplitLoopTests.t.sol +25 -2
  66. package/test/TestAccessToFunds.sol +17 -2
  67. package/test/TestAuditResponseDesignProofs.sol +434 -0
  68. package/test/TestCashOut.sol +15 -1
  69. package/test/TestCashOutCountFor.sol +1 -1
  70. package/test/TestCashOutHooks.sol +47 -25
  71. package/test/TestCashOutTimingEdge.sol +13 -1
  72. package/test/TestDataHookFuzzing.sol +520 -0
  73. package/test/TestDurationUnderflow.sol +13 -1
  74. package/test/TestFeeFreeCashOutBypass.sol +617 -0
  75. package/test/TestFeeProcessingFailure.sol +16 -1
  76. package/test/TestFees.sol +14 -1
  77. package/test/TestInterfaceSupport.sol +20 -1
  78. package/test/TestJBERC20Inheritance.sol +11 -1
  79. package/test/TestL2SequencerPriceFeed.sol +292 -0
  80. package/test/TestLaunchProject.sol +13 -1
  81. package/test/TestMetaTx.sol +15 -1
  82. package/test/TestMetadataOffsetOverflow.sol +179 -0
  83. package/test/TestMetadataParserLib.sol +37 -4
  84. package/test/TestMigrationHeldFees.sol +16 -1
  85. package/test/TestMintTokensOf.sol +14 -1
  86. package/test/TestMultiTerminalSurplus.sol +348 -0
  87. package/test/TestMultiTokenSurplus.sol +14 -1
  88. package/test/TestMultipleAccessLimits.sol +23 -1
  89. package/test/TestPayBurnRedeemFlow.sol +16 -1
  90. package/test/TestPayHooks.sol +33 -14
  91. package/test/TestPermissions.sol +20 -1
  92. package/test/TestPermissionsEdge.sol +5 -1
  93. package/test/TestPermit2DataHook.t.sol +360 -0
  94. package/test/TestPermit2Terminal.sol +36 -3
  95. package/test/TestRulesetQueueing.sol +23 -1
  96. package/test/TestRulesetQueuingStress.sol +20 -1
  97. package/test/TestRulesetWeightCaching.sol +127 -125
  98. package/test/TestSplits.sol +23 -1
  99. package/test/TestTerminalMigration.sol +11 -1
  100. package/test/TestTokenFlow.sol +18 -1
  101. package/test/TestWeightCacheStaleAfterRejection.sol +15 -1
  102. package/test/WeirdTokenTests.t.sol +54 -1
  103. package/test/fork/TestChainlinkPriceFeedFork.sol +6 -1
  104. package/test/formal/BondingCurveProperties.t.sol +8 -1
  105. package/test/formal/FeeProperties.t.sol +7 -1
  106. package/test/helpers/JBTest.sol +1 -1
  107. package/test/helpers/TestBaseWorkflow.sol +84 -1
  108. package/test/invariants/Phase3DeepInvariant.t.sol +13 -2
  109. package/test/invariants/RulesetsInvariant.t.sol +12 -2
  110. package/test/invariants/TerminalStoreInvariant.t.sol +11 -2
  111. package/test/invariants/TokensInvariant.t.sol +13 -2
  112. package/test/invariants/handlers/ComprehensiveHandler.sol +19 -1
  113. package/test/invariants/handlers/EconomicHandler.sol +31 -1
  114. package/test/invariants/handlers/Phase3Handler.sol +31 -1
  115. package/test/invariants/handlers/RulesetsHandler.sol +5 -1
  116. package/test/invariants/handlers/TerminalStoreHandler.sol +6 -1
  117. package/test/invariants/handlers/TokensHandler.sol +1 -1
  118. package/test/mock/MockERC20.sol +0 -2
  119. package/test/mock/MockMaliciousBeneficiary.sol +2 -1
  120. package/test/mock/MockMaliciousSplitHook.sol +2 -1
  121. package/test/mock/MockPriceFeed.sol +1 -1
  122. package/test/regression/HoldFeesCashOutReserved.t.sol +415 -0
  123. package/test/regression/WeightCacheBoundary.t.sol +291 -0
  124. package/test/units/static/JBChainlinkV3PriceFeed/TestPriceFeed.sol +0 -1
  125. package/test/units/static/JBController/JBControllerSetup.sol +10 -1
  126. package/test/units/static/JBController/TestBurnTokensOf.sol +8 -1
  127. package/test/units/static/JBController/TestClaimTokensFor.sol +4 -1
  128. package/test/units/static/JBController/TestDeployErc20For.sol +7 -1
  129. package/test/units/static/JBController/TestLaunchProjectFor.sol +21 -1
  130. package/test/units/static/JBController/TestLaunchRulesetsFor.sol +21 -1
  131. package/test/units/static/JBController/TestMigrateController.sol +10 -1
  132. package/test/units/static/JBController/TestMintTokensOfUnits.sol +10 -1
  133. package/test/units/static/JBController/TestPayReservedTokenToTerminal.sol +4 -1
  134. package/test/units/static/JBController/TestReceiveMigrationFrom.sol +5 -1
  135. package/test/units/static/JBController/TestRulesetViews.sol +7 -1
  136. package/test/units/static/JBController/TestSendReservedTokensToSplitsOf.sol +21 -1
  137. package/test/units/static/JBController/TestSetSplitGroupsOf.sol +6 -1
  138. package/test/units/static/JBController/TestSetTokenFor.sol +13 -1
  139. package/test/units/static/JBController/TestSetUriOf.sol +5 -1
  140. package/test/units/static/JBController/TestTransferCreditsFrom.sol +11 -1
  141. package/test/units/static/JBDeadline/TestDeadlineFuzz.sol +12 -1
  142. package/test/units/static/JBDirectory/JBDirectorySetup.sol +4 -1
  143. package/test/units/static/JBDirectory/TestPrimaryTerminalOf.sol +5 -1
  144. package/test/units/static/JBDirectory/TestSetControllerOf.sol +11 -1
  145. package/test/units/static/JBDirectory/TestSetControllerOfMigrationOrder.sol +7 -1
  146. package/test/units/static/JBDirectory/TestSetPrimaryTerminalOf.sol +11 -1
  147. package/test/units/static/JBDirectory/TestSetTerminalsOf.sol +10 -1
  148. package/test/units/static/JBERC20/JBERC20Setup.sol +2 -1
  149. package/test/units/static/JBERC20/SigUtils.sol +2 -0
  150. package/test/units/static/JBERC20/TestInitialize.sol +1 -1
  151. package/test/units/static/JBERC20/TestName.sol +1 -1
  152. package/test/units/static/JBERC20/TestNonces.sol +3 -1
  153. package/test/units/static/JBERC20/TestSymbol.sol +1 -1
  154. package/test/units/static/JBFeelessAdresses/JBFeelessSetup.sol +2 -1
  155. package/test/units/static/JBFeelessAdresses/TestInterfaces.sol +2 -1
  156. package/test/units/static/JBFeelessAdresses/TestSetFeelessAddress.sol +1 -1
  157. package/test/units/static/JBFees/TestFeesFuzz.sol +1 -1
  158. package/test/units/static/JBFixedPointNumber/TestAdjustDecimals.sol +0 -1
  159. package/test/units/static/JBFixedPointNumber/TestAdjustDecimalsFuzz.sol +0 -1
  160. package/test/units/static/JBFundAccessLimits/JBFundAccessSetup.sol +3 -1
  161. package/test/units/static/JBFundAccessLimits/TestFundAccessLimitsEdge.sol +4 -1
  162. package/test/units/static/JBFundAccessLimits/TestPayoutLimitOf.sol +4 -1
  163. package/test/units/static/JBFundAccessLimits/TestPayoutLimitsOf.sol +8 -1
  164. package/test/units/static/JBFundAccessLimits/TestSetFundAccessLimitsFor.sol +8 -1
  165. package/test/units/static/JBFundAccessLimits/TestSurplusAllowanceOf.sol +4 -1
  166. package/test/units/static/JBFundAccessLimits/TestSurplusAllowancesOf.sol +7 -1
  167. package/test/units/static/JBMetadataResolver/TestGetDataFor.sol +1 -1
  168. package/test/units/static/JBMetadataResolver/TestMetadataResolverEdgeCases.sol +2 -1
  169. package/test/units/static/JBMetadataResolver/TestMetadataResolverFuzz.sol +2 -1
  170. package/test/units/static/JBMultiTerminal/JBMultiTerminalSetup.sol +12 -1
  171. package/test/units/static/JBMultiTerminal/TestAccountingContextsOf.sol +9 -1
  172. package/test/units/static/JBMultiTerminal/TestAddAccountingContextsFor.sol +18 -2
  173. package/test/units/static/JBMultiTerminal/TestAddToBalanceOf.sol +44 -9
  174. package/test/units/static/JBMultiTerminal/TestCashOutTokensOf.sol +48 -23
  175. package/test/units/static/JBMultiTerminal/TestExecutePayout.sol +18 -2
  176. package/test/units/static/JBMultiTerminal/TestExecuteProcessFee.sol +13 -3
  177. package/test/units/static/JBMultiTerminal/TestMigrateBalanceOf.sol +21 -4
  178. package/test/units/static/JBMultiTerminal/TestPay.sol +35 -7
  179. package/test/units/static/JBMultiTerminal/TestProcessHeldFeesOf.sol +206 -19
  180. package/test/units/static/JBMultiTerminal/TestSendPayoutsOf.sol +15 -1
  181. package/test/units/static/JBMultiTerminal/TestUseAllowanceOf.sol +297 -1
  182. package/test/units/static/JBPermissions/JBPermissionsSetup.sol +2 -1
  183. package/test/units/static/JBPermissions/TestHasPermission.sol +1 -1
  184. package/test/units/static/JBPermissions/TestHasPermissions.sol +1 -1
  185. package/test/units/static/JBPermissions/TestSetPermissionsFor.sol +3 -1
  186. package/test/units/static/JBPrices/JBPricesSetup.sol +6 -1
  187. package/test/units/static/JBPrices/TestAddPriceFeedFor.sol +6 -1
  188. package/test/units/static/JBPrices/TestPricePerUnitOf.sol +4 -1
  189. package/test/units/static/JBPrices/TestPrices.sol +4 -1
  190. package/test/units/static/JBProjects/JBProjectsSetup.sol +2 -1
  191. package/test/units/static/JBProjects/TestCreateFor.sol +3 -1
  192. package/test/units/static/JBProjects/TestInitialProject.sol +2 -1
  193. package/test/units/static/JBProjects/TestInterfaces.sol +0 -1
  194. package/test/units/static/JBProjects/TestSetResolver.sol +2 -1
  195. package/test/units/static/JBProjects/TestTokenUri.sol +3 -1
  196. package/test/units/static/JBRulesetMetadataResolver/TestSetCashOutTaxRateTo.sol +9 -1
  197. package/test/units/static/JBRulesets/JBRulesetsSetup.sol +3 -1
  198. package/test/units/static/JBRulesets/TestCurrentApprovalStatusForLatestRulesetOf.sol +9 -1
  199. package/test/units/static/JBRulesets/TestCurrentOf.sol +10 -1
  200. package/test/units/static/JBRulesets/TestGetRulesetOf.sol +7 -1
  201. package/test/units/static/JBRulesets/TestLatestQueuedRulesetOf.sol +9 -1
  202. package/test/units/static/JBRulesets/TestRulesets.sol +12 -1
  203. package/test/units/static/JBRulesets/TestRulesetsOf.sol +1 -1
  204. package/test/units/static/JBRulesets/TestUpcomingRulesetOf.sol +10 -1
  205. package/test/units/static/JBRulesets/TestUpdateRulesetWeightCache.sol +6 -1
  206. package/test/units/static/JBSplits/JBSplitsSetup.sol +3 -1
  207. package/test/units/static/JBSplits/TestSelfManagedSplitGroups.sol +63 -13
  208. package/test/units/static/JBSplits/TestSetSplitGroupsOf.sol +8 -1
  209. package/test/units/static/JBSplits/TestSplitsLockedEdge.sol +6 -1
  210. package/test/units/static/JBSplits/TestSplitsOf.sol +1 -1
  211. package/test/units/static/JBSplits/TestSplitsPacking.sol +5 -2
  212. package/test/units/static/JBSurplus/TestSurplusFuzz.sol +3 -1
  213. package/test/units/static/JBTerminalStore/JBTerminalStoreSetup.sol +5 -1
  214. package/test/units/static/JBTerminalStore/TestCurrentReclaimableSurplusOf.sol +14 -1
  215. package/test/units/static/JBTerminalStore/TestCurrentSurplusOf.sol +14 -1
  216. package/test/units/static/JBTerminalStore/TestCurrentTotalSurplusOf.sol +3 -1
  217. package/test/units/static/JBTerminalStore/TestRecordCashOutsFor.sol +92 -1
  218. package/test/units/static/JBTerminalStore/TestRecordPaymentFrom.sol +15 -1
  219. package/test/units/static/JBTerminalStore/TestRecordPayoutFor.sol +13 -1
  220. package/test/units/static/JBTerminalStore/TestRecordTerminalMigration.sol +8 -1
  221. package/test/units/static/JBTerminalStore/TestRecordUsedAllowanceOf.sol +16 -1
  222. package/test/units/static/JBTerminalStore/TestUint224Overflow.sol +15 -1
  223. package/test/units/static/JBTokens/JBTokensSetup.sol +5 -1
  224. package/test/units/static/JBTokens/TestBurnFrom.sol +4 -1
  225. package/test/units/static/JBTokens/TestClaimTokensFor.sol +4 -1
  226. package/test/units/static/JBTokens/TestDeployERC20ForUnits.sol +4 -1
  227. package/test/units/static/JBTokens/TestMintFor.sol +4 -1
  228. package/test/units/static/JBTokens/TestSetTokenFor.sol +4 -1
  229. package/test/units/static/JBTokens/TestTotalBalanceOf.sol +1 -1
  230. package/test/units/static/JBTokens/TestTotalSupplyOf.sol +1 -1
  231. package/test/units/static/JBTokens/TestTransferCreditsFrom.sol +3 -1
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
4
+ import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
5
5
  import {Script} from "forge-std/Script.sol";
6
6
 
7
7
  import {IPermit2} from "@uniswap/permit2/src/interfaces/IPermit2.sol";
@@ -26,16 +26,20 @@ contract Deploy is Script, Sphinx {
26
26
 
27
27
  /// @notice The address that is allowed to forward calls to the terminal and controller on a users behalf.
28
28
  string private constant TRUSTED_FORWARDER_NAME = "Juicebox";
29
+ // forge-lint: disable-next-line(mixed-case-variable)
29
30
  address private TRUSTED_FORWARDER;
30
31
 
31
32
  /// @notice The address that will manage the few privileged functions of the protocol.
33
+ // forge-lint: disable-next-line(mixed-case-variable)
32
34
  address private MANAGER;
33
35
 
34
36
  /// @notice The address that will own the fee-project.
37
+ // forge-lint: disable-next-line(mixed-case-variable)
35
38
  address private FEE_PROJECT_OWNER;
36
39
 
37
40
  /// @notice The nonce that gets used across all chains to sync deployment addresses and allow for new deployments of
38
41
  /// the same bytecode.
42
+ // forge-lint: disable-next-line(mixed-case-variable)
39
43
  uint256 private CORE_DEPLOYMENT_NONCE = 6;
40
44
 
41
45
  function configureSphinx() public override {
@@ -61,19 +65,24 @@ contract Deploy is Script, Sphinx {
61
65
 
62
66
  JBPermissions permissions =
63
67
  new JBPermissions{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}(TRUSTED_FORWARDER);
64
- JBProjects projects = new JBProjects{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}(
65
- safeAddress(), safeAddress(), TRUSTED_FORWARDER
66
- );
67
- JBDirectory directory =
68
- new JBDirectory{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}(permissions, projects, safeAddress());
68
+ JBProjects projects = new JBProjects{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}({
69
+ owner: safeAddress(), feeProjectOwner: safeAddress(), trustedForwarder: TRUSTED_FORWARDER
70
+ });
71
+ JBDirectory directory = new JBDirectory{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}({
72
+ permissions: permissions, projects: projects, owner: safeAddress()
73
+ });
69
74
  JBSplits splits = new JBSplits{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}(directory);
70
75
  JBRulesets rulesets = new JBRulesets{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}(directory);
71
- JBPrices prices = new JBPrices{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}(
72
- directory, permissions, projects, safeAddress(), TRUSTED_FORWARDER
73
- );
74
- JBTokens tokens = new JBTokens{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}(
75
- directory, new JBERC20{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}()
76
- );
76
+ JBPrices prices = new JBPrices{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}({
77
+ directory: directory,
78
+ permissions: permissions,
79
+ projects: projects,
80
+ owner: safeAddress(),
81
+ trustedForwarder: TRUSTED_FORWARDER
82
+ });
83
+ JBTokens tokens = new JBTokens{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}({
84
+ directory: directory, token: new JBERC20{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}()
85
+ });
77
86
 
78
87
  new JBFundAccessLimits{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}(directory);
79
88
 
@@ -103,7 +112,7 @@ contract Deploy is Script, Sphinx {
103
112
 
104
113
  // Transfer ownership to the fee project owner.
105
114
  if (FEE_PROJECT_OWNER != safeAddress() && FEE_PROJECT_OWNER != address(0)) {
106
- projects.safeTransferFrom(safeAddress(), FEE_PROJECT_OWNER, 1);
115
+ projects.safeTransferFrom({from: safeAddress(), to: FEE_PROJECT_OWNER, tokenId: 1});
107
116
  }
108
117
  }
109
118
  }
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
4
+ import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
5
5
  import {Script} from "forge-std/Script.sol";
6
6
  import {CoreDeployment, CoreDeploymentLib} from "./helpers/CoreDeploymentLib.sol";
7
7
 
@@ -23,13 +23,17 @@ contract DeployPeriphery is Script, Sphinx {
23
23
  /// @notice tracks the deployment of the core contracts for the chain we are deploying to.
24
24
  CoreDeployment core;
25
25
 
26
+ // forge-lint: disable-next-line(mixed-case-variable)
26
27
  address private TRUSTED_FORWARDER;
27
28
 
29
+ // forge-lint: disable-next-line(mixed-case-variable)
28
30
  bytes32 private DEADLINES_SALT = keccak256("_JBDeadlinesV6_");
31
+ // forge-lint: disable-next-line(mixed-case-variable)
29
32
  bytes32 private USD_NATIVE_FEED_SALT = keccak256("USD_FEEDV6");
30
33
 
31
34
  /// @notice The nonce that gets used across all chains to sync deployment addresses and allow for new deployments of
32
35
  /// the same bytecode.
36
+ // forge-lint: disable-next-line(mixed-case-variable)
33
37
  uint256 private CORE_DEPLOYMENT_NONCE = 6;
34
38
 
35
39
  /// @notice The address of the omnichain ruleset operator contract (e.g. JBOmnichainDeployer).
@@ -39,6 +43,7 @@ contract DeployPeriphery is Script, Sphinx {
39
43
  /// @dev This address should correspond to the deterministic CREATE2 deployment of the omnichain deployer contract
40
44
  /// from the nana-omnichain-deployers-v6 repository. Verify it matches the deployed address on all target chains
41
45
  /// before running this script.
46
+ // forge-lint: disable-next-line(mixed-case-variable)
42
47
  address private OMNICHAIN_RULESET_OPERATOR = address(0x8f5DED85c40b50d223269C1F922A056E72101590);
43
48
 
44
49
  function configureSphinx() public override {
@@ -71,6 +76,7 @@ contract DeployPeriphery is Script, Sphinx {
71
76
  matchingPriceFeed = new JBMatchingPriceFeed();
72
77
 
73
78
  // Same as the chainlink example grace period.
79
+ // forge-lint: disable-next-line(mixed-case-variable)
74
80
  uint256 L2GracePeriod = 3600 seconds;
75
81
 
76
82
  // NOTE: Feeds come from this url `https://data.chain.link/feeds/ethereum/mainnet/eth-usd`.
@@ -78,13 +84,15 @@ contract DeployPeriphery is Script, Sphinx {
78
84
 
79
85
  // Perform the deploy for L1(s).
80
86
  if (block.chainid == 1) {
81
- feed = new JBChainlinkV3PriceFeed{salt: USD_NATIVE_FEED_SALT}(
82
- AggregatorV3Interface(address(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419)), 3600 seconds
83
- );
87
+ feed = new JBChainlinkV3PriceFeed{salt: USD_NATIVE_FEED_SALT}({
88
+ feed: AggregatorV3Interface(address(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419)),
89
+ threshold: 3600 seconds
90
+ });
84
91
  } else if (block.chainid == 11_155_111) {
85
- feed = new JBChainlinkV3PriceFeed{salt: USD_NATIVE_FEED_SALT}(
86
- AggregatorV3Interface(address(0x694AA1769357215DE4FAC081bf1f309aDC325306)), 3600 seconds
87
- );
92
+ feed = new JBChainlinkV3PriceFeed{salt: USD_NATIVE_FEED_SALT}({
93
+ feed: AggregatorV3Interface(address(0x694AA1769357215DE4FAC081bf1f309aDC325306)),
94
+ threshold: 3600 seconds
95
+ });
88
96
  } else {
89
97
  // Perform the deploy for L2s
90
98
  AggregatorV3Interface source;
@@ -92,47 +100,47 @@ contract DeployPeriphery is Script, Sphinx {
92
100
  // Optimism
93
101
  if (block.chainid == 10) {
94
102
  source = AggregatorV3Interface(0x13e3Ee699D1909E989722E753853AE30b17e08c5);
95
- feed = new JBChainlinkV3SequencerPriceFeed{salt: USD_NATIVE_FEED_SALT}(
96
- source,
97
- 3600 seconds,
98
- AggregatorV2V3Interface(0x371EAD81c9102C9BF4874A9075FFFf170F2Ee389),
99
- L2GracePeriod
100
- );
103
+ feed = new JBChainlinkV3SequencerPriceFeed{salt: USD_NATIVE_FEED_SALT}({
104
+ feed: source,
105
+ threshold: 3600 seconds,
106
+ sequencerFeed: AggregatorV2V3Interface(0x371EAD81c9102C9BF4874A9075FFFf170F2Ee389),
107
+ gracePeriod: L2GracePeriod
108
+ });
101
109
  }
102
110
  // Optimism Sepolia
103
111
  else if (block.chainid == 11_155_420) {
104
112
  source = AggregatorV3Interface(address(0x61Ec26aA57019C486B10502285c5A3D4A4750AD7));
105
- feed = new JBChainlinkV3PriceFeed{salt: USD_NATIVE_FEED_SALT}(source, 3600 seconds);
113
+ feed = new JBChainlinkV3PriceFeed{salt: USD_NATIVE_FEED_SALT}({feed: source, threshold: 3600 seconds});
106
114
  }
107
115
  // Base
108
116
  else if (block.chainid == 8453) {
109
117
  source = AggregatorV3Interface(0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70);
110
- feed = new JBChainlinkV3SequencerPriceFeed{salt: USD_NATIVE_FEED_SALT}(
111
- source,
112
- 3600 seconds,
113
- AggregatorV2V3Interface(0xBCF85224fc0756B9Fa45aA7892530B47e10b6433),
114
- L2GracePeriod
115
- );
118
+ feed = new JBChainlinkV3SequencerPriceFeed{salt: USD_NATIVE_FEED_SALT}({
119
+ feed: source,
120
+ threshold: 3600 seconds,
121
+ sequencerFeed: AggregatorV2V3Interface(0xBCF85224fc0756B9Fa45aA7892530B47e10b6433),
122
+ gracePeriod: L2GracePeriod
123
+ });
116
124
  }
117
125
  // Base Sepolia
118
126
  else if (block.chainid == 84_532) {
119
127
  source = AggregatorV3Interface(address(0x4aDC67696bA383F43DD60A9e78F2C97Fbbfc7cb1));
120
- feed = new JBChainlinkV3PriceFeed{salt: USD_NATIVE_FEED_SALT}(source, 3600 seconds);
128
+ feed = new JBChainlinkV3PriceFeed{salt: USD_NATIVE_FEED_SALT}({feed: source, threshold: 3600 seconds});
121
129
  }
122
130
  // Arbitrum
123
131
  else if (block.chainid == 42_161) {
124
132
  source = AggregatorV3Interface(0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612);
125
- feed = new JBChainlinkV3SequencerPriceFeed{salt: USD_NATIVE_FEED_SALT}(
126
- source,
127
- 3600 seconds,
128
- AggregatorV2V3Interface(0xFdB631F5EE196F0ed6FAa767959853A9F217697D),
129
- L2GracePeriod
130
- );
133
+ feed = new JBChainlinkV3SequencerPriceFeed{salt: USD_NATIVE_FEED_SALT}({
134
+ feed: source,
135
+ threshold: 3600 seconds,
136
+ sequencerFeed: AggregatorV2V3Interface(0xFdB631F5EE196F0ed6FAa767959853A9F217697D),
137
+ gracePeriod: L2GracePeriod
138
+ });
131
139
  }
132
140
  // Arbitrum Sepolia
133
141
  else if (block.chainid == 421_614) {
134
142
  source = AggregatorV3Interface(address(0xd30e2101a97dcbAeBCBC04F14C3f624E67A35165));
135
- feed = new JBChainlinkV3PriceFeed{salt: USD_NATIVE_FEED_SALT}(source, 3600 seconds);
143
+ feed = new JBChainlinkV3PriceFeed{salt: USD_NATIVE_FEED_SALT}({feed: source, threshold: 3600 seconds});
136
144
  } else {
137
145
  revert("Unsupported chain");
138
146
  }
@@ -169,25 +177,25 @@ contract DeployPeriphery is Script, Sphinx {
169
177
  _deployUSDCFeed(L2GracePeriod);
170
178
 
171
179
  // Deploy the JBDeadlines
172
- if (!_isDeployed(DEADLINES_SALT, type(JBDeadline3Hours).creationCode, "")) {
180
+ if (!_isDeployed({salt: DEADLINES_SALT, creationCode: type(JBDeadline3Hours).creationCode, arguments: ""})) {
173
181
  new JBDeadline3Hours{salt: DEADLINES_SALT}();
174
182
  }
175
183
 
176
- if (!_isDeployed(DEADLINES_SALT, type(JBDeadline1Day).creationCode, "")) {
184
+ if (!_isDeployed({salt: DEADLINES_SALT, creationCode: type(JBDeadline1Day).creationCode, arguments: ""})) {
177
185
  new JBDeadline1Day{salt: DEADLINES_SALT}();
178
186
  }
179
187
 
180
- if (!_isDeployed(DEADLINES_SALT, type(JBDeadline3Days).creationCode, "")) {
188
+ if (!_isDeployed({salt: DEADLINES_SALT, creationCode: type(JBDeadline3Days).creationCode, arguments: ""})) {
181
189
  new JBDeadline3Days{salt: DEADLINES_SALT}();
182
190
  }
183
191
 
184
- if (!_isDeployed(DEADLINES_SALT, type(JBDeadline7Days).creationCode, "")) {
192
+ if (!_isDeployed({salt: DEADLINES_SALT, creationCode: type(JBDeadline7Days).creationCode, arguments: ""})) {
185
193
  new JBDeadline7Days{salt: DEADLINES_SALT}();
186
194
  }
187
195
 
188
196
  core.directory
189
- .setIsAllowedToSetFirstController(
190
- address(
197
+ .setIsAllowedToSetFirstController({
198
+ addr: address(
191
199
  new JBController{salt: keccak256(abi.encode(CORE_DEPLOYMENT_NONCE))}({
192
200
  directory: core.directory,
193
201
  fundAccessLimits: core.fundAccess,
@@ -201,24 +209,27 @@ contract DeployPeriphery is Script, Sphinx {
201
209
  trustedForwarder: TRUSTED_FORWARDER
202
210
  })
203
211
  ),
204
- true
205
- );
212
+ flag: true
213
+ });
206
214
  }
207
215
 
216
+ // forge-lint: disable-next-line(mixed-case-function, mixed-case-variable)
208
217
  function _deployUSDCFeed(uint256 L2GracePeriod) internal {
209
218
  IJBPriceFeed usdcFeed;
210
219
  address usdc;
211
220
 
212
221
  if (block.chainid == 1) {
213
222
  usdc = address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
214
- usdcFeed = new JBChainlinkV3PriceFeed(
215
- AggregatorV3Interface(address(0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6)), 86_400 seconds
216
- );
223
+ usdcFeed = new JBChainlinkV3PriceFeed({
224
+ feed: AggregatorV3Interface(address(0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6)),
225
+ threshold: 86_400 seconds
226
+ });
217
227
  } else if (block.chainid == 11_155_111) {
218
228
  usdc = address(0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238);
219
- usdcFeed = new JBChainlinkV3PriceFeed(
220
- AggregatorV3Interface(address(0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E)), 86_400 seconds
221
- );
229
+ usdcFeed = new JBChainlinkV3PriceFeed({
230
+ feed: AggregatorV3Interface(address(0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E)),
231
+ threshold: 86_400 seconds
232
+ });
222
233
  } else if (block.chainid == 10) {
223
234
  usdc = address(0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85);
224
235
  usdcFeed = new JBChainlinkV3SequencerPriceFeed({
@@ -229,9 +240,10 @@ contract DeployPeriphery is Script, Sphinx {
229
240
  });
230
241
  } else if (block.chainid == 11_155_420) {
231
242
  usdc = address(0x5fd84259d66Cd46123540766Be93DFE6D43130D7);
232
- usdcFeed = new JBChainlinkV3PriceFeed(
233
- AggregatorV3Interface(address(0x6e44e50E3cc14DD16e01C590DC1d7020cb36eD4C)), 86_400 seconds
234
- );
243
+ usdcFeed = new JBChainlinkV3PriceFeed({
244
+ feed: AggregatorV3Interface(address(0x6e44e50E3cc14DD16e01C590DC1d7020cb36eD4C)),
245
+ threshold: 86_400 seconds
246
+ });
235
247
  } else if (block.chainid == 8453) {
236
248
  usdc = address(0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913);
237
249
  usdcFeed = new JBChainlinkV3SequencerPriceFeed({
@@ -242,9 +254,13 @@ contract DeployPeriphery is Script, Sphinx {
242
254
  });
243
255
  } else if (block.chainid == 84_532) {
244
256
  usdc = address(0x036CbD53842c5426634e7929541eC2318f3dCF7e);
245
- usdcFeed = new JBChainlinkV3PriceFeed(
246
- AggregatorV3Interface(address(0xd30e2101a97dcbAeBCBC04F14C3f624E67A35165)), 86_400 seconds
247
- );
257
+ // TODO: Verify this feed address — 0xd30e2101... is the Arbitrum Sepolia ETH/USD feed and is likely
258
+ // incorrect for Base Sepolia USDC/USD. Replace with the correct Chainlink Base Sepolia USDC/USD address
259
+ // before deploying. Testnet-only; does not affect mainnet deployments.
260
+ usdcFeed = new JBChainlinkV3PriceFeed({
261
+ feed: AggregatorV3Interface(address(0xd30e2101a97dcbAeBCBC04F14C3f624E67A35165)),
262
+ threshold: 86_400 seconds
263
+ });
248
264
  } else if (block.chainid == 42_161) {
249
265
  usdc = address(0xaf88d065e77c8cC2239327C5EDb3A432268e5831);
250
266
  usdcFeed = new JBChainlinkV3SequencerPriceFeed({
@@ -255,9 +271,10 @@ contract DeployPeriphery is Script, Sphinx {
255
271
  });
256
272
  } else if (block.chainid == 421_614) {
257
273
  usdc = address(0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d);
258
- usdcFeed = new JBChainlinkV3PriceFeed(
259
- AggregatorV3Interface(address(0x0153002d20B96532C639313c2d54c3dA09109309)), 86_400 seconds
260
- );
274
+ usdcFeed = new JBChainlinkV3PriceFeed({
275
+ feed: AggregatorV3Interface(address(0x0153002d20B96532C639313c2d54c3dA09109309)),
276
+ threshold: 86_400 seconds
277
+ });
261
278
  } else {
262
279
  revert("Unsupported chain for USDC feed");
263
280
  }
@@ -267,10 +284,17 @@ contract DeployPeriphery is Script, Sphinx {
267
284
 
268
285
  core.prices
269
286
  .addPriceFeedFor({
270
- projectId: 0, pricingCurrency: JBCurrencyIds.USD, unitCurrency: uint32(uint160(usdc)), feed: usdcFeed
287
+ projectId: 0,
288
+ pricingCurrency: JBCurrencyIds.USD,
289
+ // forge-lint: disable-next-line(unsafe-typecast)
290
+ unitCurrency: uint32(uint160(usdc)),
291
+ feed: usdcFeed
271
292
  });
272
293
  }
273
294
 
295
+ /// @dev This helper predicts addresses using the Arachnid CREATE2 deployer, but actual deployments go through
296
+ /// Sphinx (which uses a different deployer). As a result, this guard will never detect Sphinx-deployed contracts
297
+ /// and is only effective for contracts deployed via the Arachnid deployer directly.
274
298
  function _isDeployed(bytes32 salt, bytes memory creationCode, bytes memory arguments) internal view returns (bool) {
275
299
  address _deployedTo = vm.computeCreate2Address({
276
300
  salt: salt,
@@ -38,6 +38,7 @@ struct CoreDeployment {
38
38
  library CoreDeploymentLib {
39
39
  // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D.
40
40
  address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
41
+ // forge-lint: disable-next-line(screaming-snake-case-const)
41
42
  Vm internal constant vm = Vm(VM_ADDRESS);
42
43
  string constant PROJECT_NAME = "nana-core-v5";
43
44
 
@@ -52,7 +53,7 @@ library CoreDeploymentLib {
52
53
 
53
54
  for (uint256 _i; _i < networks.length; _i++) {
54
55
  if (networks[_i].chainId == chainId) {
55
- return getDeployment(path, networks[_i].name);
56
+ return getDeployment({path: path, networkName: networks[_i].name});
56
57
  }
57
58
  }
58
59
 
@@ -61,41 +62,87 @@ library CoreDeploymentLib {
61
62
 
62
63
  function getDeployment(
63
64
  string memory path,
64
- string memory network_name
65
+ string memory networkName
65
66
  )
66
67
  internal
67
68
  view
68
69
  returns (CoreDeployment memory deployment)
69
70
  {
70
- deployment.permissions = JBPermissions(_getDeploymentAddress(path, PROJECT_NAME, network_name, "JBPermissions"));
71
-
72
- deployment.projects = JBProjects(_getDeploymentAddress(path, PROJECT_NAME, network_name, "JBProjects"));
73
-
74
- deployment.directory = JBDirectory(_getDeploymentAddress(path, PROJECT_NAME, network_name, "JBDirectory"));
75
-
76
- deployment.splits = JBSplits(_getDeploymentAddress(path, PROJECT_NAME, network_name, "JBSplits"));
77
-
78
- deployment.rulesets = JBRulesets(_getDeploymentAddress(path, PROJECT_NAME, network_name, "JBRulesets"));
79
-
80
- deployment.controller = JBController(_getDeploymentAddress(path, PROJECT_NAME, network_name, "JBController"));
81
-
82
- deployment.terminal =
83
- JBMultiTerminal(_getDeploymentAddress(path, PROJECT_NAME, network_name, "JBMultiTerminal"));
84
-
85
- deployment.terminalStore =
86
- JBTerminalStore(_getDeploymentAddress(path, PROJECT_NAME, network_name, "JBTerminalStore"));
87
-
88
- deployment.prices = JBPrices(_getDeploymentAddress(path, PROJECT_NAME, network_name, "JBPrices"));
89
-
90
- deployment.feeless =
91
- JBFeelessAddresses(_getDeploymentAddress(path, PROJECT_NAME, network_name, "JBFeelessAddresses"));
92
-
93
- deployment.fundAccess =
94
- JBFundAccessLimits(_getDeploymentAddress(path, PROJECT_NAME, network_name, "JBFundAccessLimits"));
95
-
96
- deployment.tokens = JBTokens(_getDeploymentAddress(path, PROJECT_NAME, network_name, "JBTokens"));
97
-
98
- deployment.trustedForwarder = _getDeploymentAddress(path, PROJECT_NAME, network_name, "ERC2771Forwarder");
71
+ deployment.permissions = JBPermissions(
72
+ _getDeploymentAddress({
73
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBPermissions"
74
+ })
75
+ );
76
+
77
+ deployment.projects = JBProjects(
78
+ _getDeploymentAddress({
79
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBProjects"
80
+ })
81
+ );
82
+
83
+ deployment.directory = JBDirectory(
84
+ _getDeploymentAddress({
85
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBDirectory"
86
+ })
87
+ );
88
+
89
+ deployment.splits = JBSplits(
90
+ _getDeploymentAddress({
91
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBSplits"
92
+ })
93
+ );
94
+
95
+ deployment.rulesets = JBRulesets(
96
+ _getDeploymentAddress({
97
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBRulesets"
98
+ })
99
+ );
100
+
101
+ deployment.controller = JBController(
102
+ _getDeploymentAddress({
103
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBController"
104
+ })
105
+ );
106
+
107
+ deployment.terminal = JBMultiTerminal(
108
+ _getDeploymentAddress({
109
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBMultiTerminal"
110
+ })
111
+ );
112
+
113
+ deployment.terminalStore = JBTerminalStore(
114
+ _getDeploymentAddress({
115
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBTerminalStore"
116
+ })
117
+ );
118
+
119
+ deployment.prices = JBPrices(
120
+ _getDeploymentAddress({
121
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBPrices"
122
+ })
123
+ );
124
+
125
+ deployment.feeless = JBFeelessAddresses(
126
+ _getDeploymentAddress({
127
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBFeelessAddresses"
128
+ })
129
+ );
130
+
131
+ deployment.fundAccess = JBFundAccessLimits(
132
+ _getDeploymentAddress({
133
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBFundAccessLimits"
134
+ })
135
+ );
136
+
137
+ deployment.tokens = JBTokens(
138
+ _getDeploymentAddress({
139
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBTokens"
140
+ })
141
+ );
142
+
143
+ deployment.trustedForwarder = _getDeploymentAddress({
144
+ path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "ERC2771Forwarder"
145
+ });
99
146
  }
100
147
 
101
148
  /// @notice Get the address of a contract that was deployed by the Deploy script.
@@ -105,8 +152,8 @@ library CoreDeploymentLib {
105
152
  /// @return The address of the contract.
106
153
  function _getDeploymentAddress(
107
154
  string memory path,
108
- string memory project_name,
109
- string memory network_name,
155
+ string memory projectName,
156
+ string memory networkName,
110
157
  string memory contractName
111
158
  )
112
159
  internal
@@ -114,7 +161,8 @@ library CoreDeploymentLib {
114
161
  returns (address)
115
162
  {
116
163
  string memory deploymentJson =
117
- vm.readFile(string.concat(path, project_name, "/", network_name, "/", contractName, ".json"));
118
- return stdJson.readAddress(deploymentJson, ".address");
164
+ // forge-lint: disable-next-line(unsafe-cheatcode)
165
+ vm.readFile(string.concat(path, projectName, "/", networkName, "/", contractName, ".json"));
166
+ return stdJson.readAddress({json: deploymentJson, key: ".address"});
119
167
  }
120
168
  }
@@ -68,6 +68,7 @@ contract JBChainlinkV3PriceFeed is IJBPriceFeed {
68
68
  uint256 feedDecimals = FEED.decimals();
69
69
 
70
70
  // Return the price, adjusted to the specified number of decimals.
71
+ // forge-lint: disable-next-line(unsafe-typecast)
71
72
  return uint256(price).adjustDecimals({decimals: feedDecimals, targetDecimals: decimals});
72
73
  }
73
74
  }
@@ -95,6 +95,11 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
95
95
  IJBTokens public immutable override TOKENS;
96
96
 
97
97
  /// @notice The address of the contract that manages omnichain ruleset ops.
98
+ /// @dev This is a deterministic CREATE2 deployment; bytecode verification at runtime would add
99
+ /// gas
100
+ /// cost for marginal security benefit since the address is verified at deploy time.
101
+ /// @dev Trust assumption is bounded: the operator can only queue rulesets that the omnichain
102
+ /// deployer's logic permits. It cannot drain funds or bypass access controls.
98
103
  address public immutable override OMNICHAIN_RULESET_OPERATOR;
99
104
 
100
105
  //*********************************************************************//
@@ -336,7 +341,7 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
336
341
  require(msg.sender == address(this));
337
342
 
338
343
  // Approve the tokens being paid.
339
- IERC20(address(token)).forceApprove(address(terminal), splitTokenCount);
344
+ IERC20(address(token)).forceApprove({spender: address(terminal), value: splitTokenCount});
340
345
 
341
346
  // slither-disable-next-line unused-return
342
347
  terminal.pay({
@@ -350,7 +355,7 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
350
355
  });
351
356
 
352
357
  // Make sure that the terminal received the tokens.
353
- if (IERC20(address(token)).allowance(address(this), address(terminal)) != 0) {
358
+ if (IERC20(address(token)).allowance({owner: address(this), spender: address(terminal)}) != 0) {
354
359
  revert JBController_TerminalTokensNotTransferred();
355
360
  }
356
361
  }
@@ -646,6 +651,21 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
646
651
  TOKENS.setTokenFor({projectId: projectId, token: token});
647
652
  }
648
653
 
654
+ /// @notice Sets the name and symbol of a project's token.
655
+ /// @dev Can only be called by the project's owner or an address with the owner's permission to
656
+ /// `SET_TOKEN_METADATA`.
657
+ /// @param projectId The ID of the project whose token is being updated.
658
+ /// @param name The new name.
659
+ /// @param symbol The new symbol.
660
+ function setTokenMetadataOf(uint256 projectId, string calldata name, string calldata symbol) external override {
661
+ // Enforce permissions.
662
+ _requirePermissionFrom({
663
+ account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.SET_TOKEN_METADATA
664
+ });
665
+
666
+ TOKENS.setTokenMetadataFor({projectId: projectId, name: name, symbol: symbol});
667
+ }
668
+
649
669
  /// @notice Set a project's metadata URI.
650
670
  /// @dev This is typically an IPFS hash, optionally with an `ipfs://` prefix.
651
671
  /// @dev Can only be called by the project's owner or an address with the owner's permission to
@@ -1026,7 +1046,7 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
1026
1046
  });
1027
1047
 
1028
1048
  // If it fails, transfer the tokens from this contract to the beneficiary.
1029
- IERC20(address(token)).safeTransfer(beneficiary, splitTokenCount);
1049
+ IERC20(address(token)).safeTransfer({to: beneficiary, value: splitTokenCount});
1030
1050
  }
1031
1051
  }
1032
1052
  } else if (beneficiary == address(0xdead)) {
@@ -11,6 +11,9 @@ import {JBRuleset} from "./structs/JBRuleset.sol";
11
11
  /// seconds before the current ruleset ends. In other words, rulesets must be queued before the deadline to take effect.
12
12
  /// @dev Project rulesets are stored in a queue. Rulesets take effect after the previous ruleset in the queue ends, and
13
13
  /// only if they are approved by the previous ruleset's approval hook.
14
+ /// @dev If `DURATION` is set longer than the ruleset's cycle duration, no queued ruleset can ever satisfy the deadline
15
+ /// and the current ruleset will effectively be locked in perpetuity. Choose a `DURATION` shorter than the shortest
16
+ /// cycle it will govern.
14
17
  contract JBDeadline is IJBRulesetApprovalHook {
15
18
  //*********************************************************************//
16
19
  // ---------------- public immutable stored properties --------------- //
@@ -185,7 +185,8 @@ contract JBDirectory is JBPermissioned, Ownable, IJBDirectory {
185
185
  revert JBDirectory_TokenNotAccepted(projectId, token, terminal);
186
186
  }
187
187
 
188
- // If the terminal hasn't already been added to the project, add it.
188
+ // Implicit terminal addition is by design. A primary terminal must be in the terminals list;
189
+ // implicit addition avoids requiring a separate addTerminalsOf call.
189
190
  _addTerminalIfNeeded({projectId: projectId, terminal: terminal});
190
191
 
191
192
  // Store the terminal as the project's primary terminal for the token.
package/src/JBERC20.sol CHANGED
@@ -47,7 +47,7 @@ contract JBERC20 is ERC20Votes, ERC20Permit, Ownable, IJBToken {
47
47
  /// @param account The address to burn tokens from.
48
48
  /// @param amount The amount of tokens to burn, as a fixed point number with 18 decimals.
49
49
  function burn(address account, uint256 amount) external override onlyOwner {
50
- return _burn(account, amount);
50
+ return _burn({account: account, value: amount});
51
51
  }
52
52
 
53
53
  /// @notice Mints more of this token.
@@ -55,7 +55,16 @@ contract JBERC20 is ERC20Votes, ERC20Permit, Ownable, IJBToken {
55
55
  /// @param account The address to mint the new tokens to.
56
56
  /// @param amount The amount of tokens to mint, as a fixed point number with 18 decimals.
57
57
  function mint(address account, uint256 amount) external override onlyOwner {
58
- return _mint(account, amount);
58
+ return _mint({account: account, value: amount});
59
+ }
60
+
61
+ /// @notice Sets the token's name and symbol.
62
+ /// @dev Can only be called by this contract's owner.
63
+ /// @param name_ The new name.
64
+ /// @param symbol_ The new symbol.
65
+ function setMetadata(string memory name_, string memory symbol_) external override onlyOwner {
66
+ _name = name_;
67
+ _symbol = symbol_;
59
68
  }
60
69
 
61
70
  //*********************************************************************//
@@ -130,6 +139,6 @@ contract JBERC20 is ERC20Votes, ERC20Permit, Ownable, IJBToken {
130
139
 
131
140
  /// @notice Required override.
132
141
  function _update(address from, address to, uint256 value) internal virtual override(ERC20, ERC20Votes) {
133
- super._update(from, to, value);
142
+ super._update({from: from, to: to, value: value});
134
143
  }
135
144
  }