@bananapus/core-v6 0.0.36 → 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 (286) 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 +26 -5
  5. package/src/JBMultiTerminal.sol +85 -47
  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/CrossTerminalSurplusSpoof.t.sol +0 -140
  74. package/test/audit/CycledSurplusAllowanceReset.t.sol +0 -184
  75. package/test/audit/FeeFreeSurplusLifecycle.t.sol +0 -399
  76. package/test/audit/FeeFreeSurplusStale.t.sol +0 -248
  77. package/test/audit/USDTVoidReturnCompat.t.sol +0 -525
  78. package/test/fork/TestChainlinkPriceFeedFork.sol +0 -254
  79. package/test/fork/TestSequencerPriceFeedFork.sol +0 -168
  80. package/test/fork/TestTerminalPreviewParityFork.sol +0 -108
  81. package/test/formal/BondingCurveProperties.t.sol +0 -420
  82. package/test/formal/FeeProperties.t.sol +0 -252
  83. package/test/invariants/Phase3DeepInvariant.t.sol +0 -412
  84. package/test/invariants/RulesetsInvariant.t.sol +0 -125
  85. package/test/invariants/TerminalStoreInvariant.t.sol +0 -227
  86. package/test/invariants/TokensInvariant.t.sol +0 -195
  87. package/test/invariants/handlers/ComprehensiveHandler.sol +0 -303
  88. package/test/invariants/handlers/EconomicHandler.sol +0 -377
  89. package/test/invariants/handlers/Phase3Handler.sol +0 -443
  90. package/test/invariants/handlers/RulesetsHandler.sol +0 -115
  91. package/test/invariants/handlers/TerminalStoreHandler.sol +0 -151
  92. package/test/invariants/handlers/TokensHandler.sol +0 -126
  93. package/test/regression/HoldFeesCashOutReserved.t.sol +0 -415
  94. package/test/regression/WeightCacheBoundary.t.sol +0 -291
  95. package/test/trees/JBController/burnTokensOf.tree +0 -9
  96. package/test/trees/JBController/claimTokensFor.tree +0 -5
  97. package/test/trees/JBController/deployERC20For.tree +0 -5
  98. package/test/trees/JBController/getRulesetOf.tree +0 -5
  99. package/test/trees/JBController/launchProjectFor.tree +0 -12
  100. package/test/trees/JBController/launchRulesetsFor.tree +0 -8
  101. package/test/trees/JBController/migrateController.tree +0 -12
  102. package/test/trees/JBController/mintTokensOf.tree +0 -12
  103. package/test/trees/JBController/payReservedTokenToTerminal.tree +0 -8
  104. package/test/trees/JBController/receiveMigrationFrom.tree +0 -4
  105. package/test/trees/JBController/sendReservedTokensToSplitsOf.tree +0 -12
  106. package/test/trees/JBController/setMetadataOf.tree +0 -5
  107. package/test/trees/JBController/setSplitGroupsOf.tree +0 -5
  108. package/test/trees/JBController/setTokenFor.tree +0 -5
  109. package/test/trees/JBController/transferCreditsFrom.tree +0 -8
  110. package/test/trees/JBDirectory/primaryTerminalOf.tree +0 -8
  111. package/test/trees/JBDirectory/setControllerOf.tree +0 -11
  112. package/test/trees/JBDirectory/setPrimaryTerminalOf.tree +0 -15
  113. package/test/trees/JBDirectory/setTerminalsOf.tree +0 -11
  114. package/test/trees/JBERC20/initialize.tree +0 -7
  115. package/test/trees/JBERC20/name.tree +0 -5
  116. package/test/trees/JBERC20/nonces.tree +0 -5
  117. package/test/trees/JBERC20/symbol.tree +0 -5
  118. package/test/trees/JBFeelessAddresses/setFeelessAddress.tree +0 -5
  119. package/test/trees/JBFeelessAddresses/supportsInterface.tree +0 -5
  120. package/test/trees/JBFundAccessLimits/payoutLimitOf.tree +0 -5
  121. package/test/trees/JBFundAccessLimits/payoutLimitsOf.tree +0 -8
  122. package/test/trees/JBFundAccessLimits/setFundAccessLimitsFor.tree +0 -18
  123. package/test/trees/JBFundAccessLimits/surplusAllowanceOf.tree +0 -5
  124. package/test/trees/JBFundAccessLimits/surplusAllowancesOf.tree +0 -8
  125. package/test/trees/JBMetadataResolver/getDataFor.tree +0 -8
  126. package/test/trees/JBMultiTerminal/accountingContextsOf.tree +0 -5
  127. package/test/trees/JBMultiTerminal/addAccountingContextsFor.tree +0 -10
  128. package/test/trees/JBMultiTerminal/addToBalanceOf.tree +0 -23
  129. package/test/trees/JBMultiTerminal/cashOutTokensOf.tree +0 -23
  130. package/test/trees/JBMultiTerminal/executePayout.tree +0 -32
  131. package/test/trees/JBMultiTerminal/executeProcessFee.tree +0 -14
  132. package/test/trees/JBMultiTerminal/migrateBalanceOf.tree +0 -12
  133. package/test/trees/JBMultiTerminal/pay.tree +0 -23
  134. package/test/trees/JBMultiTerminal/processHeldFeesOf.tree +0 -8
  135. package/test/trees/JBMultiTerminal/sendPayoutsOf.tree +0 -34
  136. package/test/trees/JBMultiTerminal/useAllowanceOf.tree +0 -16
  137. package/test/trees/JBPermissions/hasPermission.tree +0 -8
  138. package/test/trees/JBPermissions/hasPermissions.tree +0 -8
  139. package/test/trees/JBPermissions/setPermissionsFor.tree +0 -5
  140. package/test/trees/JBPrices/addPriceFeedFor.tree +0 -14
  141. package/test/trees/JBPrices/pricePerUnitOf.tree +0 -11
  142. package/test/trees/JBProjects/createFor.tree +0 -11
  143. package/test/trees/JBProjects/setTokenUriResolver.tree +0 -5
  144. package/test/trees/JBProjects/supportsInterface.tree +0 -9
  145. package/test/trees/JBProjects/tokenURI.tree +0 -5
  146. package/test/trees/JBRulesets/currentApprovalStatusForLatestRulesetOf.tree +0 -8
  147. package/test/trees/JBRulesets/currentOf.tree +0 -12
  148. package/test/trees/JBRulesets/getRulesetOf.tree +0 -5
  149. package/test/trees/JBRulesets/latestQueuedRulesetOf.tree +0 -10
  150. package/test/trees/JBRulesets/rulesetsOf.tree +0 -11
  151. package/test/trees/JBRulesets/upcomingRulesetOf.tree +0 -20
  152. package/test/trees/JBRulesets/updateRulesetWeightCache.tree +0 -5
  153. package/test/trees/JBSplits/setSplitGroupsOf.tree +0 -17
  154. package/test/trees/JBSplits/splitsOf.tree +0 -5
  155. package/test/trees/JBTerminalStore/currentReclaimableSurplusOf.tree +0 -16
  156. package/test/trees/JBTerminalStore/currentSurplusOf.tree +0 -25
  157. package/test/trees/JBTerminalStore/currentTotalSurplusOf.tree +0 -5
  158. package/test/trees/JBTerminalStore/recordCashOutsFor.tree +0 -16
  159. package/test/trees/JBTerminalStore/recordPaymentFrom.tree +0 -14
  160. package/test/trees/JBTerminalStore/recordPayoutFor.tree +0 -10
  161. package/test/trees/JBTerminalStore/recordTerminalMigration.tree +0 -5
  162. package/test/trees/JBTerminalStore/recordUsedAllowanceOf.tree +0 -10
  163. package/test/trees/JBTokens/burnFrom.tree +0 -10
  164. package/test/trees/JBTokens/claimTokensFor.tree +0 -10
  165. package/test/trees/JBTokens/deployERC20For.tree +0 -12
  166. package/test/trees/JBTokens/mintFor.tree +0 -10
  167. package/test/trees/JBTokens/setTokenFor.tree +0 -11
  168. package/test/trees/JBTokens/totalBalanceOf.tree +0 -5
  169. package/test/trees/JBTokens/totalSupplyOf.tree +0 -5
  170. package/test/trees/JBTokens/transferCreditsFrom.tree +0 -8
  171. package/test/trees/mintTokensOf.tree +0 -12
  172. package/test/units/static/JBChainlinkV3PriceFeed/TestPriceFeed.sol +0 -223
  173. package/test/units/static/JBController/JBControllerSetup.sol +0 -50
  174. package/test/units/static/JBController/TestBurnTokensOf.sol +0 -114
  175. package/test/units/static/JBController/TestClaimTokensFor.sol +0 -63
  176. package/test/units/static/JBController/TestDeployErc20For.sol +0 -86
  177. package/test/units/static/JBController/TestLaunchProjectFor.sol +0 -302
  178. package/test/units/static/JBController/TestLaunchRulesetsFor.sol +0 -342
  179. package/test/units/static/JBController/TestMigrateController.sol +0 -157
  180. package/test/units/static/JBController/TestMintTokensOfUnits.sol +0 -111
  181. package/test/units/static/JBController/TestOmnichainRulesetOperator.sol +0 -324
  182. package/test/units/static/JBController/TestPayReservedTokenToTerminal.sol +0 -74
  183. package/test/units/static/JBController/TestPreviewMintOf.sol +0 -117
  184. package/test/units/static/JBController/TestReceiveMigrationFrom.sol +0 -99
  185. package/test/units/static/JBController/TestRulesetViews.sol +0 -225
  186. package/test/units/static/JBController/TestSendReservedTokensToSplitsOf.sol +0 -615
  187. package/test/units/static/JBController/TestSetSplitGroupsOf.sol +0 -68
  188. package/test/units/static/JBController/TestSetTokenFor.sol +0 -239
  189. package/test/units/static/JBController/TestSetUriOf.sol +0 -57
  190. package/test/units/static/JBController/TestTransferCreditsFrom.sol +0 -169
  191. package/test/units/static/JBDeadline/TestDeadlineFuzz.sol +0 -211
  192. package/test/units/static/JBDirectory/JBDirectorySetup.sol +0 -26
  193. package/test/units/static/JBDirectory/TestPrimaryTerminalOf.sol +0 -126
  194. package/test/units/static/JBDirectory/TestSetControllerOf.sol +0 -183
  195. package/test/units/static/JBDirectory/TestSetControllerOfMigrationOrder.sol +0 -104
  196. package/test/units/static/JBDirectory/TestSetPrimaryTerminalOf.sol +0 -179
  197. package/test/units/static/JBDirectory/TestSetTerminalsOf.sol +0 -137
  198. package/test/units/static/JBERC20/JBERC20Setup.sol +0 -34
  199. package/test/units/static/JBERC20/SigUtils.sol +0 -36
  200. package/test/units/static/JBERC20/TestInitialize.sol +0 -60
  201. package/test/units/static/JBERC20/TestName.sol +0 -30
  202. package/test/units/static/JBERC20/TestNonces.sol +0 -62
  203. package/test/units/static/JBERC20/TestSymbol.sol +0 -31
  204. package/test/units/static/JBFeelessAdresses/JBFeelessSetup.sol +0 -22
  205. package/test/units/static/JBFeelessAdresses/TestInterfaces.sol +0 -30
  206. package/test/units/static/JBFeelessAdresses/TestSetFeelessAddress.sol +0 -35
  207. package/test/units/static/JBFees/TestFeesFuzz.sol +0 -79
  208. package/test/units/static/JBFixedPointNumber/TestAdjustDecimals.sol +0 -16
  209. package/test/units/static/JBFixedPointNumber/TestAdjustDecimalsFuzz.sol +0 -71
  210. package/test/units/static/JBFundAccessLimits/JBFundAccessSetup.sol +0 -24
  211. package/test/units/static/JBFundAccessLimits/TestFundAccessLimitsEdge.sol +0 -163
  212. package/test/units/static/JBFundAccessLimits/TestPayoutLimitOf.sol +0 -59
  213. package/test/units/static/JBFundAccessLimits/TestPayoutLimitsOf.sol +0 -101
  214. package/test/units/static/JBFundAccessLimits/TestSetFundAccessLimitsFor.sol +0 -189
  215. package/test/units/static/JBFundAccessLimits/TestSurplusAllowanceOf.sol +0 -64
  216. package/test/units/static/JBFundAccessLimits/TestSurplusAllowancesOf.sol +0 -102
  217. package/test/units/static/JBMetadataResolver/TestGetDataFor.sol +0 -90
  218. package/test/units/static/JBMetadataResolver/TestMetadataResolverEdgeCases.sol +0 -247
  219. package/test/units/static/JBMetadataResolver/TestMetadataResolverFuzz.sol +0 -229
  220. package/test/units/static/JBMultiTerminal/JBMultiTerminalSetup.sol +0 -50
  221. package/test/units/static/JBMultiTerminal/TestAccountingContextsOf.sol +0 -72
  222. package/test/units/static/JBMultiTerminal/TestAddAccountingContextsFor.sol +0 -289
  223. package/test/units/static/JBMultiTerminal/TestAddToBalanceOf.sol +0 -474
  224. package/test/units/static/JBMultiTerminal/TestCashOutTokensOf.sol +0 -624
  225. package/test/units/static/JBMultiTerminal/TestExecutePayout.sol +0 -578
  226. package/test/units/static/JBMultiTerminal/TestExecuteProcessFee.sol +0 -202
  227. package/test/units/static/JBMultiTerminal/TestMigrateBalanceOf.sol +0 -222
  228. package/test/units/static/JBMultiTerminal/TestPay.sol +0 -604
  229. package/test/units/static/JBMultiTerminal/TestPreviewCashOutFrom.sol +0 -117
  230. package/test/units/static/JBMultiTerminal/TestPreviewPayFor.sol +0 -114
  231. package/test/units/static/JBMultiTerminal/TestProcessHeldFeesOf.sol +0 -228
  232. package/test/units/static/JBMultiTerminal/TestSelfPayRevert.sol +0 -55
  233. package/test/units/static/JBMultiTerminal/TestSendPayoutsOf.sol +0 -257
  234. package/test/units/static/JBMultiTerminal/TestUseAllowanceOf.sol +0 -611
  235. package/test/units/static/JBPermissions/JBPermissionsSetup.sol +0 -20
  236. package/test/units/static/JBPermissions/TestHasPermission.sol +0 -50
  237. package/test/units/static/JBPermissions/TestHasPermissions.sol +0 -93
  238. package/test/units/static/JBPermissions/TestSetPermissionsFor.sol +0 -64
  239. package/test/units/static/JBPrices/JBPricesSetup.sol +0 -32
  240. package/test/units/static/JBPrices/TestAddPriceFeedFor.sol +0 -107
  241. package/test/units/static/JBPrices/TestPricePerUnitOf.sol +0 -132
  242. package/test/units/static/JBPrices/TestPrices.sol +0 -265
  243. package/test/units/static/JBProjects/JBProjectsSetup.sol +0 -22
  244. package/test/units/static/JBProjects/TestCreateFor.sol +0 -71
  245. package/test/units/static/JBProjects/TestInitialProject.sol +0 -21
  246. package/test/units/static/JBProjects/TestInterfaces.sol +0 -26
  247. package/test/units/static/JBProjects/TestSetResolver.sol +0 -37
  248. package/test/units/static/JBProjects/TestTokenUri.sol +0 -40
  249. package/test/units/static/JBRulesetMetadataResolver/TestSetCashOutTaxRateTo.sol +0 -108
  250. package/test/units/static/JBRulesets/JBRulesetsSetup.sol +0 -24
  251. package/test/units/static/JBRulesets/TestCurrentApprovalStatusForLatestRulesetOf.sol +0 -265
  252. package/test/units/static/JBRulesets/TestCurrentOf.sol +0 -242
  253. package/test/units/static/JBRulesets/TestGetRulesetOf.sol +0 -100
  254. package/test/units/static/JBRulesets/TestLatestQueuedRulesetOf.sol +0 -260
  255. package/test/units/static/JBRulesets/TestRulesets.sol +0 -632
  256. package/test/units/static/JBRulesets/TestRulesetsOf.sol +0 -37
  257. package/test/units/static/JBRulesets/TestUpcomingRulesetOf.sol +0 -522
  258. package/test/units/static/JBRulesets/TestUpdateRulesetWeightCache.sol +0 -96
  259. package/test/units/static/JBSplits/JBSplitsSetup.sol +0 -26
  260. package/test/units/static/JBSplits/TestSelfManagedSplitGroups.sol +0 -552
  261. package/test/units/static/JBSplits/TestSetSplitGroupsOf.sol +0 -377
  262. package/test/units/static/JBSplits/TestSplitsLockedEdge.sol +0 -267
  263. package/test/units/static/JBSplits/TestSplitsOf.sol +0 -24
  264. package/test/units/static/JBSplits/TestSplitsPacking.sol +0 -36
  265. package/test/units/static/JBSurplus/TestSurplusFuzz.sol +0 -160
  266. package/test/units/static/JBTerminalStore/JBTerminalStoreSetup.sol +0 -45
  267. package/test/units/static/JBTerminalStore/TestCurrentReclaimableSurplusOf.sol +0 -536
  268. package/test/units/static/JBTerminalStore/TestCurrentSurplusOf.sol +0 -463
  269. package/test/units/static/JBTerminalStore/TestCurrentTotalSurplusOf.sol +0 -135
  270. package/test/units/static/JBTerminalStore/TestPreviewCashOutFrom.sol +0 -476
  271. package/test/units/static/JBTerminalStore/TestPreviewPayFrom.sol +0 -494
  272. package/test/units/static/JBTerminalStore/TestRecordCashOutsFor.sol +0 -652
  273. package/test/units/static/JBTerminalStore/TestRecordPaymentFrom.sol +0 -744
  274. package/test/units/static/JBTerminalStore/TestRecordPayoutFor.sol +0 -289
  275. package/test/units/static/JBTerminalStore/TestRecordTerminalMigration.sol +0 -138
  276. package/test/units/static/JBTerminalStore/TestRecordUsedAllowanceOf.sol +0 -415
  277. package/test/units/static/JBTerminalStore/TestUint224Overflow.sol +0 -219
  278. package/test/units/static/JBTokens/JBTokensSetup.sol +0 -32
  279. package/test/units/static/JBTokens/TestBurnFrom.sol +0 -107
  280. package/test/units/static/JBTokens/TestClaimTokensFor.sol +0 -110
  281. package/test/units/static/JBTokens/TestDeployERC20ForUnits.sol +0 -92
  282. package/test/units/static/JBTokens/TestMintFor.sol +0 -100
  283. package/test/units/static/JBTokens/TestSetTokenFor.sol +0 -98
  284. package/test/units/static/JBTokens/TestTotalBalanceOf.sol +0 -65
  285. package/test/units/static/JBTokens/TestTotalSupplyOf.sol +0 -56
  286. 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
- }