@bananapus/core-v6 0.0.1

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 (436) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +112 -0
  3. package/SKILLS.md +151 -0
  4. package/docs/book.css +13 -0
  5. package/docs/book.toml +12 -0
  6. package/docs/solidity.min.js +74 -0
  7. package/docs/src/README.md +703 -0
  8. package/docs/src/SUMMARY.md +94 -0
  9. package/docs/src/src/JBChainlinkV3PriceFeed.sol/contract.JBChainlinkV3PriceFeed.md +83 -0
  10. package/docs/src/src/JBChainlinkV3SequencerPriceFeed.sol/contract.JBChainlinkV3SequencerPriceFeed.md +88 -0
  11. package/docs/src/src/JBController.sol/contract.JBController.md +1121 -0
  12. package/docs/src/src/JBDeadline.sol/contract.JBDeadline.md +84 -0
  13. package/docs/src/src/JBDirectory.sol/contract.JBDirectory.md +294 -0
  14. package/docs/src/src/JBERC20.sol/contract.JBERC20.md +190 -0
  15. package/docs/src/src/JBFeelessAddresses.sol/contract.JBFeelessAddresses.md +80 -0
  16. package/docs/src/src/JBFundAccessLimits.sol/contract.JBFundAccessLimits.md +253 -0
  17. package/docs/src/src/JBMultiTerminal.sol/contract.JBMultiTerminal.md +1472 -0
  18. package/docs/src/src/JBPermissions.sol/contract.JBPermissions.md +199 -0
  19. package/docs/src/src/JBPrices.sol/contract.JBPrices.md +154 -0
  20. package/docs/src/src/JBProjects.sol/contract.JBProjects.md +131 -0
  21. package/docs/src/src/JBRulesets.sol/contract.JBRulesets.md +677 -0
  22. package/docs/src/src/JBSplits.sol/contract.JBSplits.md +237 -0
  23. package/docs/src/src/JBTerminalStore.sol/contract.JBTerminalStore.md +591 -0
  24. package/docs/src/src/JBTokens.sol/contract.JBTokens.md +353 -0
  25. package/docs/src/src/README.md +25 -0
  26. package/docs/src/src/abstract/JBControlled.sol/abstract.JBControlled.md +64 -0
  27. package/docs/src/src/abstract/JBPermissioned.sol/abstract.JBPermissioned.md +84 -0
  28. package/docs/src/src/abstract/README.md +5 -0
  29. package/docs/src/src/enums/JBApprovalStatus.sol/enum.JBApprovalStatus.md +17 -0
  30. package/docs/src/src/enums/README.md +4 -0
  31. package/docs/src/src/interfaces/IJBCashOutHook.sol/interface.IJBCashOutHook.md +29 -0
  32. package/docs/src/src/interfaces/IJBCashOutTerminal.sol/interface.IJBCashOutTerminal.md +57 -0
  33. package/docs/src/src/interfaces/IJBControlled.sol/interface.IJBControlled.md +12 -0
  34. package/docs/src/src/interfaces/IJBController.sol/interface.IJBController.md +334 -0
  35. package/docs/src/src/interfaces/IJBDirectory.sol/interface.IJBDirectory.md +108 -0
  36. package/docs/src/src/interfaces/IJBDirectoryAccessControl.sol/interface.IJBDirectoryAccessControl.md +19 -0
  37. package/docs/src/src/interfaces/IJBFeeTerminal.sol/interface.IJBFeeTerminal.md +91 -0
  38. package/docs/src/src/interfaces/IJBFeelessAddresses.sol/interface.IJBFeelessAddresses.md +26 -0
  39. package/docs/src/src/interfaces/IJBFundAccessLimits.sol/interface.IJBFundAccessLimits.md +88 -0
  40. package/docs/src/src/interfaces/IJBMigratable.sol/interface.IJBMigratable.md +29 -0
  41. package/docs/src/src/interfaces/IJBMultiTerminal.sol/interface.IJBMultiTerminal.md +50 -0
  42. package/docs/src/src/interfaces/IJBPayHook.sol/interface.IJBPayHook.md +28 -0
  43. package/docs/src/src/interfaces/IJBPayoutTerminal.sol/interface.IJBPayoutTerminal.md +105 -0
  44. package/docs/src/src/interfaces/IJBPermissioned.sol/interface.IJBPermissioned.md +12 -0
  45. package/docs/src/src/interfaces/IJBPermissions.sol/interface.IJBPermissions.md +74 -0
  46. package/docs/src/src/interfaces/IJBPermitTerminal.sol/interface.IJBPermitTerminal.md +15 -0
  47. package/docs/src/src/interfaces/IJBPriceFeed.sol/interface.IJBPriceFeed.md +12 -0
  48. package/docs/src/src/interfaces/IJBPrices.sol/interface.IJBPrices.md +74 -0
  49. package/docs/src/src/interfaces/IJBProjectUriRegistry.sol/interface.IJBProjectUriRegistry.md +19 -0
  50. package/docs/src/src/interfaces/IJBProjects.sol/interface.IJBProjects.md +49 -0
  51. package/docs/src/src/interfaces/IJBRulesetApprovalHook.sol/interface.IJBRulesetApprovalHook.md +35 -0
  52. package/docs/src/src/interfaces/IJBRulesetDataHook.sol/interface.IJBRulesetDataHook.md +97 -0
  53. package/docs/src/src/interfaces/IJBRulesets.sol/interface.IJBRulesets.md +165 -0
  54. package/docs/src/src/interfaces/IJBSplitHook.sol/interface.IJBSplitHook.md +31 -0
  55. package/docs/src/src/interfaces/IJBSplits.sol/interface.IJBSplits.md +35 -0
  56. package/docs/src/src/interfaces/IJBTerminal.sol/interface.IJBTerminal.md +141 -0
  57. package/docs/src/src/interfaces/IJBTerminalStore.sol/interface.IJBTerminalStore.md +198 -0
  58. package/docs/src/src/interfaces/IJBToken.sol/interface.IJBToken.md +54 -0
  59. package/docs/src/src/interfaces/IJBTokenUriResolver.sol/interface.IJBTokenUriResolver.md +12 -0
  60. package/docs/src/src/interfaces/IJBTokens.sol/interface.IJBTokens.md +151 -0
  61. package/docs/src/src/interfaces/README.md +33 -0
  62. package/docs/src/src/libraries/JBCashOuts.sol/library.JBCashOuts.md +40 -0
  63. package/docs/src/src/libraries/JBConstants.sol/library.JBConstants.md +52 -0
  64. package/docs/src/src/libraries/JBCurrencyIds.sol/library.JBCurrencyIds.md +19 -0
  65. package/docs/src/src/libraries/JBFees.sol/library.JBFees.md +52 -0
  66. package/docs/src/src/libraries/JBFixedPointNumber.sol/library.JBFixedPointNumber.md +12 -0
  67. package/docs/src/src/libraries/JBMetadataResolver.sol/library.JBMetadataResolver.md +242 -0
  68. package/docs/src/src/libraries/JBRulesetMetadataResolver.sol/library.JBRulesetMetadataResolver.md +180 -0
  69. package/docs/src/src/libraries/JBSplitGroupIds.sol/library.JBSplitGroupIds.md +14 -0
  70. package/docs/src/src/libraries/JBSurplus.sol/library.JBSurplus.md +44 -0
  71. package/docs/src/src/libraries/README.md +12 -0
  72. package/docs/src/src/periphery/JBDeadline1Day.sol/contract.JBDeadline1Day.md +15 -0
  73. package/docs/src/src/periphery/JBDeadline3Days.sol/contract.JBDeadline3Days.md +15 -0
  74. package/docs/src/src/periphery/JBDeadline3Hours.sol/contract.JBDeadline3Hours.md +15 -0
  75. package/docs/src/src/periphery/JBDeadline7Days.sol/contract.JBDeadline7Days.md +15 -0
  76. package/docs/src/src/periphery/JBMatchingPriceFeed.sol/contract.JBMatchingPriceFeed.md +22 -0
  77. package/docs/src/src/periphery/README.md +8 -0
  78. package/docs/src/src/structs/JBAccountingContext.sol/struct.JBAccountingContext.md +20 -0
  79. package/docs/src/src/structs/JBAfterCashOutRecordedContext.sol/struct.JBAfterCashOutRecordedContext.md +43 -0
  80. package/docs/src/src/structs/JBAfterPayRecordedContext.sol/struct.JBAfterPayRecordedContext.md +42 -0
  81. package/docs/src/src/structs/JBBeforeCashOutRecordedContext.sol/struct.JBBeforeCashOutRecordedContext.md +45 -0
  82. package/docs/src/src/structs/JBBeforePayRecordedContext.sol/struct.JBBeforePayRecordedContext.md +41 -0
  83. package/docs/src/src/structs/JBCashOutHookSpecification.sol/struct.JBCashOutHookSpecification.md +22 -0
  84. package/docs/src/src/structs/JBCurrencyAmount.sol/struct.JBCurrencyAmount.md +17 -0
  85. package/docs/src/src/structs/JBFee.sol/struct.JBFee.md +20 -0
  86. package/docs/src/src/structs/JBFundAccessLimitGroup.sol/struct.JBFundAccessLimitGroup.md +39 -0
  87. package/docs/src/src/structs/JBPayHookSpecification.sol/struct.JBPayHookSpecification.md +22 -0
  88. package/docs/src/src/structs/JBPermissionsData.sol/struct.JBPermissionsData.md +21 -0
  89. package/docs/src/src/structs/JBRuleset.sol/struct.JBRuleset.md +55 -0
  90. package/docs/src/src/structs/JBRulesetConfig.sol/struct.JBRulesetConfig.md +51 -0
  91. package/docs/src/src/structs/JBRulesetMetadata.sol/struct.JBRulesetMetadata.md +79 -0
  92. package/docs/src/src/structs/JBRulesetWeightCache.sol/struct.JBRulesetWeightCache.md +16 -0
  93. package/docs/src/src/structs/JBRulesetWithMetadata.sol/struct.JBRulesetWithMetadata.md +16 -0
  94. package/docs/src/src/structs/JBSingleAllowance.sol/struct.JBSingleAllowance.md +26 -0
  95. package/docs/src/src/structs/JBSplit.sol/struct.JBSplit.md +49 -0
  96. package/docs/src/src/structs/JBSplitGroup.sol/struct.JBSplitGroup.md +17 -0
  97. package/docs/src/src/structs/JBSplitHookContext.sol/struct.JBSplitHookContext.md +29 -0
  98. package/docs/src/src/structs/JBTerminalConfig.sol/struct.JBTerminalConfig.md +16 -0
  99. package/docs/src/src/structs/JBTokenAmount.sol/struct.JBTokenAmount.md +23 -0
  100. package/docs/src/src/structs/README.md +25 -0
  101. package/foundry.lock +11 -0
  102. package/foundry.toml +41 -0
  103. package/package.json +38 -0
  104. package/remappings.txt +1 -0
  105. package/script/Deploy.s.sol +111 -0
  106. package/script/DeployPeriphery.s.sol +287 -0
  107. package/script/helpers/CoreDeploymentLib.sol +121 -0
  108. package/slither-ci.config.json +10 -0
  109. package/sphinx.lock +507 -0
  110. package/src/JBChainlinkV3PriceFeed.sol +77 -0
  111. package/src/JBChainlinkV3SequencerPriceFeed.sol +75 -0
  112. package/src/JBController.sol +1186 -0
  113. package/src/JBDeadline.sol +73 -0
  114. package/src/JBDirectory.sol +343 -0
  115. package/src/JBERC20.sol +131 -0
  116. package/src/JBFeelessAddresses.sol +54 -0
  117. package/src/JBFundAccessLimits.sol +308 -0
  118. package/src/JBMultiTerminal.sol +2024 -0
  119. package/src/JBPermissions.sol +252 -0
  120. package/src/JBPrices.sol +227 -0
  121. package/src/JBProjects.sol +126 -0
  122. package/src/JBRulesets.sol +1093 -0
  123. package/src/JBSplits.sol +324 -0
  124. package/src/JBTerminalStore.sol +908 -0
  125. package/src/JBTokens.sol +376 -0
  126. package/src/abstract/JBControlled.sol +48 -0
  127. package/src/abstract/JBPermissioned.sol +77 -0
  128. package/src/enums/JBApprovalStatus.sol +12 -0
  129. package/src/interfaces/IJBCashOutHook.sol +15 -0
  130. package/src/interfaces/IJBCashOutTerminal.sol +51 -0
  131. package/src/interfaces/IJBControlled.sol +10 -0
  132. package/src/interfaces/IJBController.sol +280 -0
  133. package/src/interfaces/IJBDirectory.sol +69 -0
  134. package/src/interfaces/IJBDirectoryAccessControl.sol +15 -0
  135. package/src/interfaces/IJBFeeTerminal.sol +61 -0
  136. package/src/interfaces/IJBFeelessAddresses.sol +17 -0
  137. package/src/interfaces/IJBFundAccessLimits.sol +94 -0
  138. package/src/interfaces/IJBMigratable.sol +24 -0
  139. package/src/interfaces/IJBMultiTerminal.sol +36 -0
  140. package/src/interfaces/IJBPayHook.sol +14 -0
  141. package/src/interfaces/IJBPayoutTerminal.sol +92 -0
  142. package/src/interfaces/IJBPermissioned.sol +10 -0
  143. package/src/interfaces/IJBPermissions.sol +71 -0
  144. package/src/interfaces/IJBPermitTerminal.sol +14 -0
  145. package/src/interfaces/IJBPriceFeed.sol +10 -0
  146. package/src/interfaces/IJBPrices.sol +65 -0
  147. package/src/interfaces/IJBProjectUriRegistry.sol +15 -0
  148. package/src/interfaces/IJBProjects.sol +27 -0
  149. package/src/interfaces/IJBRulesetApprovalHook.sol +21 -0
  150. package/src/interfaces/IJBRulesetDataHook.sol +56 -0
  151. package/src/interfaces/IJBRulesets.sol +151 -0
  152. package/src/interfaces/IJBSplitHook.sol +16 -0
  153. package/src/interfaces/IJBSplits.sol +28 -0
  154. package/src/interfaces/IJBTerminal.sol +120 -0
  155. package/src/interfaces/IJBTerminalStore.sol +225 -0
  156. package/src/interfaces/IJBToken.sol +39 -0
  157. package/src/interfaces/IJBTokenUriResolver.sol +10 -0
  158. package/src/interfaces/IJBTokens.sol +113 -0
  159. package/src/libraries/JBCashOuts.sol +120 -0
  160. package/src/libraries/JBConstants.sol +14 -0
  161. package/src/libraries/JBCurrencyIds.sol +7 -0
  162. package/src/libraries/JBFees.sol +28 -0
  163. package/src/libraries/JBFixedPointNumber.sol +12 -0
  164. package/src/libraries/JBMetadataResolver.sol +306 -0
  165. package/src/libraries/JBRulesetMetadataResolver.sol +160 -0
  166. package/src/libraries/JBSplitGroupIds.sol +7 -0
  167. package/src/libraries/JBSurplus.sol +40 -0
  168. package/src/periphery/JBDeadline1Day.sol +8 -0
  169. package/src/periphery/JBDeadline3Days.sol +8 -0
  170. package/src/periphery/JBDeadline3Hours.sol +8 -0
  171. package/src/periphery/JBDeadline7Days.sol +8 -0
  172. package/src/periphery/JBMatchingPriceFeed.sol +13 -0
  173. package/src/structs/JBAccountingContext.sol +12 -0
  174. package/src/structs/JBAfterCashOutRecordedContext.sol +30 -0
  175. package/src/structs/JBAfterPayRecordedContext.sol +29 -0
  176. package/src/structs/JBBeforeCashOutRecordedContext.sol +31 -0
  177. package/src/structs/JBBeforePayRecordedContext.sol +28 -0
  178. package/src/structs/JBCashOutHookSpecification.sol +15 -0
  179. package/src/structs/JBCurrencyAmount.sol +10 -0
  180. package/src/structs/JBFee.sol +12 -0
  181. package/src/structs/JBFundAccessLimitGroup.sol +28 -0
  182. package/src/structs/JBPayHookSpecification.sol +15 -0
  183. package/src/structs/JBPermissionsData.sol +13 -0
  184. package/src/structs/JBRuleset.sol +42 -0
  185. package/src/structs/JBRulesetConfig.sol +43 -0
  186. package/src/structs/JBRulesetMetadata.sol +56 -0
  187. package/src/structs/JBRulesetWeightCache.sol +9 -0
  188. package/src/structs/JBRulesetWithMetadata.sol +12 -0
  189. package/src/structs/JBSingleAllowance.sol +16 -0
  190. package/src/structs/JBSplit.sol +37 -0
  191. package/src/structs/JBSplitGroup.sol +12 -0
  192. package/src/structs/JBSplitHookContext.sol +20 -0
  193. package/src/structs/JBTerminalConfig.sol +12 -0
  194. package/src/structs/JBTokenAmount.sol +14 -0
  195. package/test/AuditExploits.t.sol +2710 -0
  196. package/test/ComprehensiveInvariant.t.sol +298 -0
  197. package/test/EconomicSimulation.t.sol +340 -0
  198. package/test/EntryPointPermutations.t.sol +671 -0
  199. package/test/FlashLoanAttacks.t.sol +792 -0
  200. package/test/PermissionEscalation.t.sol +679 -0
  201. package/test/RulesetTransitions.t.sol +699 -0
  202. package/test/SplitLoopTests.t.sol +731 -0
  203. package/test/TestAccessToFunds.sol +2644 -0
  204. package/test/TestCashOut.sol +185 -0
  205. package/test/TestCashOutCountFor.sol +272 -0
  206. package/test/TestCashOutHooks.sol +317 -0
  207. package/test/TestCashOutTimingEdge.sol +229 -0
  208. package/test/TestDurationUnderflow.sol +220 -0
  209. package/test/TestFeeProcessingFailure.sol +208 -0
  210. package/test/TestFees.sol +604 -0
  211. package/test/TestInterfaceSupport.sol +62 -0
  212. package/test/TestJBERC20Inheritance.sol +91 -0
  213. package/test/TestLaunchProject.sol +176 -0
  214. package/test/TestMetaTx.sol +203 -0
  215. package/test/TestMetadataParserLib.sol +438 -0
  216. package/test/TestMigrationHeldFees.sol +249 -0
  217. package/test/TestMintTokensOf.sol +172 -0
  218. package/test/TestMultiTokenSurplus.sol +206 -0
  219. package/test/TestMultipleAccessLimits.sol +642 -0
  220. package/test/TestPayBurnRedeemFlow.sol +180 -0
  221. package/test/TestPayHooks.sol +190 -0
  222. package/test/TestPermissions.sol +305 -0
  223. package/test/TestPermissionsEdge.sol +286 -0
  224. package/test/TestPermit2Terminal.sol +339 -0
  225. package/test/TestRulesetQueueing.sol +1001 -0
  226. package/test/TestRulesetQueuingStress.sol +778 -0
  227. package/test/TestRulesetWeightCaching.sol +177 -0
  228. package/test/TestSplits.sol +369 -0
  229. package/test/TestTerminalMigration.sol +167 -0
  230. package/test/TestTokenFlow.sol +174 -0
  231. package/test/WeirdTokenTests.t.sol +764 -0
  232. package/test/formal/BondingCurveProperties.t.sol +411 -0
  233. package/test/formal/FeeProperties.t.sol +246 -0
  234. package/test/helpers/JBTest.sol +129 -0
  235. package/test/helpers/MetadataResolverHelper.sol +116 -0
  236. package/test/helpers/TestBaseWorkflow.sol +317 -0
  237. package/test/invariants/Phase3DeepInvariant.t.sol +404 -0
  238. package/test/invariants/RulesetsInvariant.t.sol +115 -0
  239. package/test/invariants/TerminalStoreInvariant.t.sol +220 -0
  240. package/test/invariants/TokensInvariant.t.sol +184 -0
  241. package/test/invariants/handlers/ComprehensiveHandler.sol +285 -0
  242. package/test/invariants/handlers/EconomicHandler.sol +347 -0
  243. package/test/invariants/handlers/Phase3Handler.sol +414 -0
  244. package/test/invariants/handlers/RulesetsHandler.sol +111 -0
  245. package/test/invariants/handlers/TerminalStoreHandler.sol +146 -0
  246. package/test/invariants/handlers/TokensHandler.sol +127 -0
  247. package/test/mock/ERC2771ForwarderMock.sol +37 -0
  248. package/test/mock/MockERC20.sol +18 -0
  249. package/test/mock/MockMaliciousBeneficiary.sol +67 -0
  250. package/test/mock/MockMaliciousSplitHook.sol +42 -0
  251. package/test/mock/MockPriceFeed.sol +20 -0
  252. package/test/trees/JBController/burnTokensOf.tree +9 -0
  253. package/test/trees/JBController/claimTokensFor.tree +5 -0
  254. package/test/trees/JBController/deployERC20For.tree +5 -0
  255. package/test/trees/JBController/getRulesetOf.tree +5 -0
  256. package/test/trees/JBController/launchProjectFor.tree +12 -0
  257. package/test/trees/JBController/launchRulesetsFor.tree +8 -0
  258. package/test/trees/JBController/migrateController.tree +12 -0
  259. package/test/trees/JBController/mintTokensOf.tree +12 -0
  260. package/test/trees/JBController/payReservedTokenToTerminal.tree +8 -0
  261. package/test/trees/JBController/receiveMigrationFrom.tree +4 -0
  262. package/test/trees/JBController/sendReservedTokensToSplitsOf.tree +12 -0
  263. package/test/trees/JBController/setMetadataOf.tree +5 -0
  264. package/test/trees/JBController/setSplitGroupsOf.tree +5 -0
  265. package/test/trees/JBController/setTokenFor.tree +5 -0
  266. package/test/trees/JBController/transferCreditsFrom.tree +8 -0
  267. package/test/trees/JBDirectory/primaryTerminalOf.tree +8 -0
  268. package/test/trees/JBDirectory/setControllerOf.tree +11 -0
  269. package/test/trees/JBDirectory/setPrimaryTerminalOf.tree +15 -0
  270. package/test/trees/JBDirectory/setTerminalsOf.tree +11 -0
  271. package/test/trees/JBERC20/initialize.tree +7 -0
  272. package/test/trees/JBERC20/name.tree +5 -0
  273. package/test/trees/JBERC20/nonces.tree +5 -0
  274. package/test/trees/JBERC20/symbol.tree +5 -0
  275. package/test/trees/JBFeelessAddresses/setFeelessAddress.tree +5 -0
  276. package/test/trees/JBFeelessAddresses/supportsInterface.tree +5 -0
  277. package/test/trees/JBFundAccessLimits/payoutLimitOf.tree +5 -0
  278. package/test/trees/JBFundAccessLimits/payoutLimitsOf.tree +8 -0
  279. package/test/trees/JBFundAccessLimits/setFundAccessLimitsFor.tree +18 -0
  280. package/test/trees/JBFundAccessLimits/surplusAllowanceOf.tree +5 -0
  281. package/test/trees/JBFundAccessLimits/surplusAllowancesOf.tree +8 -0
  282. package/test/trees/JBMetadataResolver/getDataFor.tree +8 -0
  283. package/test/trees/JBMultiTerminal/accountingContextsOf.tree +5 -0
  284. package/test/trees/JBMultiTerminal/addAccountingContextsFor.tree +10 -0
  285. package/test/trees/JBMultiTerminal/addToBalanceOf.tree +23 -0
  286. package/test/trees/JBMultiTerminal/cashOutTokensOf.tree +23 -0
  287. package/test/trees/JBMultiTerminal/executePayout.tree +32 -0
  288. package/test/trees/JBMultiTerminal/executeProcessFee.tree +14 -0
  289. package/test/trees/JBMultiTerminal/migrateBalanceOf.tree +12 -0
  290. package/test/trees/JBMultiTerminal/pay.tree +23 -0
  291. package/test/trees/JBMultiTerminal/processHeldFeesOf.tree +8 -0
  292. package/test/trees/JBMultiTerminal/sendPayoutsOf.tree +34 -0
  293. package/test/trees/JBMultiTerminal/useAllowanceOf.tree +16 -0
  294. package/test/trees/JBPermissions/hasPermission.tree +8 -0
  295. package/test/trees/JBPermissions/hasPermissions.tree +8 -0
  296. package/test/trees/JBPermissions/setPermissionsFor.tree +5 -0
  297. package/test/trees/JBPrices/addPriceFeedFor.tree +14 -0
  298. package/test/trees/JBPrices/pricePerUnitOf.tree +11 -0
  299. package/test/trees/JBProjects/createFor.tree +11 -0
  300. package/test/trees/JBProjects/setTokenUriResolver.tree +5 -0
  301. package/test/trees/JBProjects/supportsInterface.tree +9 -0
  302. package/test/trees/JBProjects/tokenURI.tree +5 -0
  303. package/test/trees/JBRulesets/currentApprovalStatusForLatestRulesetOf.tree +8 -0
  304. package/test/trees/JBRulesets/currentOf.tree +12 -0
  305. package/test/trees/JBRulesets/getRulesetOf.tree +5 -0
  306. package/test/trees/JBRulesets/latestQueuedRulesetOf.tree +10 -0
  307. package/test/trees/JBRulesets/rulesetsOf.tree +11 -0
  308. package/test/trees/JBRulesets/upcomingRulesetOf.tree +20 -0
  309. package/test/trees/JBRulesets/updateRulesetWeightCache.tree +5 -0
  310. package/test/trees/JBSplits/setSplitGroupsOf.tree +17 -0
  311. package/test/trees/JBSplits/splitsOf.tree +5 -0
  312. package/test/trees/JBTerminalStore/currentReclaimableSurplusOf.tree +16 -0
  313. package/test/trees/JBTerminalStore/currentSurplusOf.tree +25 -0
  314. package/test/trees/JBTerminalStore/currentTotalSurplusOf.tree +5 -0
  315. package/test/trees/JBTerminalStore/recordCashOutsFor.tree +16 -0
  316. package/test/trees/JBTerminalStore/recordPaymentFrom.tree +14 -0
  317. package/test/trees/JBTerminalStore/recordPayoutFor.tree +10 -0
  318. package/test/trees/JBTerminalStore/recordTerminalMigration.tree +5 -0
  319. package/test/trees/JBTerminalStore/recordUsedAllowanceOf.tree +10 -0
  320. package/test/trees/JBTokens/burnFrom.tree +10 -0
  321. package/test/trees/JBTokens/claimTokensFor.tree +10 -0
  322. package/test/trees/JBTokens/deployERC20For.tree +12 -0
  323. package/test/trees/JBTokens/mintFor.tree +10 -0
  324. package/test/trees/JBTokens/setTokenFor.tree +11 -0
  325. package/test/trees/JBTokens/totalBalanceOf.tree +5 -0
  326. package/test/trees/JBTokens/totalSupplyOf.tree +5 -0
  327. package/test/trees/JBTokens/transferCreditsFrom.tree +8 -0
  328. package/test/trees/mintTokensOf.tree +12 -0
  329. package/test/units/static/JBChainlinkV3PriceFeed/TestPriceFeed.sol +220 -0
  330. package/test/units/static/JBController/JBControllerSetup.sol +40 -0
  331. package/test/units/static/JBController/TestBurnTokensOf.sol +107 -0
  332. package/test/units/static/JBController/TestClaimTokensFor.sol +60 -0
  333. package/test/units/static/JBController/TestDeployErc20For.sol +80 -0
  334. package/test/units/static/JBController/TestLaunchProjectFor.sol +282 -0
  335. package/test/units/static/JBController/TestLaunchRulesetsFor.sol +322 -0
  336. package/test/units/static/JBController/TestMigrateController.sol +148 -0
  337. package/test/units/static/JBController/TestMintTokensOfUnits.sol +102 -0
  338. package/test/units/static/JBController/TestPayReservedTokenToTerminal.sol +71 -0
  339. package/test/units/static/JBController/TestReceiveMigrationFrom.sol +95 -0
  340. package/test/units/static/JBController/TestRulesetViews.sol +219 -0
  341. package/test/units/static/JBController/TestSendReservedTokensToSplitsOf.sol +595 -0
  342. package/test/units/static/JBController/TestSetSplitGroupsOf.sol +63 -0
  343. package/test/units/static/JBController/TestSetTokenFor.sol +227 -0
  344. package/test/units/static/JBController/TestSetUriOf.sol +53 -0
  345. package/test/units/static/JBController/TestTransferCreditsFrom.sol +159 -0
  346. package/test/units/static/JBDeadline/TestDeadlineFuzz.sol +194 -0
  347. package/test/units/static/JBDirectory/JBDirectorySetup.sol +22 -0
  348. package/test/units/static/JBDirectory/TestPrimaryTerminalOf.sol +122 -0
  349. package/test/units/static/JBDirectory/TestSetControllerOf.sol +173 -0
  350. package/test/units/static/JBDirectory/TestSetControllerOfMigrationOrder.sol +98 -0
  351. package/test/units/static/JBDirectory/TestSetPrimaryTerminalOf.sol +169 -0
  352. package/test/units/static/JBDirectory/TestSetTerminalsOf.sol +128 -0
  353. package/test/units/static/JBERC20/JBERC20Setup.sol +20 -0
  354. package/test/units/static/JBERC20/SigUtils.sol +34 -0
  355. package/test/units/static/JBERC20/TestInitialize.sol +54 -0
  356. package/test/units/static/JBERC20/TestName.sol +30 -0
  357. package/test/units/static/JBERC20/TestNonces.sol +59 -0
  358. package/test/units/static/JBERC20/TestSymbol.sol +31 -0
  359. package/test/units/static/JBFeelessAdresses/JBFeelessSetup.sol +20 -0
  360. package/test/units/static/JBFeelessAdresses/TestInterfaces.sol +29 -0
  361. package/test/units/static/JBFeelessAdresses/TestSetFeelessAddress.sol +35 -0
  362. package/test/units/static/JBFees/TestFeesFuzz.sol +78 -0
  363. package/test/units/static/JBFixedPointNumber/TestAdjustDecimals.sol +16 -0
  364. package/test/units/static/JBFixedPointNumber/TestAdjustDecimalsFuzz.sol +71 -0
  365. package/test/units/static/JBFundAccessLimits/JBFundAccessSetup.sol +21 -0
  366. package/test/units/static/JBFundAccessLimits/TestFundAccessLimitsEdge.sol +159 -0
  367. package/test/units/static/JBFundAccessLimits/TestPayoutLimitOf.sol +56 -0
  368. package/test/units/static/JBFundAccessLimits/TestPayoutLimitsOf.sol +94 -0
  369. package/test/units/static/JBFundAccessLimits/TestSetFundAccessLimitsFor.sol +182 -0
  370. package/test/units/static/JBFundAccessLimits/TestSurplusAllowanceOf.sol +61 -0
  371. package/test/units/static/JBFundAccessLimits/TestSurplusAllowancesOf.sol +96 -0
  372. package/test/units/static/JBMetadataResolver/TestGetDataFor.sol +89 -0
  373. package/test/units/static/JBMetadataResolver/TestMetadataResolverFuzz.sol +227 -0
  374. package/test/units/static/JBMetadataResolver/TestMetadataResolverM20M21.sol +245 -0
  375. package/test/units/static/JBMultiTerminal/JBMultiTerminalSetup.sol +39 -0
  376. package/test/units/static/JBMultiTerminal/TestAccountingContextsOf.sol +65 -0
  377. package/test/units/static/JBMultiTerminal/TestAddAccountingContextsFor.sol +313 -0
  378. package/test/units/static/JBMultiTerminal/TestAddToBalanceOf.sol +432 -0
  379. package/test/units/static/JBMultiTerminal/TestCashOutTokensOf.sol +478 -0
  380. package/test/units/static/JBMultiTerminal/TestExecutePayout.sol +577 -0
  381. package/test/units/static/JBMultiTerminal/TestExecuteProcessFee.sol +176 -0
  382. package/test/units/static/JBMultiTerminal/TestMigrateBalanceOf.sol +190 -0
  383. package/test/units/static/JBMultiTerminal/TestPay.sol +514 -0
  384. package/test/units/static/JBMultiTerminal/TestProcessHeldFeesOf.sol +29 -0
  385. package/test/units/static/JBMultiTerminal/TestSendPayoutsOf.sol +243 -0
  386. package/test/units/static/JBMultiTerminal/TestUseAllowanceOf.sol +310 -0
  387. package/test/units/static/JBPermissions/JBPermissionsSetup.sol +18 -0
  388. package/test/units/static/JBPermissions/TestHasPermission.sol +50 -0
  389. package/test/units/static/JBPermissions/TestHasPermissions.sol +93 -0
  390. package/test/units/static/JBPermissions/TestSetPermissionsFor.sol +62 -0
  391. package/test/units/static/JBPrices/JBPricesSetup.sol +26 -0
  392. package/test/units/static/JBPrices/TestAddPriceFeedFor.sol +102 -0
  393. package/test/units/static/JBPrices/TestPricePerUnitOf.sol +129 -0
  394. package/test/units/static/JBPrices/TestPrices.sol +262 -0
  395. package/test/units/static/JBProjects/JBProjectsSetup.sol +20 -0
  396. package/test/units/static/JBProjects/TestCreateFor.sol +69 -0
  397. package/test/units/static/JBProjects/TestInitialProject.sol +19 -0
  398. package/test/units/static/JBProjects/TestInterfaces.sol +27 -0
  399. package/test/units/static/JBProjects/TestSetResolver.sol +36 -0
  400. package/test/units/static/JBProjects/TestTokenUri.sol +38 -0
  401. package/test/units/static/JBRulesetMetadataResolver/TestSetCashOutTaxRateTo.sol +99 -0
  402. package/test/units/static/JBRulesets/JBRulesetsSetup.sol +21 -0
  403. package/test/units/static/JBRulesets/TestCurrentApprovalStatusForLatestRulesetOf.sol +257 -0
  404. package/test/units/static/JBRulesets/TestCurrentOf.sol +231 -0
  405. package/test/units/static/JBRulesets/TestGetRulesetOf.sol +94 -0
  406. package/test/units/static/JBRulesets/TestLatestQueuedRulesetOf.sol +252 -0
  407. package/test/units/static/JBRulesets/TestRulesets.sol +617 -0
  408. package/test/units/static/JBRulesets/TestRulesetsOf.sol +37 -0
  409. package/test/units/static/JBRulesets/TestUpcomingRulesetOf.sol +526 -0
  410. package/test/units/static/JBRulesets/TestUpdateRulesetWeightCache.sol +91 -0
  411. package/test/units/static/JBSplits/JBSplitsSetup.sol +23 -0
  412. package/test/units/static/JBSplits/TestSelfManagedSplitGroups.sol +502 -0
  413. package/test/units/static/JBSplits/TestSetSplitGroupsOf.sol +370 -0
  414. package/test/units/static/JBSplits/TestSplitsLockedEdge.sol +262 -0
  415. package/test/units/static/JBSplits/TestSplitsOf.sol +24 -0
  416. package/test/units/static/JBSplits/TestSplitsPacking.sol +33 -0
  417. package/test/units/static/JBSurplus/TestSurplusFuzz.sol +125 -0
  418. package/test/units/static/JBTerminalStore/JBTerminalStoreSetup.sol +23 -0
  419. package/test/units/static/JBTerminalStore/TestCurrentReclaimableSurplusOf.sol +434 -0
  420. package/test/units/static/JBTerminalStore/TestCurrentSurplusOf.sol +428 -0
  421. package/test/units/static/JBTerminalStore/TestCurrentTotalSurplusOf.sol +65 -0
  422. package/test/units/static/JBTerminalStore/TestRecordCashOutsFor.sol +479 -0
  423. package/test/units/static/JBTerminalStore/TestRecordPaymentFrom.sol +508 -0
  424. package/test/units/static/JBTerminalStore/TestRecordPayoutFor.sol +257 -0
  425. package/test/units/static/JBTerminalStore/TestRecordTerminalMigration.sol +131 -0
  426. package/test/units/static/JBTerminalStore/TestRecordUsedAllowanceOf.sol +390 -0
  427. package/test/units/static/JBTerminalStore/TestUint224Overflow.sol +187 -0
  428. package/test/units/static/JBTokens/JBTokensSetup.sol +23 -0
  429. package/test/units/static/JBTokens/TestBurnFrom.sol +104 -0
  430. package/test/units/static/JBTokens/TestClaimTokensFor.sol +107 -0
  431. package/test/units/static/JBTokens/TestDeployERC20ForUnits.sol +89 -0
  432. package/test/units/static/JBTokens/TestMintFor.sol +97 -0
  433. package/test/units/static/JBTokens/TestSetTokenFor.sol +95 -0
  434. package/test/units/static/JBTokens/TestTotalBalanceOf.sol +65 -0
  435. package/test/units/static/JBTokens/TestTotalSupplyOf.sol +56 -0
  436. package/test/units/static/JBTokens/TestTransferCreditsFrom.sol +54 -0
