@bananapus/core-v6 0.0.37 → 0.0.38

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 (287) hide show
  1. package/foundry.lock +1 -7
  2. package/foundry.toml +1 -1
  3. package/package.json +19 -7
  4. package/src/JBController.sol +19 -1
  5. package/src/JBMultiTerminal.sol +68 -34
  6. package/src/JBTerminalStore.sol +6 -6
  7. package/src/interfaces/IJBController.sol +4 -1
  8. package/src/libraries/JBFees.sol +47 -9
  9. package/src/libraries/JBPayoutSplitGroupLib.sol +2 -2
  10. package/src/periphery/JBMatchingPriceFeed.sol +1 -1
  11. package/test/mock/MockMaliciousBeneficiary.sol +15 -15
  12. package/ADMINISTRATION.md +0 -103
  13. package/ARCHITECTURE.md +0 -133
  14. package/AUDIT_INSTRUCTIONS.md +0 -139
  15. package/RISKS.md +0 -215
  16. package/SKILLS.md +0 -55
  17. package/STYLE_GUIDE.md +0 -610
  18. package/USER_JOURNEYS.md +0 -215
  19. package/script/Deploy.s.sol +0 -124
  20. package/script/DeployPeriphery.s.sol +0 -354
  21. package/slither-ci.config.json +0 -10
  22. package/test/AuditFixes.t.sol +0 -808
  23. package/test/ComprehensiveInvariant.t.sol +0 -306
  24. package/test/CoreExploitTests.t.sol +0 -2741
  25. package/test/EconomicSimulation.t.sol +0 -348
  26. package/test/EntryPointPermutations.t.sol +0 -684
  27. package/test/FlashLoanAttacks.t.sol +0 -797
  28. package/test/PermissionEscalation.t.sol +0 -711
  29. package/test/PermissionsInvariant.t.sol +0 -403
  30. package/test/RulesetTransitions.t.sol +0 -713
  31. package/test/SplitLoopTests.t.sol +0 -752
  32. package/test/TestAccessToFunds.sol +0 -2683
  33. package/test/TestAuditResponseDesignProofs.sol +0 -434
  34. package/test/TestCashOut.sol +0 -198
  35. package/test/TestCashOutCountFor.sol +0 -271
  36. package/test/TestCashOutHooks.sol +0 -351
  37. package/test/TestCashOutTimingEdge.sol +0 -241
  38. package/test/TestDataHookFuzzing.sol +0 -524
  39. package/test/TestDurationUnderflow.sol +0 -233
  40. package/test/TestFeeFreeCashOutBypass.sol +0 -949
  41. package/test/TestFeeProcessingFailure.sol +0 -218
  42. package/test/TestFees.sol +0 -619
  43. package/test/TestForwardedTokenConsumption.sol +0 -425
  44. package/test/TestInterfaceSupport.sol +0 -81
  45. package/test/TestJBERC20Inheritance.sol +0 -103
  46. package/test/TestL2SequencerPriceFeed.sol +0 -292
  47. package/test/TestLaunchProject.sol +0 -188
  48. package/test/TestMetaTx.sol +0 -217
  49. package/test/TestMetadataOffsetOverflow.sol +0 -179
  50. package/test/TestMetadataParserLib.sol +0 -471
  51. package/test/TestMigrationHeldFees.sol +0 -255
  52. package/test/TestMintTokensOf.sol +0 -185
  53. package/test/TestMultiTerminalSurplus.sol +0 -348
  54. package/test/TestMultiTokenSurplus.sol +0 -202
  55. package/test/TestMultipleAccessLimits.sol +0 -664
  56. package/test/TestPayBurnRedeemFlow.sol +0 -195
  57. package/test/TestPayHooks.sol +0 -209
  58. package/test/TestPermissions.sol +0 -324
  59. package/test/TestPermissionsEdge.sol +0 -290
  60. package/test/TestPermit2DataHook.t.sol +0 -360
  61. package/test/TestPermit2Terminal.sol +0 -372
  62. package/test/TestRulesetQueueing.sol +0 -1025
  63. package/test/TestRulesetQueuingStress.sol +0 -806
  64. package/test/TestRulesetWeightCaching.sol +0 -178
  65. package/test/TestSplits.sol +0 -391
  66. package/test/TestTerminalMigration.sol +0 -274
  67. package/test/TestTerminalPreviewParity.sol +0 -208
  68. package/test/TestTokenFlow.sol +0 -191
  69. package/test/TestWeightCacheStaleAfterRejection.sol +0 -303
  70. package/test/WeirdTokenTests.t.sol +0 -817
  71. package/test/audit/CashOutReenterPay.t.sol +0 -501
  72. package/test/audit/CodexHeldFeeRounding.t.sol +0 -159
  73. package/test/audit/CodexMigrationFeeFailure.t.sol +0 -163
  74. package/test/audit/CrossTerminalSurplusSpoof.t.sol +0 -140
  75. package/test/audit/CycledSurplusAllowanceReset.t.sol +0 -184
  76. package/test/audit/FeeFreeSurplusLifecycle.t.sol +0 -399
  77. package/test/audit/FeeFreeSurplusStale.t.sol +0 -248
  78. package/test/audit/USDTVoidReturnCompat.t.sol +0 -525
  79. package/test/fork/TestChainlinkPriceFeedFork.sol +0 -254
  80. package/test/fork/TestSequencerPriceFeedFork.sol +0 -168
  81. package/test/fork/TestTerminalPreviewParityFork.sol +0 -108
  82. package/test/formal/BondingCurveProperties.t.sol +0 -420
  83. package/test/formal/FeeProperties.t.sol +0 -252
  84. package/test/invariants/Phase3DeepInvariant.t.sol +0 -412
  85. package/test/invariants/RulesetsInvariant.t.sol +0 -125
  86. package/test/invariants/TerminalStoreInvariant.t.sol +0 -227
  87. package/test/invariants/TokensInvariant.t.sol +0 -195
  88. package/test/invariants/handlers/ComprehensiveHandler.sol +0 -303
  89. package/test/invariants/handlers/EconomicHandler.sol +0 -377
  90. package/test/invariants/handlers/Phase3Handler.sol +0 -443
  91. package/test/invariants/handlers/RulesetsHandler.sol +0 -115
  92. package/test/invariants/handlers/TerminalStoreHandler.sol +0 -151
  93. package/test/invariants/handlers/TokensHandler.sol +0 -126
  94. package/test/regression/HoldFeesCashOutReserved.t.sol +0 -415
  95. package/test/regression/WeightCacheBoundary.t.sol +0 -291
  96. package/test/trees/JBController/burnTokensOf.tree +0 -9
  97. package/test/trees/JBController/claimTokensFor.tree +0 -5
  98. package/test/trees/JBController/deployERC20For.tree +0 -5
  99. package/test/trees/JBController/getRulesetOf.tree +0 -5
  100. package/test/trees/JBController/launchProjectFor.tree +0 -12
  101. package/test/trees/JBController/launchRulesetsFor.tree +0 -8
  102. package/test/trees/JBController/migrateController.tree +0 -12
  103. package/test/trees/JBController/mintTokensOf.tree +0 -12
  104. package/test/trees/JBController/payReservedTokenToTerminal.tree +0 -8
  105. package/test/trees/JBController/receiveMigrationFrom.tree +0 -4
  106. package/test/trees/JBController/sendReservedTokensToSplitsOf.tree +0 -12
  107. package/test/trees/JBController/setMetadataOf.tree +0 -5
  108. package/test/trees/JBController/setSplitGroupsOf.tree +0 -5
  109. package/test/trees/JBController/setTokenFor.tree +0 -5
  110. package/test/trees/JBController/transferCreditsFrom.tree +0 -8
  111. package/test/trees/JBDirectory/primaryTerminalOf.tree +0 -8
  112. package/test/trees/JBDirectory/setControllerOf.tree +0 -11
  113. package/test/trees/JBDirectory/setPrimaryTerminalOf.tree +0 -15
  114. package/test/trees/JBDirectory/setTerminalsOf.tree +0 -11
  115. package/test/trees/JBERC20/initialize.tree +0 -7
  116. package/test/trees/JBERC20/name.tree +0 -5
  117. package/test/trees/JBERC20/nonces.tree +0 -5
  118. package/test/trees/JBERC20/symbol.tree +0 -5
  119. package/test/trees/JBFeelessAddresses/setFeelessAddress.tree +0 -5
  120. package/test/trees/JBFeelessAddresses/supportsInterface.tree +0 -5
  121. package/test/trees/JBFundAccessLimits/payoutLimitOf.tree +0 -5
  122. package/test/trees/JBFundAccessLimits/payoutLimitsOf.tree +0 -8
  123. package/test/trees/JBFundAccessLimits/setFundAccessLimitsFor.tree +0 -18
  124. package/test/trees/JBFundAccessLimits/surplusAllowanceOf.tree +0 -5
  125. package/test/trees/JBFundAccessLimits/surplusAllowancesOf.tree +0 -8
  126. package/test/trees/JBMetadataResolver/getDataFor.tree +0 -8
  127. package/test/trees/JBMultiTerminal/accountingContextsOf.tree +0 -5
  128. package/test/trees/JBMultiTerminal/addAccountingContextsFor.tree +0 -10
  129. package/test/trees/JBMultiTerminal/addToBalanceOf.tree +0 -23
  130. package/test/trees/JBMultiTerminal/cashOutTokensOf.tree +0 -23
  131. package/test/trees/JBMultiTerminal/executePayout.tree +0 -32
  132. package/test/trees/JBMultiTerminal/executeProcessFee.tree +0 -14
  133. package/test/trees/JBMultiTerminal/migrateBalanceOf.tree +0 -12
  134. package/test/trees/JBMultiTerminal/pay.tree +0 -23
  135. package/test/trees/JBMultiTerminal/processHeldFeesOf.tree +0 -8
  136. package/test/trees/JBMultiTerminal/sendPayoutsOf.tree +0 -34
  137. package/test/trees/JBMultiTerminal/useAllowanceOf.tree +0 -16
  138. package/test/trees/JBPermissions/hasPermission.tree +0 -8
  139. package/test/trees/JBPermissions/hasPermissions.tree +0 -8
  140. package/test/trees/JBPermissions/setPermissionsFor.tree +0 -5
  141. package/test/trees/JBPrices/addPriceFeedFor.tree +0 -14
  142. package/test/trees/JBPrices/pricePerUnitOf.tree +0 -11
  143. package/test/trees/JBProjects/createFor.tree +0 -11
  144. package/test/trees/JBProjects/setTokenUriResolver.tree +0 -5
  145. package/test/trees/JBProjects/supportsInterface.tree +0 -9
  146. package/test/trees/JBProjects/tokenURI.tree +0 -5
  147. package/test/trees/JBRulesets/currentApprovalStatusForLatestRulesetOf.tree +0 -8
  148. package/test/trees/JBRulesets/currentOf.tree +0 -12
  149. package/test/trees/JBRulesets/getRulesetOf.tree +0 -5
  150. package/test/trees/JBRulesets/latestQueuedRulesetOf.tree +0 -10
  151. package/test/trees/JBRulesets/rulesetsOf.tree +0 -11
  152. package/test/trees/JBRulesets/upcomingRulesetOf.tree +0 -20
  153. package/test/trees/JBRulesets/updateRulesetWeightCache.tree +0 -5
  154. package/test/trees/JBSplits/setSplitGroupsOf.tree +0 -17
  155. package/test/trees/JBSplits/splitsOf.tree +0 -5
  156. package/test/trees/JBTerminalStore/currentReclaimableSurplusOf.tree +0 -16
  157. package/test/trees/JBTerminalStore/currentSurplusOf.tree +0 -25
  158. package/test/trees/JBTerminalStore/currentTotalSurplusOf.tree +0 -5
  159. package/test/trees/JBTerminalStore/recordCashOutsFor.tree +0 -16
  160. package/test/trees/JBTerminalStore/recordPaymentFrom.tree +0 -14
  161. package/test/trees/JBTerminalStore/recordPayoutFor.tree +0 -10
  162. package/test/trees/JBTerminalStore/recordTerminalMigration.tree +0 -5
  163. package/test/trees/JBTerminalStore/recordUsedAllowanceOf.tree +0 -10
  164. package/test/trees/JBTokens/burnFrom.tree +0 -10
  165. package/test/trees/JBTokens/claimTokensFor.tree +0 -10
  166. package/test/trees/JBTokens/deployERC20For.tree +0 -12
  167. package/test/trees/JBTokens/mintFor.tree +0 -10
  168. package/test/trees/JBTokens/setTokenFor.tree +0 -11
  169. package/test/trees/JBTokens/totalBalanceOf.tree +0 -5
  170. package/test/trees/JBTokens/totalSupplyOf.tree +0 -5
  171. package/test/trees/JBTokens/transferCreditsFrom.tree +0 -8
  172. package/test/trees/mintTokensOf.tree +0 -12
  173. package/test/units/static/JBChainlinkV3PriceFeed/TestPriceFeed.sol +0 -223
  174. package/test/units/static/JBController/JBControllerSetup.sol +0 -50
  175. package/test/units/static/JBController/TestBurnTokensOf.sol +0 -114
  176. package/test/units/static/JBController/TestClaimTokensFor.sol +0 -63
  177. package/test/units/static/JBController/TestDeployErc20For.sol +0 -86
  178. package/test/units/static/JBController/TestLaunchProjectFor.sol +0 -302
  179. package/test/units/static/JBController/TestLaunchRulesetsFor.sol +0 -342
  180. package/test/units/static/JBController/TestMigrateController.sol +0 -157
  181. package/test/units/static/JBController/TestMintTokensOfUnits.sol +0 -111
  182. package/test/units/static/JBController/TestOmnichainRulesetOperator.sol +0 -324
  183. package/test/units/static/JBController/TestPayReservedTokenToTerminal.sol +0 -74
  184. package/test/units/static/JBController/TestPreviewMintOf.sol +0 -117
  185. package/test/units/static/JBController/TestReceiveMigrationFrom.sol +0 -99
  186. package/test/units/static/JBController/TestRulesetViews.sol +0 -225
  187. package/test/units/static/JBController/TestSendReservedTokensToSplitsOf.sol +0 -615
  188. package/test/units/static/JBController/TestSetSplitGroupsOf.sol +0 -68
  189. package/test/units/static/JBController/TestSetTokenFor.sol +0 -239
  190. package/test/units/static/JBController/TestSetUriOf.sol +0 -57
  191. package/test/units/static/JBController/TestTransferCreditsFrom.sol +0 -169
  192. package/test/units/static/JBDeadline/TestDeadlineFuzz.sol +0 -211
  193. package/test/units/static/JBDirectory/JBDirectorySetup.sol +0 -26
  194. package/test/units/static/JBDirectory/TestPrimaryTerminalOf.sol +0 -126
  195. package/test/units/static/JBDirectory/TestSetControllerOf.sol +0 -183
  196. package/test/units/static/JBDirectory/TestSetControllerOfMigrationOrder.sol +0 -104
  197. package/test/units/static/JBDirectory/TestSetPrimaryTerminalOf.sol +0 -179
  198. package/test/units/static/JBDirectory/TestSetTerminalsOf.sol +0 -137
  199. package/test/units/static/JBERC20/JBERC20Setup.sol +0 -34
  200. package/test/units/static/JBERC20/SigUtils.sol +0 -36
  201. package/test/units/static/JBERC20/TestInitialize.sol +0 -60
  202. package/test/units/static/JBERC20/TestName.sol +0 -30
  203. package/test/units/static/JBERC20/TestNonces.sol +0 -62
  204. package/test/units/static/JBERC20/TestSymbol.sol +0 -31
  205. package/test/units/static/JBFeelessAdresses/JBFeelessSetup.sol +0 -22
  206. package/test/units/static/JBFeelessAdresses/TestInterfaces.sol +0 -30
  207. package/test/units/static/JBFeelessAdresses/TestSetFeelessAddress.sol +0 -35
  208. package/test/units/static/JBFees/TestFeesFuzz.sol +0 -79
  209. package/test/units/static/JBFixedPointNumber/TestAdjustDecimals.sol +0 -16
  210. package/test/units/static/JBFixedPointNumber/TestAdjustDecimalsFuzz.sol +0 -71
  211. package/test/units/static/JBFundAccessLimits/JBFundAccessSetup.sol +0 -24
  212. package/test/units/static/JBFundAccessLimits/TestFundAccessLimitsEdge.sol +0 -163
  213. package/test/units/static/JBFundAccessLimits/TestPayoutLimitOf.sol +0 -59
  214. package/test/units/static/JBFundAccessLimits/TestPayoutLimitsOf.sol +0 -101
  215. package/test/units/static/JBFundAccessLimits/TestSetFundAccessLimitsFor.sol +0 -189
  216. package/test/units/static/JBFundAccessLimits/TestSurplusAllowanceOf.sol +0 -64
  217. package/test/units/static/JBFundAccessLimits/TestSurplusAllowancesOf.sol +0 -102
  218. package/test/units/static/JBMetadataResolver/TestGetDataFor.sol +0 -90
  219. package/test/units/static/JBMetadataResolver/TestMetadataResolverEdgeCases.sol +0 -247
  220. package/test/units/static/JBMetadataResolver/TestMetadataResolverFuzz.sol +0 -229
  221. package/test/units/static/JBMultiTerminal/JBMultiTerminalSetup.sol +0 -50
  222. package/test/units/static/JBMultiTerminal/TestAccountingContextsOf.sol +0 -72
  223. package/test/units/static/JBMultiTerminal/TestAddAccountingContextsFor.sol +0 -289
  224. package/test/units/static/JBMultiTerminal/TestAddToBalanceOf.sol +0 -474
  225. package/test/units/static/JBMultiTerminal/TestCashOutTokensOf.sol +0 -624
  226. package/test/units/static/JBMultiTerminal/TestExecutePayout.sol +0 -578
  227. package/test/units/static/JBMultiTerminal/TestExecuteProcessFee.sol +0 -202
  228. package/test/units/static/JBMultiTerminal/TestMigrateBalanceOf.sol +0 -222
  229. package/test/units/static/JBMultiTerminal/TestPay.sol +0 -604
  230. package/test/units/static/JBMultiTerminal/TestPreviewCashOutFrom.sol +0 -117
  231. package/test/units/static/JBMultiTerminal/TestPreviewPayFor.sol +0 -114
  232. package/test/units/static/JBMultiTerminal/TestProcessHeldFeesOf.sol +0 -228
  233. package/test/units/static/JBMultiTerminal/TestSelfPayRevert.sol +0 -55
  234. package/test/units/static/JBMultiTerminal/TestSendPayoutsOf.sol +0 -257
  235. package/test/units/static/JBMultiTerminal/TestUseAllowanceOf.sol +0 -611
  236. package/test/units/static/JBPermissions/JBPermissionsSetup.sol +0 -20
  237. package/test/units/static/JBPermissions/TestHasPermission.sol +0 -50
  238. package/test/units/static/JBPermissions/TestHasPermissions.sol +0 -93
  239. package/test/units/static/JBPermissions/TestSetPermissionsFor.sol +0 -64
  240. package/test/units/static/JBPrices/JBPricesSetup.sol +0 -32
  241. package/test/units/static/JBPrices/TestAddPriceFeedFor.sol +0 -107
  242. package/test/units/static/JBPrices/TestPricePerUnitOf.sol +0 -132
  243. package/test/units/static/JBPrices/TestPrices.sol +0 -265
  244. package/test/units/static/JBProjects/JBProjectsSetup.sol +0 -22
  245. package/test/units/static/JBProjects/TestCreateFor.sol +0 -71
  246. package/test/units/static/JBProjects/TestInitialProject.sol +0 -21
  247. package/test/units/static/JBProjects/TestInterfaces.sol +0 -26
  248. package/test/units/static/JBProjects/TestSetResolver.sol +0 -37
  249. package/test/units/static/JBProjects/TestTokenUri.sol +0 -40
  250. package/test/units/static/JBRulesetMetadataResolver/TestSetCashOutTaxRateTo.sol +0 -108
  251. package/test/units/static/JBRulesets/JBRulesetsSetup.sol +0 -24
  252. package/test/units/static/JBRulesets/TestCurrentApprovalStatusForLatestRulesetOf.sol +0 -265
  253. package/test/units/static/JBRulesets/TestCurrentOf.sol +0 -242
  254. package/test/units/static/JBRulesets/TestGetRulesetOf.sol +0 -100
  255. package/test/units/static/JBRulesets/TestLatestQueuedRulesetOf.sol +0 -260
  256. package/test/units/static/JBRulesets/TestRulesets.sol +0 -632
  257. package/test/units/static/JBRulesets/TestRulesetsOf.sol +0 -37
  258. package/test/units/static/JBRulesets/TestUpcomingRulesetOf.sol +0 -522
  259. package/test/units/static/JBRulesets/TestUpdateRulesetWeightCache.sol +0 -96
  260. package/test/units/static/JBSplits/JBSplitsSetup.sol +0 -26
  261. package/test/units/static/JBSplits/TestSelfManagedSplitGroups.sol +0 -552
  262. package/test/units/static/JBSplits/TestSetSplitGroupsOf.sol +0 -377
  263. package/test/units/static/JBSplits/TestSplitsLockedEdge.sol +0 -267
  264. package/test/units/static/JBSplits/TestSplitsOf.sol +0 -24
  265. package/test/units/static/JBSplits/TestSplitsPacking.sol +0 -36
  266. package/test/units/static/JBSurplus/TestSurplusFuzz.sol +0 -160
  267. package/test/units/static/JBTerminalStore/JBTerminalStoreSetup.sol +0 -45
  268. package/test/units/static/JBTerminalStore/TestCurrentReclaimableSurplusOf.sol +0 -536
  269. package/test/units/static/JBTerminalStore/TestCurrentSurplusOf.sol +0 -463
  270. package/test/units/static/JBTerminalStore/TestCurrentTotalSurplusOf.sol +0 -135
  271. package/test/units/static/JBTerminalStore/TestPreviewCashOutFrom.sol +0 -476
  272. package/test/units/static/JBTerminalStore/TestPreviewPayFrom.sol +0 -494
  273. package/test/units/static/JBTerminalStore/TestRecordCashOutsFor.sol +0 -652
  274. package/test/units/static/JBTerminalStore/TestRecordPaymentFrom.sol +0 -744
  275. package/test/units/static/JBTerminalStore/TestRecordPayoutFor.sol +0 -289
  276. package/test/units/static/JBTerminalStore/TestRecordTerminalMigration.sol +0 -138
  277. package/test/units/static/JBTerminalStore/TestRecordUsedAllowanceOf.sol +0 -415
  278. package/test/units/static/JBTerminalStore/TestUint224Overflow.sol +0 -219
  279. package/test/units/static/JBTokens/JBTokensSetup.sol +0 -32
  280. package/test/units/static/JBTokens/TestBurnFrom.sol +0 -107
  281. package/test/units/static/JBTokens/TestClaimTokensFor.sol +0 -110
  282. package/test/units/static/JBTokens/TestDeployERC20ForUnits.sol +0 -92
  283. package/test/units/static/JBTokens/TestMintFor.sol +0 -100
  284. package/test/units/static/JBTokens/TestSetTokenFor.sol +0 -98
  285. package/test/units/static/JBTokens/TestTotalBalanceOf.sol +0 -65
  286. package/test/units/static/JBTokens/TestTotalSupplyOf.sol +0 -56
  287. package/test/units/static/JBTokens/TestTransferCreditsFrom.sol +0 -56
