@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
@@ -145,6 +145,8 @@ interface IJBTerminalStore {
145
145
  /// @param cashOutCount The number of project tokens being cashed out.
146
146
  /// @param accountingContext The accounting context of the token being reclaimed.
147
147
  /// @param balanceAccountingContexts The accounting contexts to include in the balance calculation.
148
+ /// @param beneficiaryIsFeeless Whether the cash out's beneficiary is a feeless address. Passed through to data
149
+ /// hooks so they can skip their own fees when value stays in the protocol (e.g. project-to-project routing).
148
150
  /// @param metadata Extra data to pass along to the data hook.
149
151
  /// @return ruleset The project's current ruleset.
150
152
  /// @return reclaimAmount The amount reclaimed.
@@ -156,6 +158,7 @@ interface IJBTerminalStore {
156
158
  uint256 cashOutCount,
157
159
  JBAccountingContext calldata accountingContext,
158
160
  JBAccountingContext[] calldata balanceAccountingContexts,
161
+ bool beneficiaryIsFeeless,
159
162
  bytes calldata metadata
160
163
  )
161
164
  external
@@ -36,4 +36,9 @@ interface IJBToken {
36
36
  /// @param account The address to mint tokens to.
37
37
  /// @param amount The amount of tokens to mint.
38
38
  function mint(address account, uint256 amount) external;
39
+
40
+ /// @notice Sets the token's name and symbol.
41
+ /// @param name The new name.
42
+ /// @param symbol The new symbol.
43
+ function setMetadata(string memory name, string memory symbol) external;
39
44
  }
@@ -64,6 +64,13 @@ interface IJBTokens {
64
64
  /// @param caller The address that set the token.
65
65
  event SetToken(uint256 indexed projectId, IJBToken indexed token, address caller);
66
66
 
67
+ /// @notice A project token's name and symbol were updated.
68
+ /// @param projectId The ID of the project whose token was updated.
69
+ /// @param name The new token name.
70
+ /// @param symbol The new token symbol.
71
+ /// @param caller The address that called the function.
72
+ event SetTokenMetadata(uint256 indexed projectId, string name, string symbol, address caller);
73
+
67
74
  /// @notice Credits were transferred from one holder to another.
68
75
  /// @param holder The address that transferred the credits.
69
76
  /// @param projectId The ID of the project whose credits were transferred.
@@ -146,6 +153,12 @@ interface IJBTokens {
146
153
  /// @param token The token to set.
147
154
  function setTokenFor(uint256 projectId, IJBToken token) external;
148
155
 
156
+ /// @notice Sets the name and symbol of a project's token.
157
+ /// @param projectId The ID of the project whose token is being updated.
158
+ /// @param name The new name.
159
+ /// @param symbol The new symbol.
160
+ function setTokenMetadataFor(uint256 projectId, string calldata name, string calldata symbol) external;
161
+
149
162
  /// @notice Transfers credits from one holder to another.
150
163
  /// @param holder The address to transfer credits from.
151
164
  /// @param projectId The ID of the project whose credits are being transferred.
@@ -19,6 +19,8 @@ library JBFees {
19
19
 
20
20
  /// @notice Returns the fee that would be taken from `amountBeforeFee`.
21
21
  /// @dev Use this to forward-calculate the fee from a known pre-fee amount.
22
+ /// @dev Fee rounding error is bounded by N-1 wei (N = number of splits). Economically
23
+ /// insignificant. Rounds down (mulDiv floors), so the fee beneficiary may receive up to 1 wei less per split.
22
24
  /// @param amountBeforeFee The amount before the fee is applied, as a fixed point number.
23
25
  /// @param feePercent The fee percent, out of `JBConstants.MAX_FEE`.
24
26
  /// @return The fee amount, as a fixed point number with the same number of decimals as the provided `amount`.
@@ -60,17 +60,18 @@ library JBMetadataResolver {
60
60
  pure
61
61
  returns (bytes memory newMetadata)
62
62
  {
63
+ // Validate data padding upfront so that the fast path below cannot bypass the check.
64
+ if (dataToAdd.length < 32) revert JBMetadataResolver_DataNotPadded();
65
+
63
66
  // Empty original metadata and maybe something in the first 32 bytes: create new metadata
64
67
  if (originalMetadata.length <= RESERVED_SIZE) {
68
+ // forge-lint: disable-next-line(unsafe-typecast)
65
69
  return abi.encodePacked(bytes32(originalMetadata), bytes32(abi.encodePacked(idToAdd, uint8(2))), dataToAdd);
66
70
  }
67
71
 
68
72
  // There is something in the table offset, but not a valid entry - avoid overwriting
69
73
  if (originalMetadata.length < RESERVED_SIZE + ID_SIZE + 1) revert JBMetadataResolver_MetadataTooShort();
70
74
 
71
- // Make sure the data is padded to 32 bytes.
72
- if (dataToAdd.length < 32) revert JBMetadataResolver_DataNotPadded();
73
-
74
75
  // Get the first data offset - upcast to avoid overflow (same for other offset)...
75
76
  uint256 firstOffset = uint8(originalMetadata[RESERVED_SIZE + ID_SIZE]);
76
77
 
@@ -96,13 +97,16 @@ library JBMetadataResolver {
96
97
  numberOfWordslastData = (originalMetadata.length - lastOffset * WORD_SIZE) / WORD_SIZE;
97
98
 
98
99
  // Copy the reserved word and the table and remove the previous padding
99
- newMetadata = _sliceBytes(originalMetadata, 0, lastOffsetIndex + 1);
100
+ newMetadata = _sliceBytes({data: originalMetadata, start: 0, end: lastOffsetIndex + 1});
100
101
 
101
102
  // Check if the new entry is still fitting in this word
102
103
  if (i + TOTAL_ID_SIZE >= firstOffset * WORD_SIZE) {
103
104
  // Increment every offset by 1 (as the table now takes one more word)
104
105
  for (uint256 j = RESERVED_SIZE + ID_SIZE; j < lastOffsetIndex + 1; j += TOTAL_ID_SIZE) {
105
- newMetadata[j] = bytes1(uint8(originalMetadata[j]) + 1);
106
+ uint256 incremented = uint256(uint8(originalMetadata[j])) + 1;
107
+ if (incremented > 255) revert JBMetadataResolver_MetadataTooLong();
108
+ // forge-lint: disable-next-line(unsafe-typecast)
109
+ newMetadata[j] = bytes1(uint8(incremented));
106
110
  }
107
111
 
108
112
  // Increment the last offset so the new offset will be properly set too
@@ -118,9 +122,14 @@ library JBMetadataResolver {
118
122
  // Compute in uint256 first — casting directly to uint8 silently wraps offsets > 255.
119
123
  uint256 newOffset = lastOffset + numberOfWordslastData;
120
124
  if (newOffset > 255) revert JBMetadataResolver_MetadataTooLong();
125
+ // forge-lint: disable-next-line(unsafe-typecast)
121
126
  newMetadata = abi.encodePacked(newMetadata, idToAdd, bytes1(uint8(newOffset)));
122
127
 
123
128
  // Pad as needed - inlined for gas saving
129
+ // The length inflation to the next 32-byte boundary does NOT read uninitialized memory.
130
+ // abi.encodePacked always advances the free memory pointer to a 32-byte-aligned position, so the
131
+ // padding bytes (up to 31) are within the already-allocated region and guaranteed to be zero by
132
+ // Solidity's virgin-memory invariant. The zeros are the intended table padding per the metadata format.
124
133
  uint256 paddedLength =
125
134
  newMetadata.length % WORD_SIZE == 0 ? newMetadata.length : (newMetadata.length / WORD_SIZE + 1) * WORD_SIZE;
126
135
  assembly ("memory-safe") {
@@ -129,7 +138,8 @@ library JBMetadataResolver {
129
138
 
130
139
  // Add existing data at the end
131
140
  newMetadata = abi.encodePacked(
132
- newMetadata, _sliceBytes(originalMetadata, firstOffset * WORD_SIZE, originalMetadata.length)
141
+ newMetadata,
142
+ _sliceBytes({data: originalMetadata, start: firstOffset * WORD_SIZE, end: originalMetadata.length})
133
143
  );
134
144
 
135
145
  // Pad as needed
@@ -159,6 +169,9 @@ library JBMetadataResolver {
159
169
  function createMetadata(bytes4[] memory ids, bytes[] memory datas) internal pure returns (bytes memory metadata) {
160
170
  if (ids.length != datas.length) revert JBMetadataResolver_LengthMismatch();
161
171
 
172
+ // Return empty bytes for empty input arrays to avoid underflow in offset calculation below.
173
+ if (ids.length == 0) return bytes("");
174
+
162
175
  // Add a first empty 32B for the protocol reserved word
163
176
  metadata = abi.encodePacked(bytes32(0));
164
177
 
@@ -181,6 +194,7 @@ library JBMetadataResolver {
181
194
  revert JBMetadataResolver_DataNotPadded();
182
195
  }
183
196
 
197
+ // forge-lint: disable-next-line(unsafe-typecast)
184
198
  metadata = abi.encodePacked(metadata, ids[i], bytes1(uint8(offset)));
185
199
  offset += data.length / JBMetadataResolver.WORD_SIZE;
186
200
 
@@ -214,6 +228,9 @@ library JBMetadataResolver {
214
228
 
215
229
  /// @notice Parse the metadata to find the data for a specific ID
216
230
  /// @dev Returns false and an empty bytes if no data is found
231
+ /// @dev Padding to 32-byte boundaries is required for ABI compatibility. The apparent
232
+ /// inconsistency between creation and parsing is intentional: creation pads for storage alignment,
233
+ /// parsing uses actual data length boundaries from the lookup table.
217
234
  /// @param id The ID to find.
218
235
  /// @param metadata The metadata to parse.
219
236
  /// @return found Whether the {id:data} was found
@@ -244,7 +261,7 @@ library JBMetadataResolver {
244
261
  ? metadata.length
245
262
  : uint256(uint8(metadata[i + NEXT_ID_OFFSET])) * WORD_SIZE;
246
263
 
247
- return (true, _sliceBytes(metadata, currentOffset * WORD_SIZE, end));
264
+ return (true, _sliceBytes({data: metadata, start: currentOffset * WORD_SIZE, end: end}));
248
265
  }
249
266
  unchecked {
250
267
  i += TOTAL_ID_SIZE;
@@ -135,26 +135,26 @@ library JBRulesetMetadataResolver {
135
135
  /// @param ruleset The funding cycle having its metadata expanded.
136
136
  /// @return rulesetMetadata The ruleset's metadata object.
137
137
  function expandMetadata(JBRuleset memory ruleset) internal pure returns (JBRulesetMetadata memory) {
138
- return JBRulesetMetadata(
139
- reservedPercent(ruleset),
140
- cashOutTaxRate(ruleset),
141
- baseCurrency(ruleset),
142
- pausePay(ruleset),
143
- pauseCreditTransfers(ruleset),
144
- allowOwnerMinting(ruleset),
145
- allowSetCustomToken(ruleset),
146
- allowTerminalMigration(ruleset),
147
- allowSetTerminals(ruleset),
148
- allowSetController(ruleset),
149
- allowAddAccountingContext(ruleset),
150
- allowAddPriceFeed(ruleset),
151
- ownerMustSendPayouts(ruleset),
152
- holdFees(ruleset),
153
- useTotalSurplusForCashOuts(ruleset),
154
- useDataHookForPay(ruleset),
155
- useDataHookForCashOut(ruleset),
156
- dataHook(ruleset),
157
- metadata(ruleset)
158
- );
138
+ return JBRulesetMetadata({
139
+ reservedPercent: reservedPercent(ruleset),
140
+ cashOutTaxRate: cashOutTaxRate(ruleset),
141
+ baseCurrency: baseCurrency(ruleset),
142
+ pausePay: pausePay(ruleset),
143
+ pauseCreditTransfers: pauseCreditTransfers(ruleset),
144
+ allowOwnerMinting: allowOwnerMinting(ruleset),
145
+ allowSetCustomToken: allowSetCustomToken(ruleset),
146
+ allowTerminalMigration: allowTerminalMigration(ruleset),
147
+ allowSetTerminals: allowSetTerminals(ruleset),
148
+ allowSetController: allowSetController(ruleset),
149
+ allowAddAccountingContext: allowAddAccountingContext(ruleset),
150
+ allowAddPriceFeed: allowAddPriceFeed(ruleset),
151
+ ownerMustSendPayouts: ownerMustSendPayouts(ruleset),
152
+ holdFees: holdFees(ruleset),
153
+ useTotalSurplusForCashOuts: useTotalSurplusForCashOuts(ruleset),
154
+ useDataHookForPay: useDataHookForPay(ruleset),
155
+ useDataHookForCashOut: useDataHookForCashOut(ruleset),
156
+ dataHook: dataHook(ruleset),
157
+ metadata: metadata(ruleset)
158
+ });
159
159
  }
160
160
  }
@@ -5,6 +5,7 @@ pragma solidity ^0.8.0;
5
5
  /// @custom:member decimals The number of decimals expected in that token's fixed point accounting.
6
6
  /// @custom:member currency The currency that the token is priced in terms of. By convention, this is
7
7
  /// `uint32(uint160(tokenAddress))` for tokens, or a constant ID from e.g. `JBCurrencyIds` for other currencies.
8
+ // forge-lint: disable-next-line(pascal-case-struct)
8
9
  struct JBAccountingContext {
9
10
  address token;
10
11
  uint8 decimals;
@@ -16,6 +16,7 @@ import {JBTokenAmount} from "./JBTokenAmount.sol";
16
16
  /// @custom:member beneficiary The address the reclaimed amount will be sent to.
17
17
  /// @custom:member hookMetadata Extra data specified by the data hook, which is sent to the cash out hook.
18
18
  /// @custom:member cashOutMetadata Extra data specified by the account cashing out, which is sent to the cash out hook.
19
+ // forge-lint: disable-next-line(pascal-case-struct)
19
20
  struct JBAfterCashOutRecordedContext {
20
21
  address holder;
21
22
  uint256 projectId;
@@ -15,6 +15,7 @@ import {JBTokenAmount} from "./JBTokenAmount.sol";
15
15
  /// @custom:member beneficiary The address which receives any tokens this payment yields.
16
16
  /// @custom:member hookMetadata Extra data specified by the data hook, which is sent to the pay hook.
17
17
  /// @custom:member payerMetadata Extra data specified by the payer, which is sent to the pay hook.
18
+ // forge-lint: disable-next-line(pascal-case-struct)
18
19
  struct JBAfterPayRecordedContext {
19
20
  address payer;
20
21
  uint256 projectId;
@@ -16,7 +16,11 @@ import {JBTokenAmount} from "./JBTokenAmount.sol";
16
16
  /// included, and the currency of the surplus.
17
17
  /// @custom:member useTotalSurplus If surplus across all of a project's terminals is being used when making cash outs.
18
18
  /// @custom:member cashOutTaxRate The cash out tax rate of the ruleset the cash out is being made during.
19
+ /// @custom:member beneficiaryIsFeeless Whether the cash out's beneficiary is a feeless address. Useful for data hooks
20
+ /// that charge their own fees — they can skip fees when value stays in the protocol (e.g. project-to-project
21
+ /// routing).
19
22
  /// @custom:member metadata Extra data provided by the casher.
23
+ // forge-lint: disable-next-line(pascal-case-struct)
20
24
  struct JBBeforeCashOutRecordedContext {
21
25
  address terminal;
22
26
  address holder;
@@ -27,5 +31,6 @@ struct JBBeforeCashOutRecordedContext {
27
31
  JBTokenAmount surplus;
28
32
  bool useTotalSurplus;
29
33
  uint256 cashOutTaxRate;
34
+ bool beneficiaryIsFeeless;
30
35
  bytes metadata;
31
36
  }
@@ -15,6 +15,7 @@ import {JBTokenAmount} from "./JBTokenAmount.sol";
15
15
  /// @custom:member weight The weight of the ruleset during which the payment is being made.
16
16
  /// @custom:member reservedPercent The reserved percent of the ruleset the payment is being made during.
17
17
  /// @custom:member metadata Extra data specified by the payer.
18
+ // forge-lint: disable-next-line(pascal-case-struct)
18
19
  struct JBBeforePayRecordedContext {
19
20
  address terminal;
20
21
  address payer;
@@ -8,6 +8,7 @@ import {IJBCashOutHook} from "../interfaces/IJBCashOutHook.sol";
8
8
  /// @custom:member hook The cash out hook to use when fulfilling this specification.
9
9
  /// @custom:member amount The amount to send to the hook.
10
10
  /// @custom:member metadata Metadata to pass to the hook.
11
+ // forge-lint: disable-next-line(pascal-case-struct)
11
12
  struct JBCashOutHookSpecification {
12
13
  IJBCashOutHook hook;
13
14
  uint256 amount;
@@ -4,6 +4,7 @@ pragma solidity ^0.8.0;
4
4
  /// @custom:member amount The amount of the currency.
5
5
  /// @custom:member currency The currency. By convention, this is `uint32(uint160(tokenAddress))` for tokens, or a
6
6
  /// constant ID from e.g. `JBCurrencyIds` for other currencies.
7
+ // forge-lint: disable-next-line(pascal-case-struct)
7
8
  struct JBCurrencyAmount {
8
9
  uint224 amount;
9
10
  uint32 currency;
@@ -5,6 +5,7 @@ pragma solidity ^0.8.0;
5
5
  /// decimals as the terminal in which this struct was created.
6
6
  /// @custom:member beneficiary The address that will receive the tokens that are minted as a result of the fee payment.
7
7
  /// @custom:member unlockTimestamp The timestamp at which the fee is unlocked and can be processed.
8
+ // forge-lint: disable-next-line(pascal-case-struct)
8
9
  struct JBFee {
9
10
  uint256 amount;
10
11
  address beneficiary;
@@ -20,6 +20,7 @@ import {JBCurrencyAmount} from "./JBCurrencyAmount.sol";
20
20
  /// @custom:member surplusAllowances An array of surplus allowances. The surplus allowances cumulatively dictates the
21
21
  /// maximum value of `token`s a project can pay out from its surplus (balance less payouts) in a terminal during a
22
22
  /// ruleset. Each surplus allowance can have a unique currency and amount.
23
+ // forge-lint: disable-next-line(pascal-case-struct)
23
24
  struct JBFundAccessLimitGroup {
24
25
  address terminal;
25
26
  address token;
@@ -8,6 +8,7 @@ import {IJBPayHook} from "../interfaces/IJBPayHook.sol";
8
8
  /// @custom:member hook The pay hook to use when fulfilling this specification.
9
9
  /// @custom:member amount The amount to send to the hook.
10
10
  /// @custom:member metadata Metadata to pass the hook.
11
+ // forge-lint: disable-next-line(pascal-case-struct)
11
12
  struct JBPayHookSpecification {
12
13
  IJBPayHook hook;
13
14
  uint256 amount;
@@ -6,6 +6,7 @@ pragma solidity ^0.8.0;
6
6
  /// permissions under this project's scope. An ID of 0 is a wildcard, which gives an operator permissions across all
7
7
  /// projects.
8
8
  /// @custom:member permissionIds The IDs of the permissions being given. See the `JBPermissionIds` library.
9
+ // forge-lint: disable-next-line(pascal-case-struct)
9
10
  struct JBPermissionsData {
10
11
  address operator;
11
12
  uint64 projectId;
@@ -29,6 +29,7 @@ import {IJBRulesetApprovalHook} from "./../interfaces/IJBRulesetApprovalHook.sol
29
29
  /// ruleset is rejected, it won't go into effect. An approval hook can be used to create rules which dictate how a
30
30
  /// project owner can change their ruleset over time.
31
31
  /// @custom:member metadata Extra data associated with a ruleset which can be used by other contracts.
32
+ // forge-lint: disable-next-line(pascal-case-struct)
32
33
  struct JBRuleset {
33
34
  uint48 cycleNumber;
34
35
  uint48 id;
@@ -31,6 +31,7 @@ import {JBSplitGroup} from "./JBSplitGroup.sol";
31
31
  /// its balance in each payment terminal while the ruleset is active. Amounts are fixed point numbers using the same
32
32
  /// number of decimals as the corresponding terminal. The `_payoutLimit` and `_surplusAllowance` parameters must fit in
33
33
  /// a `uint232`.
34
+ // forge-lint: disable-next-line(pascal-case-struct)
34
35
  struct JBRulesetConfig {
35
36
  uint48 mustStartAtOrAfter;
36
37
  uint32 duration;
@@ -33,6 +33,7 @@ pragma solidity ^0.8.0;
33
33
  /// @custom:member dataHook The data hook to use during this ruleset.
34
34
  /// @custom:member metadata Metadata of the metadata, only the 14 least significant bits can be used, the 2 most
35
35
  /// significant bits are disregarded.
36
+ // forge-lint: disable-next-line(pascal-case-struct)
36
37
  struct JBRulesetMetadata {
37
38
  uint16 reservedPercent;
38
39
  uint16 cashOutTaxRate;
@@ -3,6 +3,7 @@ pragma solidity ^0.8.0;
3
3
 
4
4
  /// @custom:member weight The cached weight value.
5
5
  /// @custom:member weightCutMultiple The weight cut multiple that produces the given weight.
6
+ // forge-lint: disable-next-line(pascal-case-struct)
6
7
  struct JBRulesetWeightCache {
7
8
  uint112 weight;
8
9
  uint168 weightCutMultiple;
@@ -6,6 +6,7 @@ import {JBRulesetMetadata} from "./JBRulesetMetadata.sol";
6
6
 
7
7
  /// @custom:member ruleset The ruleset.
8
8
  /// @custom:member metadata The ruleset's metadata.
9
+ // forge-lint: disable-next-line(pascal-case-struct)
9
10
  struct JBRulesetWithMetadata {
10
11
  JBRuleset ruleset;
11
12
  JBRulesetMetadata metadata;
@@ -7,6 +7,7 @@ pragma solidity ^0.8.0;
7
7
  /// @custom:member nonce An incrementing value indexed per owner,token,and spender for each signature.
8
8
  /// @custom:member signature The signature over the permit data. Supports EOA signatures, compact signatures defined by
9
9
  /// EIP-2098, and contract signatures defined by EIP-1271.
10
+ // forge-lint: disable-next-line(pascal-case-struct)
10
11
  struct JBSingleAllowance {
11
12
  uint256 sigDeadline;
12
13
  uint160 amount;
@@ -27,6 +27,7 @@ import {IJBSplitHook} from "./../interfaces/IJBSplitHook.sol";
27
27
  /// increased while a split is locked. If `lockedUntil` is zero, this split can be changed at any time.
28
28
  /// @custom:member hook A contract which will receive this split's tokens and properties, and can define custom
29
29
  /// behavior.
30
+ // forge-lint: disable-next-line(pascal-case-struct)
30
31
  struct JBSplit {
31
32
  uint32 percent;
32
33
  uint64 projectId;
@@ -6,6 +6,7 @@ import {JBSplit} from "./JBSplit.sol";
6
6
  /// @custom:member groupId An identifier for the group. By convention, this ID is `uint256(uint160(tokenAddress))` for
7
7
  /// payouts and `1` for reserved tokens.
8
8
  /// @custom:member splits The splits in the group.
9
+ // forge-lint: disable-next-line(pascal-case-struct)
9
10
  struct JBSplitGroup {
10
11
  uint256 groupId;
11
12
  JBSplit[] splits;
@@ -10,6 +10,7 @@ import {JBSplit} from "./JBSplit.sol";
10
10
  /// @custom:member groupId The group the split belongs to. By convention, this ID is `uint256(uint160(tokenAddress))`
11
11
  /// for payouts and `1` for reserved tokens.
12
12
  /// @custom:member split The split which specified the hook.
13
+ // forge-lint: disable-next-line(pascal-case-struct)
13
14
  struct JBSplitHookContext {
14
15
  address token;
15
16
  uint256 amount;
@@ -6,6 +6,7 @@ import {IJBTerminal} from "./../interfaces/IJBTerminal.sol";
6
6
 
7
7
  /// @custom:member terminal The terminal to configure.
8
8
  /// @custom:member accountingContextsToAccept The accounting contexts to accept from the terminal.
9
+ // forge-lint: disable-next-line(pascal-case-struct)
9
10
  struct JBTerminalConfig {
10
11
  IJBTerminal terminal;
11
12
  JBAccountingContext[] accountingContextsToAccept;
@@ -6,6 +6,7 @@ pragma solidity ^0.8.0;
6
6
  /// @custom:member currency The currency. By convention, this is `uint32(uint160(tokenAddress))` for tokens, or a
7
7
  /// constant ID from e.g. `JBCurrencyIds` for other currencies.
8
8
  /// @custom:member value The amount of tokens that was paid, as a fixed point number.
9
+ // forge-lint: disable-next-line(pascal-case-struct)
9
10
  struct JBTokenAmount {
10
11
  address token;
11
12
  uint8 decimals;
@@ -1,8 +1,21 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity ^0.8.6;
3
3
 
4
- import "forge-std/StdInvariant.sol";
5
- import /* {*} from */ "./helpers/TestBaseWorkflow.sol";
4
+ import {StdInvariant} from "forge-std/StdInvariant.sol";
5
+ import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
6
+ import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
7
+ import {IJBSplitHook} from "../src/interfaces/IJBSplitHook.sol";
8
+ import {IJBToken} from "../src/interfaces/IJBToken.sol";
9
+ import {JBConstants} from "../src/libraries/JBConstants.sol";
10
+ import {JBRulesetMetadataResolver} from "../src/libraries/JBRulesetMetadataResolver.sol";
11
+ import {JBCurrencyAmount} from "../src/structs/JBCurrencyAmount.sol";
12
+ import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
13
+ import {JBRuleset} from "../src/structs/JBRuleset.sol";
14
+ import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
15
+ import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
16
+ import {JBSplit} from "../src/structs/JBSplit.sol";
17
+ import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
18
+ import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
6
19
  import {ComprehensiveHandler} from "./invariants/handlers/ComprehensiveHandler.sol";
7
20
  import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
8
21
 
@@ -1,7 +1,32 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity ^0.8.6;
3
3
 
4
- import /* {*} from */ "./helpers/TestBaseWorkflow.sol";
4
+ import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
5
+ import {MetadataResolverHelper} from "./helpers/MetadataResolverHelper.sol";
6
+ import {MockERC20} from "./mock/MockERC20.sol";
7
+ import {JBMultiTerminal} from "../src/JBMultiTerminal.sol";
8
+ import {JBTokens} from "../src/JBTokens.sol";
9
+ import {JBApprovalStatus} from "../src/enums/JBApprovalStatus.sol";
10
+ import {IJBController} from "../src/interfaces/IJBController.sol";
11
+ import {IJBMultiTerminal} from "../src/interfaces/IJBMultiTerminal.sol";
12
+ import {IJBPayHook} from "../src/interfaces/IJBPayHook.sol";
13
+ import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
14
+ import {IJBRulesetDataHook} from "../src/interfaces/IJBRulesetDataHook.sol";
15
+ import {IJBTerminal} from "../src/interfaces/IJBTerminal.sol";
16
+ import {IJBToken} from "../src/interfaces/IJBToken.sol";
17
+ import {JBConstants} from "../src/libraries/JBConstants.sol";
18
+ import {JBFees} from "../src/libraries/JBFees.sol";
19
+ import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
20
+ import {JBCurrencyAmount} from "../src/structs/JBCurrencyAmount.sol";
21
+ import {JBFee} from "../src/structs/JBFee.sol";
22
+ import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
23
+ import {JBPayHookSpecification} from "../src/structs/JBPayHookSpecification.sol";
24
+ import {JBRuleset} from "../src/structs/JBRuleset.sol";
25
+ import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
26
+ import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
27
+ import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
28
+ import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
29
+ import {ERC165, IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
5
30
  import {JBCashOuts} from "../src/libraries/JBCashOuts.sol";
6
31
 
7
32
  /// @notice Tests for edge case scenarios in Juicebox V5.
@@ -1227,7 +1252,9 @@ contract EdgeCases_Local is TestBaseWorkflow {
1227
1252
  uint256 hugeBorrow = uint256(type(uint112).max) + 500 ether;
1228
1253
 
1229
1254
  // Silent truncation — Solidity 0.8.x does NOT revert on explicit downcasts!
1255
+ // forge-lint: disable-next-line(unsafe-typecast)
1230
1256
  uint112 truncatedCollateral = uint112(hugeCollateral);
1257
+ // forge-lint: disable-next-line(unsafe-typecast)
1231
1258
  uint112 truncatedBorrow = uint112(hugeBorrow);
1232
1259
 
1233
1260
  // The truncated values are dramatically smaller.
@@ -2050,6 +2077,7 @@ contract EdgeCases_Local is TestBaseWorkflow {
2050
2077
 
2051
2078
  /// @notice Helper: launches a project with only MockERC20 (6 decimals, simulating USDC on Tempo).
2052
2079
  /// No NATIVE_TOKEN accounting context is registered.
2080
+ // forge-lint: disable-next-line(mixed-case-function)
2053
2081
  function _launchProjectERC20(uint16 cashOutTaxRate, uint16 reservedPercent) internal returns (uint256 projectId) {
2054
2082
  MockERC20 token = usdcToken();
2055
2083
 
@@ -2119,6 +2147,7 @@ contract EdgeCases_Local is TestBaseWorkflow {
2119
2147
  }
2120
2148
 
2121
2149
  /// @notice Helper: launches an ERC-20-only project with payout limits.
2150
+ // forge-lint: disable-next-line(mixed-case-function)
2122
2151
  function _launchProjectERC20WithPayoutLimit(
2123
2152
  uint16 cashOutTaxRate,
2124
2153
  uint224 payoutLimit
@@ -2632,8 +2661,11 @@ contract ReentrancyAttacker {
2632
2661
 
2633
2662
  /// @notice Malicious fee terminal that reenters processHeldFeesOf during pay().
2634
2663
  contract ReentrantFeeTerminal is ERC165 {
2664
+ // forge-lint: disable-next-line(screaming-snake-case-immutable)
2635
2665
  IJBMultiTerminal public immutable victim;
2666
+ // forge-lint: disable-next-line(screaming-snake-case-immutable)
2636
2667
  uint256 public immutable targetProjectId;
2668
+ // forge-lint: disable-next-line(screaming-snake-case-immutable)
2637
2669
  address public immutable targetToken;
2638
2670
  uint256 public payCallCount;
2639
2671
 
@@ -2688,6 +2720,7 @@ contract ReentrantFeeTerminal is ERC165 {
2688
2720
 
2689
2721
  /// @notice Malicious approval hook that always reverts.
2690
2722
  contract MaliciousApprovalHook is ERC165, IJBRulesetApprovalHook {
2723
+ // forge-lint: disable-next-line(mixed-case-function)
2691
2724
  function DURATION() external pure override returns (uint256) {
2692
2725
  return 1 days;
2693
2726
  }
@@ -1,8 +1,16 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity ^0.8.6;
3
3
 
4
- import "forge-std/StdInvariant.sol";
5
- import /* {*} from */ "./helpers/TestBaseWorkflow.sol";
4
+ import {StdInvariant} from "forge-std/StdInvariant.sol";
5
+ import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
6
+ import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
7
+ import {JBRulesetMetadataResolver} from "../src/libraries/JBRulesetMetadataResolver.sol";
8
+ import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
9
+ import {JBRuleset} from "../src/structs/JBRuleset.sol";
10
+ import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
11
+ import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
12
+ import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
13
+ import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
6
14
  import {EconomicHandler} from "./invariants/handlers/EconomicHandler.sol";
7
15
  import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
8
16
  import {JBConstants} from "../src/libraries/JBConstants.sol";
@@ -1,7 +1,17 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity ^0.8.6;
3
3
 
4
- import /* {*} from */ "./helpers/TestBaseWorkflow.sol";
4
+ import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
5
+ import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
6
+ import {JBRulesetMetadataResolver} from "../src/libraries/JBRulesetMetadataResolver.sol";
7
+ import {JBCurrencyAmount} from "../src/structs/JBCurrencyAmount.sol";
8
+ import {JBFee} from "../src/structs/JBFee.sol";
9
+ import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
10
+ import {JBRuleset} from "../src/structs/JBRuleset.sol";
11
+ import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
12
+ import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
13
+ import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
14
+ import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
5
15
  import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
6
16
  import {JBConstants} from "../src/libraries/JBConstants.sol";
7
17
 
@@ -592,7 +602,9 @@ contract EntryPointPermutations_Local is TestBaseWorkflow {
592
602
  if (payoutLimit > 0) {
593
603
  payoutLimits = new JBCurrencyAmount[](1);
594
604
  payoutLimits[0] = JBCurrencyAmount({
595
- amount: uint224(payoutLimit), currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
605
+ // forge-lint: disable-next-line(unsafe-typecast)
606
+ amount: uint224(payoutLimit),
607
+ currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
596
608
  });
597
609
  } else {
598
610
  payoutLimits = new JBCurrencyAmount[](0);
@@ -601,7 +613,9 @@ contract EntryPointPermutations_Local is TestBaseWorkflow {
601
613
  if (surplusAllowance > 0) {
602
614
  surplusAllowances = new JBCurrencyAmount[](1);
603
615
  surplusAllowances[0] = JBCurrencyAmount({
604
- amount: uint224(surplusAllowance), currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
616
+ // forge-lint: disable-next-line(unsafe-typecast)
617
+ amount: uint224(surplusAllowance),
618
+ currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
605
619
  });
606
620
  } else {
607
621
  surplusAllowances = new JBCurrencyAmount[](0);
@@ -1,7 +1,17 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity ^0.8.6;
3
3
 
4
- import /* {*} from */ "./helpers/TestBaseWorkflow.sol";
4
+ import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
5
+ import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
6
+ import {JBConstants} from "../src/libraries/JBConstants.sol";
7
+ import {JBRulesetMetadataResolver} from "../src/libraries/JBRulesetMetadataResolver.sol";
8
+ import {JBCurrencyAmount} from "../src/structs/JBCurrencyAmount.sol";
9
+ import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
10
+ import {JBRuleset} from "../src/structs/JBRuleset.sol";
11
+ import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
12
+ import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
13
+ import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
14
+ import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
5
15
  import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
6
16
 
7
17
  /// @notice Tests that flash-loan style atomic pay+cashOut attacks cannot extract profit.
@@ -548,6 +558,7 @@ contract FlashLoanAttacks_Local is TestBaseWorkflow {
548
558
 
549
559
  // Attacker front-runs: pays right before payout
550
560
  address attacker = address(0xA77AC0);
561
+ // forge-lint: disable-next-line(mixed-case-variable)
551
562
  uint256 attackerInitialETH = 10 ether;
552
563
  vm.deal(attacker, attackerInitialETH);
553
564
  vm.prank(attacker);