@@ -0,0 +1,679 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.6;
3
+
4
+ import /* {*} from */ "./helpers/TestBaseWorkflow.sol";
5
+ import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
6
+
7
+ /// @notice Tests for permission system correctness: ROOT restrictions, wildcard, boundary IDs, escalation prevention.
8
+ contract PermissionEscalation_Local is TestBaseWorkflow {
9
+ using JBRulesetMetadataResolver for JBRuleset;
10
+
11
+ uint256 public projectId2;
12
+ uint256 public projectId3;
13
+ address public projectOwner;
14
+ address public alice;
15
+ address public bob;
16
+ address public charlie;
17
+
18
+ function setUp() public override {
19
+ super.setUp();
20
+ projectOwner = multisig();
21
+ alice = address(0xA11CE);
22
+ bob = address(0xB0B);
23
+ charlie = address(0xC4A7);
24
+
25
+ // Launch fee collector project (#1)
26
+ _launchFeeProject();
27
+
28
+ // Launch test project #2
29
+ projectId2 = _launchSimpleProject("project2");
30
+
31
+ // Launch test project #3
32
+ projectId3 = _launchSimpleProject("project3");
33
+
34
+ // Give Alice ROOT on project 2
35
+ uint8[] memory rootPerms = new uint8[](1);
36
+ rootPerms[0] = JBPermissionIds.ROOT;
37
+ vm.prank(projectOwner);
38
+ jbPermissions()
39
+ .setPermissionsFor(
40
+ projectOwner,
41
+ JBPermissionsData({operator: alice, projectId: uint64(projectId2), permissionIds: rootPerms})
42
+ );
43
+ }
44
+
45
+ // ═══════════════════════════════════════════════════════════════════
46
+ // Helpers
47
+ // ═══════════════════════════════════════════════════════════════════
48
+
49
+ function _launchFeeProject() internal {
50
+ JBRulesetConfig[] memory feeRulesetConfig = new JBRulesetConfig[](1);
51
+ feeRulesetConfig[0].mustStartAtOrAfter = 0;
52
+ feeRulesetConfig[0].duration = 0;
53
+ feeRulesetConfig[0].weight = 1000e18;
54
+ feeRulesetConfig[0].weightCutPercent = 0;
55
+ feeRulesetConfig[0].approvalHook = IJBRulesetApprovalHook(address(0));
56
+ feeRulesetConfig[0].metadata = JBRulesetMetadata({
57
+ reservedPercent: 0,
58
+ cashOutTaxRate: 0,
59
+ baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
60
+ pausePay: false,
61
+ pauseCreditTransfers: false,
62
+ allowOwnerMinting: false,
63
+ allowSetCustomToken: false,
64
+ allowTerminalMigration: false,
65
+ allowSetTerminals: false,
66
+ ownerMustSendPayouts: false,
67
+ allowSetController: false,
68
+ allowAddAccountingContext: true,
69
+ allowAddPriceFeed: false,
70
+ holdFees: false,
71
+ useTotalSurplusForCashOuts: false,
72
+ useDataHookForPay: false,
73
+ useDataHookForCashOut: false,
74
+ dataHook: address(0),
75
+ metadata: 0
76
+ });
77
+ feeRulesetConfig[0].splitGroups = new JBSplitGroup[](0);
78
+ feeRulesetConfig[0].fundAccessLimitGroups = new JBFundAccessLimitGroup[](0);
79
+
80
+ JBTerminalConfig[] memory terminalConfigurations = _defaultTerminalConfig();
81
+
82
+ jbController()
83
+ .launchProjectFor({
84
+ owner: address(420),
85
+ projectUri: "feeCollector",
86
+ rulesetConfigurations: feeRulesetConfig,
87
+ terminalConfigurations: terminalConfigurations,
88
+ memo: ""
89
+ });
90
+ }
91
+
92
+ function _launchSimpleProject(string memory uri) internal returns (uint256) {
93
+ JBRulesetConfig[] memory rulesetConfig = new JBRulesetConfig[](1);
94
+ rulesetConfig[0].mustStartAtOrAfter = 0;
95
+ rulesetConfig[0].duration = 0;
96
+ rulesetConfig[0].weight = 1000e18;
97
+ rulesetConfig[0].weightCutPercent = 0;
98
+ rulesetConfig[0].approvalHook = IJBRulesetApprovalHook(address(0));
99
+ rulesetConfig[0].metadata = JBRulesetMetadata({
100
+ reservedPercent: 0,
101
+ cashOutTaxRate: 3000,
102
+ baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
103
+ pausePay: false,
104
+ pauseCreditTransfers: false,
105
+ allowOwnerMinting: true,
106
+ allowSetCustomToken: true,
107
+ allowTerminalMigration: false,
108
+ allowSetTerminals: false,
109
+ ownerMustSendPayouts: false,
110
+ allowSetController: false,
111
+ allowAddAccountingContext: true,
112
+ allowAddPriceFeed: false,
113
+ holdFees: false,
114
+ useTotalSurplusForCashOuts: false,
115
+ useDataHookForPay: false,
116
+ useDataHookForCashOut: false,
117
+ dataHook: address(0),
118
+ metadata: 0
119
+ });
120
+ rulesetConfig[0].splitGroups = new JBSplitGroup[](0);
121
+ rulesetConfig[0].fundAccessLimitGroups = new JBFundAccessLimitGroup[](0);
122
+
123
+ return jbController()
124
+ .launchProjectFor({
125
+ owner: projectOwner,
126
+ projectUri: uri,
127
+ rulesetConfigurations: rulesetConfig,
128
+ terminalConfigurations: _defaultTerminalConfig(),
129
+ memo: ""
130
+ });
131
+ }
132
+
133
+ function _defaultTerminalConfig() internal view returns (JBTerminalConfig[] memory) {
134
+ JBTerminalConfig[] memory terminalConfigurations = new JBTerminalConfig[](1);
135
+ JBAccountingContext[] memory tokensToAccept = new JBAccountingContext[](1);
136
+ tokensToAccept[0] = JBAccountingContext({
137
+ token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
138
+ });
139
+ terminalConfigurations[0] =
140
+ JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: tokensToAccept});
141
+ return terminalConfigurations;
142
+ }
143
+
144
+ // ═══════════════════════════════════════════════════════════════════
145
+ // Test 1: ROOT cannot set wildcard permissions (projectId=0)
146
+ // ═══════════════════════════════════════════════════════════════════
147
+
148
+ function test_rootOperator_cannotSetWildcardPermissions() public {
149
+ // Alice has ROOT on project 2. She tries to grant Bob permissions at projectId=0 (wildcard).
150
+ uint8[] memory perms = new uint8[](1);
151
+ perms[0] = JBPermissionIds.CASH_OUT_TOKENS;
152
+
153
+ vm.prank(alice);
154
+ vm.expectRevert(
155
+ abi.encodeWithSelector(
156
+ JBPermissions.JBPermissions_Unauthorized.selector, projectOwner, alice, 0, JBPermissionIds.ROOT
157
+ )
158
+ );
159
+ jbPermissions()
160
+ .setPermissionsFor(projectOwner, JBPermissionsData({operator: bob, projectId: 0, permissionIds: perms}));
161
+ }
162
+
163
+ // ═══════════════════════════════════════════════════════════════════
164
+ // Test 2: ROOT cannot grant ROOT to a third party
165
+ // ═══════════════════════════════════════════════════════════════════
166
+
167
+ function test_rootOperator_cannotGrantRoot() public {
168
+ // Alice has ROOT on project 2. She tries to grant ROOT to Bob.
169
+ uint8[] memory perms = new uint8[](1);
170
+ perms[0] = JBPermissionIds.ROOT;
171
+
172
+ vm.prank(alice);
173
+ vm.expectRevert(
174
+ abi.encodeWithSelector(
175
+ JBPermissions.JBPermissions_Unauthorized.selector,
176
+ projectOwner,
177
+ alice,
178
+ uint64(projectId2),
179
+ JBPermissionIds.ROOT
180
+ )
181
+ );
182
+ jbPermissions()
183
+ .setPermissionsFor(
184
+ projectOwner, JBPermissionsData({operator: bob, projectId: uint64(projectId2), permissionIds: perms})
185
+ );
186
+ }
187
+
188
+ // ═══════════════════════════════════════════════════════════════════
189
+ // Test 3: ROOT CAN grant non-ROOT permissions (positive test)
190
+ // ═══════════════════════════════════════════════════════════════════
191
+
192
+ function test_rootOperator_canGrantNonRootPermissions() public {
193
+ // Alice has ROOT on project 2. She grants Bob CASH_OUT_TOKENS.
194
+ uint8[] memory perms = new uint8[](1);
195
+ perms[0] = JBPermissionIds.CASH_OUT_TOKENS;
196
+
197
+ vm.prank(alice);
198
+ jbPermissions()
199
+ .setPermissionsFor(
200
+ projectOwner, JBPermissionsData({operator: bob, projectId: uint64(projectId2), permissionIds: perms})
201
+ );
202
+
203
+ // Verify Bob now has CASH_OUT_TOKENS
204
+ bool hasPerm = jbPermissions()
205
+ .hasPermission({
206
+ operator: bob,
207
+ account: projectOwner,
208
+ projectId: projectId2,
209
+ permissionId: JBPermissionIds.CASH_OUT_TOKENS,
210
+ includeRoot: false,
211
+ includeWildcardProjectId: false
212
+ });
213
+ assertTrue(hasPerm, "ROOT should be able to grant non-ROOT permissions");
214
+ }
215
+
216
+ // ═══════════════════════════════════════════════════════════════════
217
+ // Test 4: Wildcard permission — applies cross-project
218
+ // ═══════════════════════════════════════════════════════════════════
219
+
220
+ function test_wildcardPermission_crossProject() public {
221
+ // Owner grants Bob CASH_OUT_TOKENS at projectId=0 (wildcard)
222
+ uint8[] memory perms = new uint8[](1);
223
+ perms[0] = JBPermissionIds.CASH_OUT_TOKENS;
224
+
225
+ vm.prank(projectOwner);
226
+ jbPermissions()
227
+ .setPermissionsFor(projectOwner, JBPermissionsData({operator: bob, projectId: 0, permissionIds: perms}));
228
+
229
+ // Bob should have CASH_OUT_TOKENS for project 2 (via wildcard)
230
+ bool hasPermProject2 = jbPermissions()
231
+ .hasPermission({
232
+ operator: bob,
233
+ account: projectOwner,
234
+ projectId: projectId2,
235
+ permissionId: JBPermissionIds.CASH_OUT_TOKENS,
236
+ includeRoot: false,
237
+ includeWildcardProjectId: true
238
+ });
239
+ assertTrue(hasPermProject2, "Wildcard should apply to project 2");
240
+
241
+ // Bob should have CASH_OUT_TOKENS for project 3 (via wildcard)
242
+ bool hasPermProject3 = jbPermissions()
243
+ .hasPermission({
244
+ operator: bob,
245
+ account: projectOwner,
246
+ projectId: projectId3,
247
+ permissionId: JBPermissionIds.CASH_OUT_TOKENS,
248
+ includeRoot: false,
249
+ includeWildcardProjectId: true
250
+ });
251
+ assertTrue(hasPermProject3, "Wildcard should apply to project 3");
252
+ }
253
+
254
+ // ═══════════════════════════════════════════════════════════════════
255
+ // Test 5: Permission revocation is immediate
256
+ // ═══════════════════════════════════════════════════════════════════
257
+
258
+ function test_permissionRevocation_immediate() public {
259
+ // Grant Bob CASH_OUT_TOKENS on project 2
260
+ uint8[] memory perms = new uint8[](1);
261
+ perms[0] = JBPermissionIds.CASH_OUT_TOKENS;
262
+
263
+ vm.prank(projectOwner);
264
+ jbPermissions()
265
+ .setPermissionsFor(
266
+ projectOwner, JBPermissionsData({operator: bob, projectId: uint64(projectId2), permissionIds: perms})
267
+ );
268
+
269
+ // Verify Bob has it
270
+ assertTrue(
271
+ jbPermissions()
272
+ .hasPermission({
273
+ operator: bob,
274
+ account: projectOwner,
275
+ projectId: projectId2,
276
+ permissionId: JBPermissionIds.CASH_OUT_TOKENS,
277
+ includeRoot: false,
278
+ includeWildcardProjectId: false
279
+ }),
280
+ "Bob should have CASH_OUT_TOKENS"
281
+ );
282
+
283
+ // Revoke by setting empty permissions
284
+ uint8[] memory emptyPerms = new uint8[](0);
285
+
286
+ vm.prank(projectOwner);
287
+ jbPermissions()
288
+ .setPermissionsFor(
289
+ projectOwner,
290
+ JBPermissionsData({operator: bob, projectId: uint64(projectId2), permissionIds: emptyPerms})
291
+ );
292
+
293
+ // Immediately verify Bob lost it
294
+ assertFalse(
295
+ jbPermissions()
296
+ .hasPermission({
297
+ operator: bob,
298
+ account: projectOwner,
299
+ projectId: projectId2,
300
+ permissionId: JBPermissionIds.CASH_OUT_TOKENS,
301
+ includeRoot: false,
302
+ includeWildcardProjectId: false
303
+ }),
304
+ "Revocation should be immediate"
305
+ );
306
+ }
307
+
308
+ // ═══════════════════════════════════════════════════════════════════
309
+ // Test 6: Bit 255 (ROOT) works. Bit 256 reverts.
310
+ // ═══════════════════════════════════════════════════════════════════
311
+
312
+ function test_permission_bit255_boundary() public {
313
+ // Permission 255 should work (max valid ID)
314
+ uint8[] memory perms = new uint8[](1);
315
+ perms[0] = 255;
316
+
317
+ vm.prank(projectOwner);
318
+ jbPermissions()
319
+ .setPermissionsFor(
320
+ projectOwner, JBPermissionsData({operator: bob, projectId: uint64(projectId2), permissionIds: perms})
321
+ );
322
+
323
+ bool hasPerm = jbPermissions()
324
+ .hasPermission({
325
+ operator: bob,
326
+ account: projectOwner,
327
+ projectId: projectId2,
328
+ permissionId: 255,
329
+ includeRoot: false,
330
+ includeWildcardProjectId: false
331
+ });
332
+ assertTrue(hasPerm, "Permission ID 255 should work");
333
+
334
+ // Permission 256 should revert (out of bounds)
335
+ vm.expectRevert(abi.encodeWithSelector(JBPermissions.JBPermissions_PermissionIdOutOfBounds.selector, 256));
336
+ jbPermissions()
337
+ .hasPermission({
338
+ operator: bob,
339
+ account: projectOwner,
340
+ projectId: projectId2,
341
+ permissionId: 256,
342
+ includeRoot: false,
343
+ includeWildcardProjectId: false
344
+ });
345
+ }
346
+
347
+ // ═══════════════════════════════════════════════════════════════════
348
+ // Test 7: Permission ID 0 reverts
349
+ // ═══════════════════════════════════════════════════════════════════
350
+
351
+ function test_permission_bit0_rejected() public {
352
+ // Permission 0 is invalid
353
+ uint8[] memory perms = new uint8[](1);
354
+ perms[0] = 0;
355
+
356
+ vm.prank(projectOwner);
357
+ vm.expectRevert(abi.encodeWithSelector(JBPermissions.JBPermissions_NoZeroPermission.selector));
358
+ jbPermissions()
359
+ .setPermissionsFor(
360
+ projectOwner, JBPermissionsData({operator: bob, projectId: uint64(projectId2), permissionIds: perms})
361
+ );
362
+ }
363
+
364
+ // ═══════════════════════════════════════════════════════════════════
365
+ // Test 8: Bob can't cashOut Alice's tokens without permission
366
+ // ═══════════════════════════════════════════════════════════════════
367
+
368
+ function test_permissionedOperation_cashOut_requiresPermission() public {
369
+ // Give Alice tokens by paying
370
+ vm.deal(alice, 10 ether);
371
+ vm.prank(alice);
372
+ uint256 tokens = jbMultiTerminal().pay{value: 10 ether}({
373
+ projectId: projectId2,
374
+ token: JBConstants.NATIVE_TOKEN,
375
+ amount: 10 ether,
376
+ beneficiary: alice,
377
+ minReturnedTokens: 0,
378
+ memo: "",
379
+ metadata: new bytes(0)
380
+ });
381
+
382
+ // Bob tries to cash out Alice's tokens without permission
383
+ vm.prank(bob);
384
+ vm.expectRevert();
385
+ jbMultiTerminal()
386
+ .cashOutTokensOf({
387
+ holder: alice,
388
+ projectId: projectId2,
389
+ cashOutCount: tokens,
390
+ tokenToReclaim: JBConstants.NATIVE_TOKEN,
391
+ minTokensReclaimed: 0,
392
+ beneficiary: payable(bob),
393
+ metadata: new bytes(0)
394
+ });
395
+ }
396
+
397
+ // ═══════════════════════════════════════════════════════════════════
398
+ // Test 9: ownerMustSendPayouts flag enforcement
399
+ // ═══════════════════════════════════════════════════════════════════
400
+
401
+ function test_permissionedOperation_sendPayouts_ownerMustSend() public {
402
+ // Launch project with ownerMustSendPayouts = true
403
+ JBRulesetConfig[] memory rulesetConfig = new JBRulesetConfig[](1);
404
+ rulesetConfig[0].mustStartAtOrAfter = 0;
405
+ rulesetConfig[0].duration = 0;
406
+ rulesetConfig[0].weight = 1000e18;
407
+ rulesetConfig[0].weightCutPercent = 0;
408
+ rulesetConfig[0].approvalHook = IJBRulesetApprovalHook(address(0));
409
+ rulesetConfig[0].metadata = JBRulesetMetadata({
410
+ reservedPercent: 0,
411
+ cashOutTaxRate: 0,
412
+ baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
413
+ pausePay: false,
414
+ pauseCreditTransfers: false,
415
+ allowOwnerMinting: true,
416
+ allowSetCustomToken: true,
417
+ allowTerminalMigration: false,
418
+ allowSetTerminals: false,
419
+ ownerMustSendPayouts: true, // KEY
420
+ allowSetController: false,
421
+ allowAddAccountingContext: true,
422
+ allowAddPriceFeed: false,
423
+ holdFees: false,
424
+ useTotalSurplusForCashOuts: false,
425
+ useDataHookForPay: false,
426
+ useDataHookForCashOut: false,
427
+ dataHook: address(0),
428
+ metadata: 0
429
+ });
430
+ rulesetConfig[0].splitGroups = new JBSplitGroup[](0);
431
+
432
+ JBCurrencyAmount[] memory payoutLimits = new JBCurrencyAmount[](1);
433
+ payoutLimits[0] = JBCurrencyAmount({amount: 10 ether, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))});
434
+ JBFundAccessLimitGroup[] memory fundAccessLimitGroups = new JBFundAccessLimitGroup[](1);
435
+ fundAccessLimitGroups[0] = JBFundAccessLimitGroup({
436
+ terminal: address(jbMultiTerminal()),
437
+ token: JBConstants.NATIVE_TOKEN,
438
+ payoutLimits: payoutLimits,
439
+ surplusAllowances: new JBCurrencyAmount[](0)
440
+ });
441
+ rulesetConfig[0].fundAccessLimitGroups = fundAccessLimitGroups;
442
+
443
+ uint256 pid = jbController()
444
+ .launchProjectFor({
445
+ owner: projectOwner,
446
+ projectUri: "ownerMustPayTest",
447
+ rulesetConfigurations: rulesetConfig,
448
+ terminalConfigurations: _defaultTerminalConfig(),
449
+ memo: ""
450
+ });
451
+
452
+ // Fund the project
453
+ vm.deal(address(0xBA1E), 20 ether);
454
+ vm.prank(address(0xBA1E));
455
+ jbMultiTerminal().pay{value: 20 ether}({
456
+ projectId: pid,
457
+ token: JBConstants.NATIVE_TOKEN,
458
+ amount: 20 ether,
459
+ beneficiary: address(0xBA1E),
460
+ minReturnedTokens: 0,
461
+ memo: "",
462
+ metadata: new bytes(0)
463
+ });
464
+
465
+ // Grant Bob SEND_PAYOUTS permission
466
+ uint8[] memory perms = new uint8[](1);
467
+ perms[0] = JBPermissionIds.SEND_PAYOUTS;
468
+ vm.prank(projectOwner);
469
+ jbPermissions()
470
+ .setPermissionsFor(
471
+ projectOwner, JBPermissionsData({operator: bob, projectId: uint64(pid), permissionIds: perms})
472
+ );
473
+
474
+ // Charlie (no permission) tries to send payouts — should fail because ownerMustSendPayouts
475
+ // requires SEND_PAYOUTS permission
476
+ vm.prank(charlie);
477
+ vm.expectRevert();
478
+ jbMultiTerminal()
479
+ .sendPayoutsOf({
480
+ projectId: pid,
481
+ token: JBConstants.NATIVE_TOKEN,
482
+ amount: 5 ether,
483
+ currency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
484
+ minTokensPaidOut: 0
485
+ });
486
+
487
+ // Bob (with SEND_PAYOUTS permission) CAN send payouts
488
+ vm.prank(bob);
489
+ jbMultiTerminal()
490
+ .sendPayoutsOf({
491
+ projectId: pid,
492
+ token: JBConstants.NATIVE_TOKEN,
493
+ amount: 5 ether,
494
+ currency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
495
+ minTokensPaidOut: 0
496
+ });
497
+ }
498
+
499
+ // ═══════════════════════════════════════════════════════════════════
500
+ // Test 10: ROOT on project 2 has no power over project 3
501
+ // ═══════════════════════════════════════════════════════════════════
502
+
503
+ function test_permission_rootOnProject_doesNotAffectOtherProject() public {
504
+ // Alice has ROOT on project 2 (from setUp)
505
+ // Alice should NOT have any permissions on project 3
506
+ bool hasPermOnProject3 = jbPermissions()
507
+ .hasPermission({
508
+ operator: alice,
509
+ account: projectOwner,
510
+ projectId: projectId3,
511
+ permissionId: JBPermissionIds.ROOT,
512
+ includeRoot: true,
513
+ includeWildcardProjectId: false
514
+ });
515
+ assertFalse(hasPermOnProject3, "ROOT on project 2 must not grant power over project 3");
516
+
517
+ bool hasCashOutOnProject3 = jbPermissions()
518
+ .hasPermission({
519
+ operator: alice,
520
+ account: projectOwner,
521
+ projectId: projectId3,
522
+ permissionId: JBPermissionIds.CASH_OUT_TOKENS,
523
+ includeRoot: true,
524
+ includeWildcardProjectId: false
525
+ });
526
+ assertFalse(hasCashOutOnProject3, "ROOT on project 2 must not grant CASH_OUT on project 3");
527
+ }
528
+
529
+ // ═══════════════════════════════════════════════════════════════════
530
+ // Test 11: Double set overwrites previous (not additive)
531
+ // ═══════════════════════════════════════════════════════════════════
532
+
533
+ function test_permission_doubleSet_overwritesPrevious() public {
534
+ // Grant Bob CASH_OUT_TOKENS + BURN_TOKENS
535
+ uint8[] memory perms1 = new uint8[](2);
536
+ perms1[0] = JBPermissionIds.CASH_OUT_TOKENS;
537
+ perms1[1] = JBPermissionIds.BURN_TOKENS;
538
+
539
+ vm.prank(projectOwner);
540
+ jbPermissions()
541
+ .setPermissionsFor(
542
+ projectOwner, JBPermissionsData({operator: bob, projectId: uint64(projectId2), permissionIds: perms1})
543
+ );
544
+
545
+ assertTrue(
546
+ jbPermissions()
547
+ .hasPermission({
548
+ operator: bob,
549
+ account: projectOwner,
550
+ projectId: projectId2,
551
+ permissionId: JBPermissionIds.CASH_OUT_TOKENS,
552
+ includeRoot: false,
553
+ includeWildcardProjectId: false
554
+ }),
555
+ "Bob should have CASH_OUT_TOKENS"
556
+ );
557
+ assertTrue(
558
+ jbPermissions()
559
+ .hasPermission({
560
+ operator: bob,
561
+ account: projectOwner,
562
+ projectId: projectId2,
563
+ permissionId: JBPermissionIds.BURN_TOKENS,
564
+ includeRoot: false,
565
+ includeWildcardProjectId: false
566
+ }),
567
+ "Bob should have BURN_TOKENS"
568
+ );
569
+
570
+ // Now set ONLY MINT_TOKENS — should replace all previous
571
+ uint8[] memory perms2 = new uint8[](1);
572
+ perms2[0] = JBPermissionIds.MINT_TOKENS;
573
+
574
+ vm.prank(projectOwner);
575
+ jbPermissions()
576
+ .setPermissionsFor(
577
+ projectOwner, JBPermissionsData({operator: bob, projectId: uint64(projectId2), permissionIds: perms2})
578
+ );
579
+
580
+ // Bob should only have MINT_TOKENS, not the previous ones
581
+ assertTrue(
582
+ jbPermissions()
583
+ .hasPermission({
584
+ operator: bob,
585
+ account: projectOwner,
586
+ projectId: projectId2,
587
+ permissionId: JBPermissionIds.MINT_TOKENS,
588
+ includeRoot: false,
589
+ includeWildcardProjectId: false
590
+ }),
591
+ "Bob should now have MINT_TOKENS"
592
+ );
593
+ assertFalse(
594
+ jbPermissions()
595
+ .hasPermission({
596
+ operator: bob,
597
+ account: projectOwner,
598
+ projectId: projectId2,
599
+ permissionId: JBPermissionIds.CASH_OUT_TOKENS,
600
+ includeRoot: false,
601
+ includeWildcardProjectId: false
602
+ }),
603
+ "Bob should no longer have CASH_OUT_TOKENS (overwritten)"
604
+ );
605
+ assertFalse(
606
+ jbPermissions()
607
+ .hasPermission({
608
+ operator: bob,
609
+ account: projectOwner,
610
+ projectId: projectId2,
611
+ permissionId: JBPermissionIds.BURN_TOKENS,
612
+ includeRoot: false,
613
+ includeWildcardProjectId: false
614
+ }),
615
+ "Bob should no longer have BURN_TOKENS (overwritten)"
616
+ );
617
+ }
618
+
619
+ // ═══════════════════════════════════════════════════════════════════
620
+ // Test 12: ERC2771 meta-tx uses correct msg.sender for permissions
621
+ // ═══════════════════════════════════════════════════════════════════
622
+
623
+ function test_rootPermission_trustedForwarder() public {
624
+ // Grant Bob ROOT on project 2
625
+ uint8[] memory perms = new uint8[](1);
626
+ perms[0] = JBPermissionIds.CASH_OUT_TOKENS;
627
+
628
+ vm.prank(projectOwner);
629
+ jbPermissions()
630
+ .setPermissionsFor(
631
+ projectOwner, JBPermissionsData({operator: bob, projectId: uint64(projectId2), permissionIds: perms})
632
+ );
633
+
634
+ // Call from trusted forwarder with Bob appended as sender
635
+ // The permission check should use Bob's address, not the forwarder
636
+ address forwarder = trustedForwarder();
637
+
638
+ // Verify the forwarder is set up correctly
639
+ assertTrue(forwarder != address(0), "Trusted forwarder should be set");
640
+
641
+ // Construct the calldata with Bob's address appended (ERC2771 pattern)
642
+ bytes memory callData = abi.encodeWithSelector(
643
+ IJBPermissions.hasPermission.selector,
644
+ bob,
645
+ projectOwner,
646
+ projectId2,
647
+ JBPermissionIds.CASH_OUT_TOKENS,
648
+ false,
649
+ false
650
+ );
651
+
652
+ // Direct call should return true
653
+ bool hasPerm = jbPermissions()
654
+ .hasPermission({
655
+ operator: bob,
656
+ account: projectOwner,
657
+ projectId: projectId2,
658
+ permissionId: JBPermissionIds.CASH_OUT_TOKENS,
659
+ includeRoot: false,
660
+ includeWildcardProjectId: false
661
+ });
662
+ assertTrue(hasPerm, "Bob should have CASH_OUT_TOKENS via direct call");
663
+
664
+ // Verify that permission checking respects msg.sender context
665
+ // Charlie (unpermissioned) cannot use Bob's permissions
666
+ bool charlieHasPerm = jbPermissions()
667
+ .hasPermission({
668
+ operator: charlie,
669
+ account: projectOwner,
670
+ projectId: projectId2,
671
+ permissionId: JBPermissionIds.CASH_OUT_TOKENS,
672
+ includeRoot: false,
673
+ includeWildcardProjectId: false
674
+ });
675
+ assertFalse(charlieHasPerm, "Charlie should NOT have Bob's CASH_OUT_TOKENS");
676
+ }
677
+
678
+ receive() external payable {}
679
+ }