@@ -1,412 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.6;
3
-
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 {JBRulesetMetadataResolver} from "../../src/libraries/JBRulesetMetadataResolver.sol";
9
- import {JBCurrencyAmount} from "../../src/structs/JBCurrencyAmount.sol";
10
- import {JBFundAccessLimitGroup} from "../../src/structs/JBFundAccessLimitGroup.sol";
11
- import {JBRuleset} from "../../src/structs/JBRuleset.sol";
12
- import {JBRulesetConfig} from "../../src/structs/JBRulesetConfig.sol";
13
- import {JBRulesetMetadata} from "../../src/structs/JBRulesetMetadata.sol";
14
- import {JBSplit} from "../../src/structs/JBSplit.sol";
15
- import {JBSplitGroup} from "../../src/structs/JBSplitGroup.sol";
16
- import {JBTerminalConfig} from "../../src/structs/JBTerminalConfig.sol";
17
- import {Phase3Handler} from "./handlers/Phase3Handler.sol";
18
- import {JBAccountingContext} from "../../src/structs/JBAccountingContext.sol";
19
- import {JBConstants} from "../../src/libraries/JBConstants.sol";
20
-
21
- /// @title Phase3DeepInvariant
22
- /// @notice Multi-project deep invariant tests with strict equality checks.
23
- /// 4 projects (fee collector, standard, split-recipient, feeless beneficiary).
24
- /// 14 handler operations with ghost variable tracking for exact fee flow verification.
25
- contract Phase3DeepInvariant_Local is StdInvariant, TestBaseWorkflow {
26
- using JBRulesetMetadataResolver for JBRuleset;
27
-
28
- Phase3Handler public handler;
29
-
30
- uint256 public project2;
31
- uint256 public project3;
32
- uint256 public project4;
33
-
34
- function setUp() public override {
35
- super.setUp();
36
-
37
- address owner = multisig();
38
-
39
- // =====================================================================
40
- // Fee collector project (#1)
41
- // =====================================================================
42
- {
43
- JBRulesetConfig[] memory feeRuleset = new JBRulesetConfig[](1);
44
- feeRuleset[0].mustStartAtOrAfter = 0;
45
- feeRuleset[0].duration = 0;
46
- feeRuleset[0].weight = uint112(1000e18);
47
- feeRuleset[0].weightCutPercent = 0;
48
- feeRuleset[0].approvalHook = IJBRulesetApprovalHook(address(0));
49
- feeRuleset[0].metadata = _defaultMetadata();
50
- feeRuleset[0].splitGroups = new JBSplitGroup[](0);
51
- feeRuleset[0].fundAccessLimitGroups = new JBFundAccessLimitGroup[](0);
52
-
53
- JBTerminalConfig[] memory feeTermCfg = new JBTerminalConfig[](1);
54
- feeTermCfg[0] =
55
- JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: _nativeTokenContextArray()});
56
-
57
- uint256 feeProjectId = jbController()
58
- .launchProjectFor({
59
- owner: owner,
60
- projectUri: "FeeProject",
61
- rulesetConfigurations: feeRuleset,
62
- terminalConfigurations: feeTermCfg,
63
- memo: ""
64
- });
65
- require(feeProjectId == 1, "Fee project must be #1");
66
- }
67
-
68
- // =====================================================================
69
- // Project #2: 20% reserved, 30% cashOutTax, holdFees=true,
70
- // 5 ETH payout limit, 3 ETH surplus allowance,
71
- // split 50% to Project #3
72
- // =====================================================================
73
- {
74
- JBRulesetConfig[] memory ruleset2 = new JBRulesetConfig[](1);
75
- ruleset2[0].mustStartAtOrAfter = 0;
76
- ruleset2[0].duration = 0;
77
- ruleset2[0].weight = uint112(1000e18);
78
- ruleset2[0].weightCutPercent = 0;
79
- ruleset2[0].approvalHook = IJBRulesetApprovalHook(address(0));
80
-
81
- JBRulesetMetadata memory meta2 = _defaultMetadata();
82
- meta2.reservedPercent = 2000; // 20%
83
- meta2.cashOutTaxRate = 3000; // 30%
84
- meta2.holdFees = true;
85
- ruleset2[0].metadata = meta2;
86
-
87
- // Split: 50% to project 3 (project 3 doesn't exist yet, we'll set ID=3)
88
- JBSplit[] memory splits2 = new JBSplit[](1);
89
- splits2[0] = JBSplit({
90
- preferAddToBalance: true,
91
- percent: uint32(JBConstants.SPLITS_TOTAL_PERCENT / 2), // 50%
92
- projectId: 3, // Will be project 3
93
- beneficiary: payable(address(0)),
94
- lockedUntil: 0,
95
- hook: IJBSplitHook(address(0))
96
- });
97
-
98
- JBSplitGroup[] memory splitGroups2 = new JBSplitGroup[](1);
99
- splitGroups2[0] = JBSplitGroup({groupId: uint32(uint160(JBConstants.NATIVE_TOKEN)), splits: splits2});
100
- ruleset2[0].splitGroups = splitGroups2;
101
-
102
- // Fund access limits: 5 ETH payout, 3 ETH surplus allowance
103
- JBFundAccessLimitGroup[] memory limits2 = new JBFundAccessLimitGroup[](1);
104
- JBCurrencyAmount[] memory payoutLimits2 = new JBCurrencyAmount[](1);
105
- payoutLimits2[0] =
106
- JBCurrencyAmount({amount: uint224(5 ether), currency: uint32(uint160(JBConstants.NATIVE_TOKEN))});
107
- JBCurrencyAmount[] memory surplusAllowances2 = new JBCurrencyAmount[](1);
108
- surplusAllowances2[0] =
109
- JBCurrencyAmount({amount: uint224(3 ether), currency: uint32(uint160(JBConstants.NATIVE_TOKEN))});
110
- limits2[0] = JBFundAccessLimitGroup({
111
- terminal: address(jbMultiTerminal()),
112
- token: JBConstants.NATIVE_TOKEN,
113
- payoutLimits: payoutLimits2,
114
- surplusAllowances: surplusAllowances2
115
- });
116
- ruleset2[0].fundAccessLimitGroups = limits2;
117
-
118
- JBTerminalConfig[] memory termCfg = new JBTerminalConfig[](1);
119
- termCfg[0] =
120
- JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: _nativeTokenContextArray()});
121
-
122
- project2 = jbController()
123
- .launchProjectFor({
124
- owner: owner,
125
- projectUri: "Project2",
126
- rulesetConfigurations: ruleset2,
127
- terminalConfigurations: termCfg,
128
- memo: ""
129
- });
130
- }
131
-
132
- // =====================================================================
133
- // Project #3: Split recipient — 10% cashOutTax, holdFees=false
134
- // =====================================================================
135
- {
136
- JBRulesetConfig[] memory ruleset3 = new JBRulesetConfig[](1);
137
- ruleset3[0].mustStartAtOrAfter = 0;
138
- ruleset3[0].duration = 0;
139
- ruleset3[0].weight = uint112(1000e18);
140
- ruleset3[0].weightCutPercent = 0;
141
- ruleset3[0].approvalHook = IJBRulesetApprovalHook(address(0));
142
-
143
- JBRulesetMetadata memory meta3 = _defaultMetadata();
144
- meta3.cashOutTaxRate = 1000; // 10%
145
- meta3.holdFees = false;
146
- ruleset3[0].metadata = meta3;
147
- ruleset3[0].splitGroups = new JBSplitGroup[](0);
148
- ruleset3[0].fundAccessLimitGroups = new JBFundAccessLimitGroup[](0);
149
-
150
- JBTerminalConfig[] memory termCfg3 = new JBTerminalConfig[](1);
151
- termCfg3[0] =
152
- JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: _nativeTokenContextArray()});
153
-
154
- project3 = jbController()
155
- .launchProjectFor({
156
- owner: owner,
157
- projectUri: "Project3",
158
- rulesetConfigurations: ruleset3,
159
- terminalConfigurations: termCfg3,
160
- memo: ""
161
- });
162
- require(project3 == 3, "Project 3 must be #3");
163
- }
164
-
165
- // =====================================================================
166
- // Project #4: Feeless beneficiary
167
- // =====================================================================
168
- {
169
- JBRulesetConfig[] memory ruleset4 = new JBRulesetConfig[](1);
170
- ruleset4[0].mustStartAtOrAfter = 0;
171
- ruleset4[0].duration = 0;
172
- ruleset4[0].weight = uint112(1000e18);
173
- ruleset4[0].weightCutPercent = 0;
174
- ruleset4[0].approvalHook = IJBRulesetApprovalHook(address(0));
175
- ruleset4[0].metadata = _defaultMetadata();
176
- ruleset4[0].splitGroups = new JBSplitGroup[](0);
177
- ruleset4[0].fundAccessLimitGroups = new JBFundAccessLimitGroup[](0);
178
-
179
- JBTerminalConfig[] memory termCfg4 = new JBTerminalConfig[](1);
180
- termCfg4[0] =
181
- JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: _nativeTokenContextArray()});
182
-
183
- project4 = jbController()
184
- .launchProjectFor({
185
- owner: owner,
186
- projectUri: "Project4",
187
- rulesetConfigurations: ruleset4,
188
- terminalConfigurations: termCfg4,
189
- memo: ""
190
- });
191
-
192
- // Register project 4's owner as feeless
193
- vm.prank(multisig());
194
- jbFeelessAddresses().setFeelessAddress(owner, true);
195
- }
196
-
197
- // =====================================================================
198
- // Deploy handler
199
- // =====================================================================
200
- handler = new Phase3Handler(
201
- jbMultiTerminal(), jbTerminalStore(), jbController(), jbTokens(), project2, project3, project4, owner
202
- );
203
-
204
- // Deploy ERC20 token for project 2 so claimCredits2 works
205
- vm.prank(owner);
206
- jbController().deployERC20For({projectId: project2, name: "Token2", symbol: "TK2", salt: bytes32(0)});
207
-
208
- // Register handler selectors
209
- bytes4[] memory selectors = new bytes4[](16);
210
- selectors[0] = Phase3Handler.payProject2.selector;
211
- selectors[1] = Phase3Handler.payProject3.selector;
212
- selectors[2] = Phase3Handler.cashOutProject2.selector;
213
- selectors[3] = Phase3Handler.cashOutProject3.selector;
214
- selectors[4] = Phase3Handler.sendPayoutsProject2.selector;
215
- selectors[5] = Phase3Handler.useAllowanceProject2.selector;
216
- selectors[6] = Phase3Handler.sendReservedTokens2.selector;
217
- selectors[7] = Phase3Handler.processHeldFees2.selector;
218
- selectors[8] = Phase3Handler.addToBalanceReturnFees2.selector;
219
- selectors[9] = Phase3Handler.addToBalanceNoReturn2.selector;
220
- selectors[10] = Phase3Handler.burnTokens2.selector;
221
- selectors[11] = Phase3Handler.burnTokens3.selector;
222
- selectors[12] = Phase3Handler.claimCredits2.selector;
223
- selectors[13] = Phase3Handler.advanceTime.selector;
224
- // Double-weight pay operations (most common)
225
- selectors[14] = Phase3Handler.payProject2.selector;
226
- selectors[15] = Phase3Handler.payProject3.selector;
227
-
228
- targetSelector(FuzzSelector({addr: address(handler), selectors: selectors}));
229
- targetContract(address(handler));
230
- }
231
-
232
- // =========================================================================
233
- // Helpers
234
- // =========================================================================
235
-
236
- function _defaultMetadata() internal pure returns (JBRulesetMetadata memory) {
237
- return JBRulesetMetadata({
238
- reservedPercent: 0,
239
- cashOutTaxRate: 0,
240
- baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
241
- pausePay: false,
242
- pauseCreditTransfers: false,
243
- allowOwnerMinting: false,
244
- allowSetCustomToken: true,
245
- allowTerminalMigration: false,
246
- allowSetTerminals: false,
247
- ownerMustSendPayouts: false,
248
- allowSetController: false,
249
- allowAddAccountingContext: true,
250
- allowAddPriceFeed: false,
251
- holdFees: false,
252
- useTotalSurplusForCashOuts: false,
253
- useDataHookForPay: false,
254
- useDataHookForCashOut: false,
255
- dataHook: address(0),
256
- metadata: 0
257
- });
258
- }
259
-
260
- function _nativeTokenContextArray() internal pure returns (JBAccountingContext[] memory) {
261
- JBAccountingContext[] memory ctx = new JBAccountingContext[](1);
262
- ctx[0] = JBAccountingContext({
263
- token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
264
- });
265
- return ctx;
266
- }
267
-
268
- // =========================================================================
269
- // INV-P3-1: Terminal balance == sum(store.balanceOf) + held fees accounting
270
- // =========================================================================
271
- /// @notice The terminal's actual ETH balance must be >= the sum of all recorded balances.
272
- /// This catches any accounting leak where ETH escapes tracking.
273
- function invariant_P3_1_terminalBalanceCoversRecorded() public view {
274
- uint256 balanceFee = jbTerminalStore().balanceOf(address(jbMultiTerminal()), 1, JBConstants.NATIVE_TOKEN);
275
- uint256 balance2 = jbTerminalStore().balanceOf(address(jbMultiTerminal()), project2, JBConstants.NATIVE_TOKEN);
276
- uint256 balance3 = jbTerminalStore().balanceOf(address(jbMultiTerminal()), project3, JBConstants.NATIVE_TOKEN);
277
- uint256 balance4 = jbTerminalStore().balanceOf(address(jbMultiTerminal()), project4, JBConstants.NATIVE_TOKEN);
278
-
279
- uint256 totalRecorded = balanceFee + balance2 + balance3 + balance4;
280
- uint256 actualBalance = address(jbMultiTerminal()).balance;
281
-
282
- // Terminal balance must be >= recorded (held fees account for the difference)
283
- assertGe(
284
- actualBalance,
285
- totalRecorded,
286
- "INV-P3-1: Terminal actual balance must >= sum of all project recorded balances"
287
- );
288
- }
289
-
290
- // =========================================================================
291
- // INV-P3-2: Fee consistency — ghost fees deducted vs fees sent + held
292
- // =========================================================================
293
- /// @notice Total fees deducted from project 2 should correlate with fees sent to
294
- /// project 1 plus unprocessed held fees. This catches fee rounding mismatches.
295
- function invariant_P3_2_feeFlowConsistency() public view {
296
- // Fee project (#1) balance represents all fees actually received
297
- uint256 feeProjectBalance = jbTerminalStore().balanceOf(address(jbMultiTerminal()), 1, JBConstants.NATIVE_TOKEN);
298
-
299
- // The fee project balance should be non-negative (always true for uint)
300
- // and should be bounded by total ghost inflows
301
- assertGe(
302
- handler.ghost_globalInflows(),
303
- feeProjectBalance,
304
- "INV-P3-2: Fee project balance should not exceed total inflows"
305
- );
306
- }
307
-
308
- // =========================================================================
309
- // INV-P3-3: No actor extracts more than contributed (per project, pre-external)
310
- // =========================================================================
311
- /// @notice With cashOutTaxRate > 0, no single actor should extract more than they contributed
312
- /// from project 2, unless addToBalance was used (which inflates surplus).
313
- function invariant_P3_3_noActorExtractionExceedsContribution() public view {
314
- if (handler.ghost_totalAddedToBalance(project2) > 0) return; // Skip if external surplus added
315
-
316
- for (uint256 i = 0; i < handler.NUM_ACTORS(); i++) {
317
- address actor = handler.getActor(i);
318
- uint256 contributed = handler.ghost_actorContributed(actor, project2);
319
- uint256 extracted = handler.ghost_actorExtracted(actor, project2);
320
-
321
- assertGe(
322
- contributed, extracted, "INV-P3-3: Actor should not extract more than contributed with cash out tax"
323
- );
324
- }
325
- }
326
-
327
- // =========================================================================
328
- // INV-P3-4: Token supply * bonding floor <= terminal balance
329
- // =========================================================================
330
- /// @notice Token supply should never exceed what the terminal can back.
331
- /// This catches token overissuance bugs.
332
- function invariant_P3_4_tokenSupplyBoundedByBalance() public view {
333
- uint256 supply2 = jbController().totalTokenSupplyWithReservedTokensOf(project2);
334
- uint256 balance2 = jbTerminalStore().balanceOf(address(jbMultiTerminal()), project2, JBConstants.NATIVE_TOKEN);
335
-
336
- // The token supply should relate to the balance. With weight=1000e18 tokens per ETH,
337
- // each token represents 0.001 ETH. A non-zero supply with zero balance is a problem.
338
- if (supply2 > 0) {
339
- // At minimum, some balance should exist to back the tokens
340
- // (unless all tokens were from reserved minting with no funds)
341
- // This is a soft check — tokens from pay() always have backing
342
- uint256 totalPaid = handler.ghost_totalPaidIn(project2) + handler.ghost_totalAddedToBalance(project2);
343
- uint256 totalOut = handler.ghost_totalCashedOut(project2) + handler.ghost_totalPaidOut(project2)
344
- + handler.ghost_totalAllowanceUsed(project2);
345
-
346
- if (totalPaid > totalOut) {
347
- assertGt(balance2, 0, "INV-P3-4: Tokens exist but terminal balance is 0");
348
- }
349
- }
350
- }
351
-
352
- // =========================================================================
353
- // INV-P3-5: Global conservation — inflows == outflows + balances
354
- // =========================================================================
355
- /// @notice Total ETH entering the system must equal ETH leaving + ETH remaining.
356
- function invariant_P3_5_globalConservation() public view {
357
- uint256 totalInflows = handler.ghost_globalInflows();
358
-
359
- // Use actual terminal balance as ground truth.
360
- // Note: ghost_globalOutflows overcounts because sendPayoutsOf returns gross amounts
361
- // before fee deduction, but fees stay in the terminal. Using actual balance avoids this.
362
- uint256 actualBalance = address(jbMultiTerminal()).balance;
363
-
364
- // Terminal balance should not exceed total inflows
365
- assertGe(totalInflows, actualBalance, "INV-P3-5: Terminal balance should not exceed total inflows");
366
- }
367
-
368
- // =========================================================================
369
- // INV-P3-6: Held fee return safety
370
- // =========================================================================
371
- /// @notice After addToBalance(shouldReturn=true), returned fees must not exceed held fees.
372
- function invariant_P3_6_heldFeeReturnBounded() public view {
373
- uint256 returned = handler.ghost_totalReturnedFees(project2);
374
-
375
- // Returned fees should never exceed what was held
376
- // (heldTotal may be 0 if we never tracked, so only check when both nonzero)
377
- if (returned > 0) {
378
- // Returned fees came from actual held fees, which is bounded by payouts * fee%
379
- // This is a sanity check — the system should never return more than was held
380
- assertTrue(true, "INV-P3-6: Fee return check passed (nonzero return)");
381
- }
382
- }
383
-
384
- // =========================================================================
385
- // INV-P3-7: Payout + allowance usage bounded by balance
386
- // =========================================================================
387
- /// @notice Used payout limit + used surplus allowance should not drain more than the balance.
388
- function invariant_P3_7_limitUsageBoundedByBalance() public view {
389
- uint256 totalDrained = handler.ghost_totalPaidOut(project2) + handler.ghost_totalAllowanceUsed(project2);
390
- uint256 totalAvailable = handler.ghost_totalPaidIn(project2) + handler.ghost_totalAddedToBalance(project2);
391
-
392
- // Total drained should not exceed total available
393
- assertGe(
394
- totalAvailable,
395
- totalDrained,
396
- "INV-P3-7: Total drained (payouts + allowance) must not exceed total available"
397
- );
398
- }
399
-
400
- // =========================================================================
401
- // INV-P3-8: Reserved tokens — after sendReservedTokens, pending == 0
402
- // =========================================================================
403
- /// @notice After sendReservedTokensToSplitsOf, the pending reserved count should be 0.
404
- /// Also verifies that token supply increased by the correct amount.
405
- function invariant_P3_8_reservedTokenConsistency() public view {
406
- // Check that total supply with reserves >= total supply (reserves are pending)
407
- uint256 supplyWithReserves = jbController().totalTokenSupplyWithReservedTokensOf(project2);
408
- uint256 rawSupply = jbTokens().totalSupplyOf(project2);
409
-
410
- assertGe(supplyWithReserves, rawSupply, "INV-P3-8: Supply with reserves must >= raw supply");
411
- }
412
- }
@@ -1,125 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.6;
3
-
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 {JBConstants} from "../../src/libraries/JBConstants.sol";
8
- import {JBRulesetMetadataResolver} from "../../src/libraries/JBRulesetMetadataResolver.sol";
9
- import {JBAccountingContext} from "../../src/structs/JBAccountingContext.sol";
10
- import {JBFundAccessLimitGroup} from "../../src/structs/JBFundAccessLimitGroup.sol";
11
- import {JBRuleset} from "../../src/structs/JBRuleset.sol";
12
- import {JBRulesetConfig} from "../../src/structs/JBRulesetConfig.sol";
13
- import {JBRulesetMetadata} from "../../src/structs/JBRulesetMetadata.sol";
14
- import {JBSplitGroup} from "../../src/structs/JBSplitGroup.sol";
15
- import {JBTerminalConfig} from "../../src/structs/JBTerminalConfig.sol";
16
- import {RulesetsHandler} from "./handlers/RulesetsHandler.sol";
17
-
18
- /// @notice Invariant tests for JBRulesets cycling, weight decay, and monotonicity.
19
- contract RulesetsInvariant_Local is StdInvariant, TestBaseWorkflow {
20
- using JBRulesetMetadataResolver for JBRuleset;
21
-
22
- RulesetsHandler public handler;
23
-
24
- uint256 public projectId;
25
- address public projectOwner;
26
-
27
- function setUp() public override {
28
- super.setUp();
29
- projectOwner = multisig();
30
-
31
- // Launch a project with a cycled ruleset (30-day duration, 10% weight decay)
32
- JBRulesetConfig[] memory rulesetConfig = new JBRulesetConfig[](1);
33
- rulesetConfig[0].mustStartAtOrAfter = 0;
34
- rulesetConfig[0].duration = 30 days;
35
- rulesetConfig[0].weight = 1000e18;
36
- rulesetConfig[0].weightCutPercent = JBConstants.MAX_WEIGHT_CUT_PERCENT / 10; // 10% cut
37
- rulesetConfig[0].approvalHook = IJBRulesetApprovalHook(address(0));
38
- rulesetConfig[0].metadata = JBRulesetMetadata({
39
- reservedPercent: 0,
40
- cashOutTaxRate: 0,
41
- baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
42
- pausePay: false,
43
- pauseCreditTransfers: false,
44
- allowOwnerMinting: true,
45
- allowSetCustomToken: true,
46
- allowTerminalMigration: false,
47
- allowSetTerminals: false,
48
- ownerMustSendPayouts: false,
49
- allowSetController: false,
50
- allowAddAccountingContext: true,
51
- allowAddPriceFeed: false,
52
- holdFees: false,
53
- useTotalSurplusForCashOuts: false,
54
- useDataHookForPay: false,
55
- useDataHookForCashOut: false,
56
- dataHook: address(0),
57
- metadata: 0
58
- });
59
- rulesetConfig[0].splitGroups = new JBSplitGroup[](0);
60
- rulesetConfig[0].fundAccessLimitGroups = new JBFundAccessLimitGroup[](0);
61
-
62
- JBTerminalConfig[] memory terminalConfigurations = new JBTerminalConfig[](1);
63
- JBAccountingContext[] memory tokensToAccept = new JBAccountingContext[](1);
64
- tokensToAccept[0] = JBAccountingContext({
65
- token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
66
- });
67
- terminalConfigurations[0] =
68
- JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: tokensToAccept});
69
-
70
- projectId = jbController()
71
- .launchProjectFor({
72
- owner: projectOwner,
73
- projectUri: "rulesetsTest",
74
- rulesetConfigurations: rulesetConfig,
75
- terminalConfigurations: terminalConfigurations,
76
- memo: ""
77
- });
78
-
79
- // Deploy handler
80
- handler = new RulesetsHandler(jbRulesets(), jbController(), projectId, projectOwner);
81
-
82
- // Register handler
83
- bytes4[] memory selectors = new bytes4[](3);
84
- selectors[0] = RulesetsHandler.queueRuleset.selector;
85
- selectors[1] = RulesetsHandler.advanceTime.selector;
86
- selectors[2] = RulesetsHandler.updateWeightCache.selector;
87
-
88
- targetContract(address(handler));
89
- targetSelector(FuzzSelector({addr: address(handler), selectors: selectors}));
90
- }
91
-
92
- /// @notice INV-RS-1: After launch, currentOf(pid).id != 0 always.
93
- /// @dev A launched project must always have an active ruleset.
94
- function invariant_RS1_currentRulesetAlwaysExists() public view {
95
- JBRuleset memory current = jbRulesets().currentOf(projectId);
96
- assertGt(current.id, 0, "INV-RS-1: currentOf must return non-zero ruleset ID after launch");
97
- }
98
-
99
- /// @notice INV-RS-2: cycleNumber never decreases.
100
- /// @dev Even after time advances and new rulesets take effect, cycle numbers
101
- /// must monotonically increase.
102
- function invariant_RS2_cycleNumberNeverDecreases() public view {
103
- JBRuleset memory current = jbRulesets().currentOf(projectId);
104
-
105
- // The current cycle number should be >= 1 (first cycle).
106
- assertGe(uint256(current.cycleNumber), 1, "INV-RS-2: cycleNumber must be >= 1");
107
- }
108
-
109
- /// @notice INV-RS-3: Weight is always within valid bounds.
110
- /// @dev Weight must fit in uint112 and should never be 0 unless explicitly set.
111
- function invariant_RS3_weightWithinBounds() public view {
112
- JBRuleset memory current = jbRulesets().currentOf(projectId);
113
-
114
- // Weight should fit in uint112 (it's stored as uint112, so this is a sanity check).
115
- assertLe(uint256(current.weight), uint256(type(uint112).max), "INV-RS-3: weight must fit in uint112");
116
- }
117
-
118
- /// @notice INV-RS-4: Ruleset start timestamp is always <= block.timestamp.
119
- /// @dev The current ruleset's start must be in the past or present.
120
- function invariant_RS4_rulesetStartNotFuture() public view {
121
- JBRuleset memory current = jbRulesets().currentOf(projectId);
122
-
123
- assertLe(uint256(current.start), block.timestamp, "INV-RS-4: current ruleset start must be <= block.timestamp");
124
- }
125
- }