@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,1186 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
5
+ import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
6
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
7
+ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
8
+ import {Context} from "@openzeppelin/contracts/utils/Context.sol";
9
+ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
10
+ import {mulDiv} from "@prb/math/src/Common.sol";
11
+
12
+ import {JBPermissioned} from "./abstract/JBPermissioned.sol";
13
+ import {JBApprovalStatus} from "./enums/JBApprovalStatus.sol";
14
+ import {IJBController} from "./interfaces/IJBController.sol";
15
+ import {IJBDirectory} from "./interfaces/IJBDirectory.sol";
16
+ import {IJBDirectoryAccessControl} from "./interfaces/IJBDirectoryAccessControl.sol";
17
+ import {IJBFundAccessLimits} from "./interfaces/IJBFundAccessLimits.sol";
18
+ import {IJBMigratable} from "./interfaces/IJBMigratable.sol";
19
+ import {IJBPermissioned} from "./interfaces/IJBPermissioned.sol";
20
+ import {IJBPermissions} from "./interfaces/IJBPermissions.sol";
21
+ import {IJBPriceFeed} from "./interfaces/IJBPriceFeed.sol";
22
+ import {IJBPrices} from "./interfaces/IJBPrices.sol";
23
+ import {IJBProjects} from "./interfaces/IJBProjects.sol";
24
+ import {IJBProjectUriRegistry} from "./interfaces/IJBProjectUriRegistry.sol";
25
+ import {IJBRulesetDataHook} from "./interfaces/IJBRulesetDataHook.sol";
26
+ import {IJBRulesets} from "./interfaces/IJBRulesets.sol";
27
+ import {IJBSplitHook} from "./interfaces/IJBSplitHook.sol";
28
+ import {IJBSplits} from "./interfaces/IJBSplits.sol";
29
+ import {IJBTerminal} from "./interfaces/IJBTerminal.sol";
30
+ import {IJBToken} from "./interfaces/IJBToken.sol";
31
+ import {IJBTokens} from "./interfaces/IJBTokens.sol";
32
+ import {JBConstants} from "./libraries/JBConstants.sol";
33
+ import {JBRulesetMetadataResolver} from "./libraries/JBRulesetMetadataResolver.sol";
34
+ import {JBSplitGroupIds} from "./libraries/JBSplitGroupIds.sol";
35
+ import {JBRuleset} from "./structs/JBRuleset.sol";
36
+ import {JBRulesetConfig} from "./structs/JBRulesetConfig.sol";
37
+ import {JBRulesetMetadata} from "./structs/JBRulesetMetadata.sol";
38
+ import {JBRulesetWithMetadata} from "./structs/JBRulesetWithMetadata.sol";
39
+ import {JBSplit} from "./structs/JBSplit.sol";
40
+ import {JBSplitGroup} from "./structs/JBSplitGroup.sol";
41
+ import {JBSplitHookContext} from "./structs/JBSplitHookContext.sol";
42
+ import {JBTerminalConfig} from "./structs/JBTerminalConfig.sol";
43
+
44
+ /// @notice `JBController` coordinates rulesets and project tokens, and is the entry point for most operations related
45
+ /// to rulesets and project tokens.
46
+ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigratable {
47
+ // A library that parses packed ruleset metadata into a friendlier format.
48
+ using JBRulesetMetadataResolver for JBRuleset;
49
+
50
+ // A library that adds default safety checks to ERC20 functionality.
51
+ using SafeERC20 for IERC20;
52
+
53
+ //*********************************************************************//
54
+ // --------------------------- custom errors ------------------------- //
55
+ //*********************************************************************//
56
+
57
+ error JBController_AddingPriceFeedNotAllowed(uint256 projectId);
58
+ error JBController_CreditTransfersPaused();
59
+ error JBController_InvalidCashOutTaxRate(uint256 rate, uint256 limit);
60
+ error JBController_InvalidReservedPercent(uint256 percent, uint256 limit);
61
+ error JBController_MintNotAllowedAndNotTerminalOrHook(address caller);
62
+ error JBController_NoReservedTokens();
63
+ error JBController_OnlyDirectory(address sender, IJBDirectory directory);
64
+ error JBController_PendingReservedTokens(uint256 pendingReservedTokenBalance);
65
+ error JBController_RulesetsAlreadyLaunched(uint256 projectId);
66
+ error JBController_RulesetsArrayEmpty();
67
+ error JBController_RulesetSetTokenNotAllowed(uint256 projectId);
68
+ error JBController_TerminalTokensNotTransferred();
69
+ error JBController_ZeroTokensToBurn();
70
+ error JBController_ZeroTokensToMint();
71
+
72
+ //*********************************************************************//
73
+ // --------------- public immutable stored properties ---------------- //
74
+ //*********************************************************************//
75
+
76
+ /// @notice The directory of terminals and controllers for projects.
77
+ IJBDirectory public immutable override DIRECTORY;
78
+
79
+ /// @notice A contract that stores fund access limits for each project.
80
+ IJBFundAccessLimits public immutable override FUND_ACCESS_LIMITS;
81
+
82
+ /// @notice A contract that stores prices for each project.
83
+ IJBPrices public immutable override PRICES;
84
+
85
+ /// @notice Mints ERC-721s that represent project ownership and transfers.
86
+ IJBProjects public immutable override PROJECTS;
87
+
88
+ /// @notice The contract storing and managing project rulesets.
89
+ IJBRulesets public immutable override RULESETS;
90
+
91
+ /// @notice The contract that stores splits for each project.
92
+ IJBSplits public immutable override SPLITS;
93
+
94
+ /// @notice The contract that manages token minting and burning.
95
+ IJBTokens public immutable override TOKENS;
96
+
97
+ /// @notice The address of the contract that manages omnichain ruleset ops.
98
+ address public immutable override OMNICHAIN_RULESET_OPERATOR;
99
+
100
+ //*********************************************************************//
101
+ // --------------------- public stored properties -------------------- //
102
+ //*********************************************************************//
103
+
104
+ /// @notice A project's unrealized reserved token balance (i.e. reserved tokens which haven't been sent out to the
105
+ /// reserved token split group yet).
106
+ /// @custom:param projectId The ID of the project to get the pending reserved token balance of.
107
+ mapping(uint256 projectId => uint256) public override pendingReservedTokenBalanceOf;
108
+
109
+ /// @notice The metadata URI for each project. This is typically an IPFS hash, optionally with an `ipfs://` prefix.
110
+ /// @custom:param projectId The ID of the project to get the metadata URI of.
111
+ mapping(uint256 projectId => string) public override uriOf;
112
+
113
+ //*********************************************************************//
114
+ // ---------------------------- constructor -------------------------- //
115
+ //*********************************************************************//
116
+
117
+ /// @param directory A contract storing directories of terminals and controllers for each project.
118
+ /// @param fundAccessLimits A contract that stores fund access limits for each project.
119
+ /// @param permissions A contract storing permissions.
120
+ /// @param prices A contract that stores prices for each project.
121
+ /// @param projects A contract which mints ERC-721s that represent project ownership and transfers.
122
+ /// @param rulesets A contract storing and managing project rulesets.
123
+ /// @param splits A contract that stores splits for each project.
124
+ /// @param tokens A contract that manages token minting and burning.
125
+ /// @param omnichainRulesetOperator The address of the contract that manages omnichain ruleset ops.
126
+ /// @param trustedForwarder The trusted forwarder for the ERC2771Context.
127
+ constructor(
128
+ IJBDirectory directory,
129
+ IJBFundAccessLimits fundAccessLimits,
130
+ IJBPermissions permissions,
131
+ IJBPrices prices,
132
+ IJBProjects projects,
133
+ IJBRulesets rulesets,
134
+ IJBSplits splits,
135
+ IJBTokens tokens,
136
+ address omnichainRulesetOperator,
137
+ address trustedForwarder
138
+ )
139
+ JBPermissioned(permissions)
140
+ ERC2771Context(trustedForwarder)
141
+ {
142
+ DIRECTORY = directory;
143
+ FUND_ACCESS_LIMITS = fundAccessLimits;
144
+ PRICES = prices;
145
+ PROJECTS = projects;
146
+ RULESETS = rulesets;
147
+ SPLITS = splits;
148
+ TOKENS = tokens;
149
+ OMNICHAIN_RULESET_OPERATOR = omnichainRulesetOperator;
150
+ }
151
+
152
+ //*********************************************************************//
153
+ // ------------------------- external views -------------------------- //
154
+ //*********************************************************************//
155
+
156
+ /// @notice Get an array of a project's rulesets (with metadata) up to a maximum array size, sorted from latest to
157
+ /// earliest.
158
+ /// @param projectId The ID of the project to get the rulesets of.
159
+ /// @param startingId The ID of the ruleset to begin with. This will be the latest ruleset in the result. If the
160
+ /// `startingId` is 0, passed, the project's latest ruleset will be used.
161
+ /// @param size The maximum number of rulesets to return.
162
+ /// @return rulesets The array of rulesets with their metadata.
163
+ function allRulesetsOf(
164
+ uint256 projectId,
165
+ uint256 startingId,
166
+ uint256 size
167
+ )
168
+ external
169
+ view
170
+ override
171
+ returns (JBRulesetWithMetadata[] memory rulesets)
172
+ {
173
+ // Get the rulesets (without metadata).
174
+ JBRuleset[] memory baseRulesets = RULESETS.allOf({projectId: projectId, startingId: startingId, size: size});
175
+
176
+ // Keep a reference to the number of rulesets.
177
+ uint256 numberOfRulesets = baseRulesets.length;
178
+
179
+ // Initialize the array being returned.
180
+ rulesets = new JBRulesetWithMetadata[](numberOfRulesets);
181
+
182
+ // Populate the array with rulesets AND their metadata.
183
+ for (uint256 i; i < numberOfRulesets; i++) {
184
+ // Set the ruleset being iterated on.
185
+ JBRuleset memory baseRuleset = baseRulesets[i];
186
+
187
+ // Set the returned value.
188
+ rulesets[i] = JBRulesetWithMetadata({ruleset: baseRuleset, metadata: baseRuleset.expandMetadata()});
189
+ }
190
+ }
191
+
192
+ /// @notice A project's currently active ruleset and its metadata.
193
+ /// @param projectId The ID of the project to get the current ruleset of.
194
+ /// @return ruleset The current ruleset's struct.
195
+ /// @return metadata The current ruleset's metadata.
196
+ function currentRulesetOf(uint256 projectId)
197
+ external
198
+ view
199
+ override
200
+ returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata)
201
+ {
202
+ ruleset = _currentRulesetOf(projectId);
203
+ metadata = ruleset.expandMetadata();
204
+ }
205
+
206
+ /// @notice Get the `JBRuleset` and `JBRulesetMetadata` corresponding to the specified `rulesetId`.
207
+ /// @param projectId The ID of the project the ruleset belongs to.
208
+ /// @return ruleset The ruleset's struct.
209
+ /// @return metadata The ruleset's metadata.
210
+ function getRulesetOf(
211
+ uint256 projectId,
212
+ uint256 rulesetId
213
+ )
214
+ external
215
+ view
216
+ override
217
+ returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata)
218
+ {
219
+ ruleset = RULESETS.getRulesetOf({projectId: projectId, rulesetId: rulesetId});
220
+ metadata = ruleset.expandMetadata();
221
+ }
222
+
223
+ /// @notice Gets the latest ruleset queued for a project, its approval status, and its metadata.
224
+ /// @dev The 'latest queued ruleset' is the ruleset initialized furthest in the future (at the end of the ruleset
225
+ /// queue).
226
+ /// @param projectId The ID of the project to get the latest ruleset of.
227
+ /// @return ruleset The struct for the project's latest queued ruleset.
228
+ /// @return metadata The ruleset's metadata.
229
+ /// @return approvalStatus The ruleset's approval status.
230
+ function latestQueuedRulesetOf(uint256 projectId)
231
+ external
232
+ view
233
+ override
234
+ returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata, JBApprovalStatus approvalStatus)
235
+ {
236
+ (ruleset, approvalStatus) = RULESETS.latestQueuedOf(projectId);
237
+ metadata = ruleset.expandMetadata();
238
+ }
239
+
240
+ /// @notice Check whether the project's terminals can currently be set.
241
+ /// @param projectId The ID of the project to check.
242
+ /// @return A `bool` which is true if the project allows terminals to be set.
243
+ function setTerminalsAllowed(uint256 projectId) external view returns (bool) {
244
+ return _currentRulesetOf(projectId).expandMetadata().allowSetTerminals;
245
+ }
246
+
247
+ /// @notice Check whether the project's controller can currently be set.
248
+ /// @param projectId The ID of the project to check.
249
+ /// @return A `bool` which is true if the project allows controllers to be set.
250
+ function setControllerAllowed(uint256 projectId) external view returns (bool) {
251
+ return _currentRulesetOf(projectId).expandMetadata().allowSetController;
252
+ }
253
+
254
+ /// @notice Gets the a project token's total supply, including pending reserved tokens.
255
+ /// @param projectId The ID of the project to get the total token supply of.
256
+ /// @return The total supply of the project's token, including pending reserved tokens.
257
+ function totalTokenSupplyWithReservedTokensOf(uint256 projectId) external view override returns (uint256) {
258
+ // Add the reserved tokens to the total supply.
259
+ return TOKENS.totalSupplyOf(projectId) + pendingReservedTokenBalanceOf[projectId];
260
+ }
261
+
262
+ /// @notice A project's next ruleset along with its metadata.
263
+ /// @dev If an upcoming ruleset isn't found, returns an empty ruleset with all properties set to 0.
264
+ /// @param projectId The ID of the project to get the next ruleset of.
265
+ /// @return ruleset The upcoming ruleset's struct.
266
+ /// @return metadata The upcoming ruleset's metadata.
267
+ function upcomingRulesetOf(uint256 projectId)
268
+ external
269
+ view
270
+ override
271
+ returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata)
272
+ {
273
+ ruleset = _upcomingRulesetOf(projectId);
274
+ metadata = ruleset.expandMetadata();
275
+ }
276
+
277
+ //*********************************************************************//
278
+ // -------------------------- public views --------------------------- //
279
+ //*********************************************************************//
280
+
281
+ /// @notice Indicates whether this contract adheres to the specified interface.
282
+ /// @dev See {IERC165-supportsInterface}.
283
+ /// @param interfaceId The ID of the interface to check for adherence to.
284
+ /// @return A flag indicating if the provided interface ID is supported.
285
+ function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
286
+ return interfaceId == type(IJBController).interfaceId || interfaceId == type(IJBProjectUriRegistry).interfaceId
287
+ || interfaceId == type(IJBDirectoryAccessControl).interfaceId
288
+ || interfaceId == type(IJBMigratable).interfaceId || interfaceId == type(IJBPermissioned).interfaceId
289
+ || interfaceId == type(IERC165).interfaceId;
290
+ }
291
+
292
+ //*********************************************************************//
293
+ // -------------------------- internal views ------------------------- //
294
+ //*********************************************************************//
295
+
296
+ /// @dev `ERC-2771` specifies the context as being a single address (20 bytes).
297
+ function _contextSuffixLength() internal view override(ERC2771Context, Context) returns (uint256) {
298
+ return super._contextSuffixLength();
299
+ }
300
+
301
+ /// @notice The project's current ruleset.
302
+ /// @param projectId The ID of the project to check.
303
+ /// @return The project's current ruleset.
304
+ function _currentRulesetOf(uint256 projectId) internal view returns (JBRuleset memory) {
305
+ return RULESETS.currentOf(projectId);
306
+ }
307
+
308
+ /// @notice Indicates whether the provided address is a terminal for the project.
309
+ /// @param projectId The ID of the project to check.
310
+ /// @param terminal The address to check.
311
+ /// @return A flag indicating if the provided address is a terminal for the project.
312
+ function _isTerminalOf(uint256 projectId, address terminal) internal view returns (bool) {
313
+ return DIRECTORY.isTerminalOf({projectId: projectId, terminal: IJBTerminal(terminal)});
314
+ }
315
+
316
+ /// @notice Indicates whether the provided address has mint permission for the project byway of the data hook.
317
+ /// @param projectId The ID of the project to check.
318
+ /// @param ruleset The ruleset to check.
319
+ /// @param addr The address to check.
320
+ /// @return A flag indicating if the provided address has mint permission for the project.
321
+ function _hasDataHookMintPermissionFor(
322
+ uint256 projectId,
323
+ JBRuleset memory ruleset,
324
+ address addr
325
+ )
326
+ internal
327
+ view
328
+ returns (bool)
329
+ {
330
+ address dataHook = ruleset.dataHook();
331
+
332
+ return dataHook != address(0)
333
+ && IJBRulesetDataHook(dataHook).hasMintPermissionFor({projectId: projectId, ruleset: ruleset, addr: addr});
334
+ }
335
+
336
+ /// @notice The calldata. Preferred to use over `msg.data`.
337
+ /// @return calldata The `msg.data` of this call.
338
+ function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) {
339
+ return ERC2771Context._msgData();
340
+ }
341
+
342
+ /// @notice The message's sender. Preferred to use over `msg.sender`.
343
+ /// @return sender The address which sent this call.
344
+ function _msgSender() internal view override(ERC2771Context, Context) returns (address sender) {
345
+ return ERC2771Context._msgSender();
346
+ }
347
+
348
+ /// @notice The project's upcoming ruleset.
349
+ /// @param projectId The ID of the project to check.
350
+ /// @return The project's upcoming ruleset.
351
+ function _upcomingRulesetOf(uint256 projectId) internal view returns (JBRuleset memory) {
352
+ return RULESETS.upcomingOf(projectId);
353
+ }
354
+
355
+ //*********************************************************************//
356
+ // --------------------- external transactions ----------------------- //
357
+ //*********************************************************************//
358
+
359
+ /// @notice Add a price feed for a project.
360
+ /// @dev Can only be called by the project's owner or an address with the owner's permission to `ADD_PRICE_FEED`.
361
+ /// @param projectId The ID of the project to add the feed for.
362
+ /// @param pricingCurrency The currency the feed's output price is in terms of.
363
+ /// @param unitCurrency The currency being priced by the feed.
364
+ /// @param feed The address of the price feed to add.
365
+ function addPriceFeed(
366
+ uint256 projectId,
367
+ uint256 pricingCurrency,
368
+ uint256 unitCurrency,
369
+ IJBPriceFeed feed
370
+ )
371
+ external
372
+ override
373
+ {
374
+ // Enforce permissions.
375
+ _requirePermissionFrom({
376
+ account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.ADD_PRICE_FEED
377
+ });
378
+
379
+ JBRuleset memory ruleset = _currentRulesetOf(projectId);
380
+
381
+ // Make sure the project's ruleset allows adding price feeds.
382
+ if (!ruleset.allowAddPriceFeed()) revert JBController_AddingPriceFeedNotAllowed(projectId);
383
+
384
+ PRICES.addPriceFeedFor({
385
+ projectId: projectId, pricingCurrency: pricingCurrency, unitCurrency: unitCurrency, feed: feed
386
+ });
387
+ }
388
+
389
+ /// @notice Prepares this controller to receive a project being migrated from another controller.
390
+ /// @dev This controller should not be the project's controller yet.
391
+ /// @param from The controller being migrated from.
392
+ /// @param projectId The ID of the project that will migrate to this controller.
393
+ function beforeReceiveMigrationFrom(IERC165 from, uint256 projectId) external override {
394
+ // Keep a reference to the sender.
395
+ address sender = _msgSender();
396
+
397
+ // Make sure the sender is the expected source controller.
398
+ if (sender != address(DIRECTORY)) revert JBController_OnlyDirectory(sender, DIRECTORY);
399
+
400
+ // If the sending controller is an `IJBProjectUriRegistry`, copy the project's metadata URI.
401
+ if (from.supportsInterface(type(IJBProjectUriRegistry).interfaceId)) {
402
+ uriOf[projectId] = IJBProjectUriRegistry(address(from)).uriOf(projectId);
403
+ }
404
+
405
+ // Send the pending reserved tokens to the splits.
406
+ if (
407
+ from.supportsInterface(type(IJBController).interfaceId)
408
+ && IJBController(address(from)).pendingReservedTokenBalanceOf(projectId) > 0
409
+ ) {
410
+ // slither-disable-next-line unused-return
411
+ IJBController(address(from)).sendReservedTokensToSplitsOf(projectId);
412
+ }
413
+ }
414
+
415
+ /// @notice Called after this controller has been set as the project's controller in the directory.
416
+ /// @dev Can only be called by the directory.
417
+ /// @param from The controller being migrated from.
418
+ /// @param projectId The ID of the project that migrated to this controller.
419
+ function afterReceiveMigrationFrom(IERC165 from, uint256 projectId) external override {
420
+ from; // Suppress unused variable warning.
421
+ projectId; // Suppress unused variable warning.
422
+
423
+ // Make sure the sender is the directory.
424
+ if (_msgSender() != address(DIRECTORY)) revert JBController_OnlyDirectory(_msgSender(), DIRECTORY);
425
+ }
426
+
427
+ /// @notice Burns a project's tokens or credits from the specific holder's balance.
428
+ /// @dev Can only be called by the holder, an address with the holder's permission to `BURN_TOKENS`, or a project's
429
+ /// terminal.
430
+ /// @param holder The address whose tokens are being burned.
431
+ /// @param projectId The ID of the project whose tokens are being burned.
432
+ /// @param tokenCount The number of tokens to burn.
433
+ /// @param memo A memo to pass along to the emitted event.
434
+ function burnTokensOf(
435
+ address holder,
436
+ uint256 projectId,
437
+ uint256 tokenCount,
438
+ string calldata memo
439
+ )
440
+ external
441
+ override
442
+ {
443
+ // Enforce permissions.
444
+ _requirePermissionAllowingOverrideFrom({
445
+ account: holder,
446
+ projectId: projectId,
447
+ permissionId: JBPermissionIds.BURN_TOKENS,
448
+ alsoGrantAccessIf: _isTerminalOf(projectId, _msgSender())
449
+ });
450
+
451
+ // There must be tokens to burn.
452
+ if (tokenCount == 0) revert JBController_ZeroTokensToBurn();
453
+
454
+ emit BurnTokens({
455
+ holder: holder, projectId: projectId, tokenCount: tokenCount, memo: memo, caller: _msgSender()
456
+ });
457
+
458
+ // Burn the tokens.
459
+ TOKENS.burnFrom({holder: holder, projectId: projectId, count: tokenCount});
460
+ }
461
+
462
+ /// @notice Redeem credits to claim tokens into a `beneficiary`'s account.
463
+ /// @dev Can only be called by the credit holder or an address with the holder's permission to `CLAIM_TOKENS`.
464
+ /// @param holder The address to redeem credits from.
465
+ /// @param projectId The ID of the project whose tokens are being claimed.
466
+ /// @param tokenCount The number of tokens to claim.
467
+ /// @param beneficiary The account the claimed tokens will go to.
468
+ function claimTokensFor(
469
+ address holder,
470
+ uint256 projectId,
471
+ uint256 tokenCount,
472
+ address beneficiary
473
+ )
474
+ external
475
+ override
476
+ {
477
+ // Enforce permissions.
478
+ _requirePermissionFrom({account: holder, projectId: projectId, permissionId: JBPermissionIds.CLAIM_TOKENS});
479
+
480
+ TOKENS.claimTokensFor({holder: holder, projectId: projectId, count: tokenCount, beneficiary: beneficiary});
481
+ }
482
+
483
+ /// @notice Deploys an ERC-20 token for a project. It will be used when claiming tokens (with credits).
484
+ /// @dev Deploys the project's ERC-20 contract.
485
+ /// @dev Can only be called by the project's owner or an address with the owner's permission to `DEPLOY_ERC20`.
486
+ /// @param projectId The ID of the project to deploy the ERC-20 for.
487
+ /// @param name The ERC-20's name.
488
+ /// @param symbol The ERC-20's symbol.
489
+ /// @param salt The salt used for ERC-1167 clone deployment. Pass a non-zero salt for deterministic deployment based
490
+ /// on `msg.sender` and the `TOKEN` implementation address.
491
+ /// @return token The address of the token that was deployed.
492
+ function deployERC20For(
493
+ uint256 projectId,
494
+ string calldata name,
495
+ string calldata symbol,
496
+ bytes32 salt
497
+ )
498
+ external
499
+ override
500
+ returns (IJBToken token)
501
+ {
502
+ // Enforce permissions.
503
+ _requirePermissionFrom({
504
+ account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.DEPLOY_ERC20
505
+ });
506
+
507
+ // If a salt is provided, use it.
508
+ bytes32 saltHash = salt != bytes32(0) ? keccak256(abi.encodePacked(_msgSender(), salt)) : bytes32(0);
509
+
510
+ // Emit the event.
511
+ emit DeployERC20({
512
+ projectId: projectId, deployer: _msgSender(), salt: salt, saltHash: saltHash, caller: _msgSender()
513
+ });
514
+
515
+ // Deploy the ERC-20 token with the hashed salt.
516
+ return TOKENS.deployERC20For({projectId: projectId, name: name, symbol: symbol, salt: saltHash});
517
+ }
518
+
519
+ /// @notice When a project receives reserved tokens, if it has a terminal for the token, this is used to pay the
520
+ /// terminal.
521
+ /// @dev Can only be called by this controller.
522
+ /// @param terminal The terminal to pay.
523
+ /// @param projectId The ID of the project being paid.
524
+ /// @param token The token being paid with.
525
+ /// @param splitTokenCount The number of tokens being paid.
526
+ /// @param beneficiary The payment's beneficiary.
527
+ /// @param metadata The pay metadata sent to the terminal.
528
+ function executePayReservedTokenToTerminal(
529
+ IJBTerminal terminal,
530
+ uint256 projectId,
531
+ IJBToken token,
532
+ uint256 splitTokenCount,
533
+ address beneficiary,
534
+ bytes calldata metadata
535
+ )
536
+ external
537
+ {
538
+ // Can only be called by this contract.
539
+ require(msg.sender == address(this));
540
+
541
+ // Approve the tokens being paid.
542
+ IERC20(address(token)).forceApprove(address(terminal), splitTokenCount);
543
+
544
+ // slither-disable-next-line unused-return
545
+ terminal.pay({
546
+ projectId: projectId,
547
+ token: address(token),
548
+ amount: splitTokenCount,
549
+ beneficiary: beneficiary,
550
+ minReturnedTokens: 0,
551
+ memo: "",
552
+ metadata: metadata
553
+ });
554
+
555
+ // Make sure that the terminal received the tokens.
556
+ if (IERC20(address(token)).allowance(address(this), address(terminal)) != 0) {
557
+ revert JBController_TerminalTokensNotTransferred();
558
+ }
559
+ }
560
+
561
+ /// @notice Creates a project.
562
+ /// @dev This will mint the project's ERC-721 to the `owner`'s address, queue the specified rulesets, and set up the
563
+ /// specified splits and terminals. Each operation within this transaction can be done in sequence separately.
564
+ /// @dev Anyone can deploy a project to any `owner`'s address.
565
+ /// @param owner The project's owner. The project ERC-721 will be minted to this address.
566
+ /// @param projectUri The project's metadata URI. This is typically an IPFS hash, optionally with the `ipfs://`
567
+ /// prefix. This can be updated by the project's owner.
568
+ /// @param rulesetConfigurations The rulesets to queue.
569
+ /// @param terminalConfigurations The terminals to set up for the project.
570
+ /// @param memo A memo to pass along to the emitted event.
571
+ /// @return projectId The project's ID.
572
+ function launchProjectFor(
573
+ address owner,
574
+ string calldata projectUri,
575
+ JBRulesetConfig[] calldata rulesetConfigurations,
576
+ JBTerminalConfig[] calldata terminalConfigurations,
577
+ string calldata memo
578
+ )
579
+ external
580
+ override
581
+ returns (uint256 projectId)
582
+ {
583
+ // Mint the project ERC-721 into the owner's wallet.
584
+ // slither-disable-next-line reentrancy-benign
585
+ projectId = PROJECTS.createFor(owner);
586
+
587
+ // If provided, set the project's metadata URI.
588
+ if (bytes(projectUri).length > 0) {
589
+ uriOf[projectId] = projectUri;
590
+ }
591
+
592
+ // Set this contract as the project's controller in the directory.
593
+ DIRECTORY.setControllerOf({projectId: projectId, controller: IERC165(this)});
594
+
595
+ // Configure the terminals.
596
+ _configureTerminals({projectId: projectId, terminalConfigurations: terminalConfigurations});
597
+
598
+ // Queue the rulesets.
599
+ // slither-disable-next-line reentrancy-events
600
+ uint256 rulesetId = _queueRulesets({projectId: projectId, rulesetConfigurations: rulesetConfigurations});
601
+
602
+ emit LaunchProject({
603
+ rulesetId: rulesetId, projectId: projectId, projectUri: projectUri, memo: memo, caller: _msgSender()
604
+ });
605
+ }
606
+
607
+ /// @notice Queue a project's initial rulesets and set up terminals for it. Projects which already have rulesets
608
+ /// should use `queueRulesetsOf(...)`.
609
+ /// @dev Each operation within this transaction can be done in sequence separately.
610
+ /// @dev Can only be called by the project's owner or an address with the owner's permission to `LAUNCH_RULESETS`.
611
+ /// @param projectId The ID of the project to launch rulesets for.
612
+ /// @param rulesetConfigurations The rulesets to queue.
613
+ /// @param terminalConfigurations The terminals to set up.
614
+ /// @param memo A memo to pass along to the emitted event.
615
+ /// @return rulesetId The ID of the last successfully queued ruleset.
616
+ function launchRulesetsFor(
617
+ uint256 projectId,
618
+ JBRulesetConfig[] calldata rulesetConfigurations,
619
+ JBTerminalConfig[] calldata terminalConfigurations,
620
+ string calldata memo
621
+ )
622
+ external
623
+ override
624
+ returns (uint256 rulesetId)
625
+ {
626
+ // Make sure there are rulesets being queued.
627
+ if (rulesetConfigurations.length == 0) revert JBController_RulesetsArrayEmpty();
628
+
629
+ // Keep a reference to the sender.
630
+ address sender = _msgSender();
631
+
632
+ // Enforce permissions.
633
+ _requirePermissionAllowingOverrideFrom({
634
+ account: PROJECTS.ownerOf(projectId),
635
+ projectId: projectId,
636
+ permissionId: JBPermissionIds.LAUNCH_RULESETS,
637
+ alsoGrantAccessIf: sender == OMNICHAIN_RULESET_OPERATOR
638
+ });
639
+
640
+ // Enforce permissions.
641
+ _requirePermissionAllowingOverrideFrom({
642
+ account: PROJECTS.ownerOf(projectId),
643
+ projectId: projectId,
644
+ permissionId: JBPermissionIds.SET_TERMINALS,
645
+ alsoGrantAccessIf: sender == OMNICHAIN_RULESET_OPERATOR
646
+ });
647
+
648
+ // If the project has already had rulesets, use `queueRulesetsOf(...)` instead.
649
+ if (RULESETS.latestRulesetIdOf(projectId) > 0) {
650
+ revert JBController_RulesetsAlreadyLaunched(projectId);
651
+ }
652
+
653
+ // Set this contract as the project's controller in the directory.
654
+ DIRECTORY.setControllerOf({projectId: projectId, controller: IERC165(this)});
655
+
656
+ // Configure the terminals.
657
+ _configureTerminals({projectId: projectId, terminalConfigurations: terminalConfigurations});
658
+
659
+ // Queue the first ruleset.
660
+ // slither-disable-next-line reentrancy-events
661
+ rulesetId = _queueRulesets({projectId: projectId, rulesetConfigurations: rulesetConfigurations});
662
+
663
+ emit LaunchRulesets({rulesetId: rulesetId, projectId: projectId, memo: memo, caller: _msgSender()});
664
+ }
665
+
666
+ /// @notice Migrate a project from this controller to another one.
667
+ /// @dev Can only be called by the directory.
668
+ /// @param projectId The ID of the project to migrate.
669
+ /// @param to The controller to migrate the project to.
670
+ function migrate(uint256 projectId, IERC165 to) external override {
671
+ // Make sure this is being called by the directory.
672
+ if (msg.sender != address(DIRECTORY)) revert JBController_OnlyDirectory(msg.sender, DIRECTORY);
673
+
674
+ emit Migrate({projectId: projectId, to: to, caller: msg.sender});
675
+
676
+ // Get a reference to the project's pending reserved token balance.
677
+ uint256 pendingReservedTokenBalance = pendingReservedTokenBalanceOf[projectId];
678
+
679
+ // Revert if there are pending reserved tokens that should be sent before migrating.
680
+ if (pendingReservedTokenBalance != 0) revert JBController_PendingReservedTokens(pendingReservedTokenBalance);
681
+ }
682
+
683
+ /// @notice Add new project tokens or credits to the specified beneficiary's balance. Optionally, reserve a portion
684
+ /// according to the ruleset's reserved percent.
685
+ /// @dev Can only be called by the project's owner, an address with the owner's permission to `MINT_TOKENS`, one of
686
+ /// the project's terminals, or the project's data hook.
687
+ /// @dev If the ruleset's metadata has `allowOwnerMinting` set to `false`, this function can only be called by the
688
+ /// project's terminals or data hook.
689
+ /// @param projectId The ID of the project whose tokens are being minted.
690
+ /// @param tokenCount The number of tokens to mint, including any reserved tokens.
691
+ /// @param beneficiary The address which will receive the (non-reserved) tokens.
692
+ /// @param memo A memo to pass along to the emitted event.
693
+ /// @param useReservedPercent Whether to apply the ruleset's reserved percent.
694
+ /// @return beneficiaryTokenCount The number of tokens minted for the `beneficiary`.
695
+ function mintTokensOf(
696
+ uint256 projectId,
697
+ uint256 tokenCount,
698
+ address beneficiary,
699
+ string calldata memo,
700
+ bool useReservedPercent
701
+ )
702
+ external
703
+ override
704
+ returns (uint256 beneficiaryTokenCount)
705
+ {
706
+ // There should be tokens to mint.
707
+ if (tokenCount == 0) revert JBController_ZeroTokensToMint();
708
+
709
+ // Keep a reference to the reserved percent.
710
+ uint256 reservedPercent;
711
+
712
+ // Get a reference to the project's ruleset.
713
+ JBRuleset memory ruleset = _currentRulesetOf(projectId);
714
+
715
+ // Minting is restricted to: the project's owner, addresses with permission to `MINT_TOKENS`, the project's
716
+ // terminals, and the project's data hook.
717
+ _requirePermissionAllowingOverrideFrom({
718
+ account: PROJECTS.ownerOf(projectId),
719
+ projectId: projectId,
720
+ permissionId: JBPermissionIds.MINT_TOKENS,
721
+ alsoGrantAccessIf: _isTerminalOf(projectId, _msgSender()) || _msgSender() == ruleset.dataHook()
722
+ || _hasDataHookMintPermissionFor(projectId, ruleset, _msgSender())
723
+ });
724
+
725
+ // If the message sender is not the project's terminal or data hook, the ruleset must have `allowOwnerMinting`
726
+ // set to `true`.
727
+ if (
728
+ ruleset.id != 0 && !ruleset.allowOwnerMinting() && !_isTerminalOf(projectId, _msgSender())
729
+ && _msgSender() != address(ruleset.dataHook())
730
+ && !_hasDataHookMintPermissionFor(projectId, ruleset, _msgSender())
731
+ ) revert JBController_MintNotAllowedAndNotTerminalOrHook(_msgSender());
732
+
733
+ // Determine the reserved percent to use.
734
+ reservedPercent = useReservedPercent ? ruleset.reservedPercent() : 0;
735
+
736
+ if (reservedPercent != JBConstants.MAX_RESERVED_PERCENT) {
737
+ // Calculate the number of (non-reserved) tokens that will be minted to the beneficiary.
738
+ beneficiaryTokenCount = mulDiv(
739
+ tokenCount, JBConstants.MAX_RESERVED_PERCENT - reservedPercent, JBConstants.MAX_RESERVED_PERCENT
740
+ );
741
+
742
+ // Mint the tokens.
743
+ // slither-disable-next-line reentrancy-benign,reentrancy-events,unused-return
744
+ TOKENS.mintFor({holder: beneficiary, projectId: projectId, count: beneficiaryTokenCount});
745
+ }
746
+
747
+ emit MintTokens({
748
+ beneficiary: beneficiary,
749
+ projectId: projectId,
750
+ tokenCount: tokenCount,
751
+ beneficiaryTokenCount: beneficiaryTokenCount,
752
+ memo: memo,
753
+ reservedPercent: reservedPercent,
754
+ caller: _msgSender()
755
+ });
756
+
757
+ // Add any reserved tokens to the pending reserved token balance.
758
+ if (reservedPercent > 0) {
759
+ pendingReservedTokenBalanceOf[projectId] += tokenCount - beneficiaryTokenCount;
760
+ }
761
+ }
762
+
763
+ /// @notice Add one or more rulesets to the end of a project's ruleset queue. Rulesets take effect after the
764
+ /// previous ruleset in the queue ends, and only if they are approved by the previous ruleset's approval hook.
765
+ /// @dev Can only be called by the project's owner or an address with the owner's permission to `QUEUE_RULESETS`.
766
+ /// @param projectId The ID of the project to queue rulesets for.
767
+ /// @param rulesetConfigurations The rulesets to queue.
768
+ /// @param memo A memo to pass along to the emitted event.
769
+ /// @return rulesetId The ID of the last ruleset which was successfully queued.
770
+ function queueRulesetsOf(
771
+ uint256 projectId,
772
+ JBRulesetConfig[] calldata rulesetConfigurations,
773
+ string calldata memo
774
+ )
775
+ external
776
+ override
777
+ returns (uint256 rulesetId)
778
+ {
779
+ // Make sure there are rulesets being queued.
780
+ if (rulesetConfigurations.length == 0) revert JBController_RulesetsArrayEmpty();
781
+
782
+ // Enforce permissions.
783
+ _requirePermissionAllowingOverrideFrom({
784
+ account: PROJECTS.ownerOf(projectId),
785
+ projectId: projectId,
786
+ permissionId: JBPermissionIds.QUEUE_RULESETS,
787
+ alsoGrantAccessIf: _msgSender() == OMNICHAIN_RULESET_OPERATOR
788
+ });
789
+
790
+ // Queue the rulesets.
791
+ // slither-disable-next-line reentrancy-events
792
+ rulesetId = _queueRulesets({projectId: projectId, rulesetConfigurations: rulesetConfigurations});
793
+
794
+ emit QueueRulesets({rulesetId: rulesetId, projectId: projectId, memo: memo, caller: _msgSender()});
795
+ }
796
+
797
+ /// @notice Sends a project's pending reserved tokens to its reserved token splits.
798
+ /// @dev If the project has no reserved token splits, or if they don't add up to 100%, leftover tokens are sent to
799
+ /// the project's owner.
800
+ /// @param projectId The ID of the project to send reserved tokens for.
801
+ /// @return The amount of reserved tokens minted and sent.
802
+ function sendReservedTokensToSplitsOf(uint256 projectId) external override returns (uint256) {
803
+ return _sendReservedTokensToSplitsOf(projectId);
804
+ }
805
+
806
+ /// @notice Sets a project's split groups. The new split groups must include any current splits which are locked.
807
+ /// @dev Can only be called by the project's owner or an address with the owner's permission to `SET_SPLIT_GROUPS`.
808
+ /// @param projectId The ID of the project to set the split groups of.
809
+ /// @param rulesetId The ID of the ruleset the split groups should be active in. Use a `rulesetId` of 0 to set the
810
+ /// default split groups, which are used when a ruleset has no splits set. If there are no default splits and no
811
+ /// splits are set, all splits are sent to the project's owner.
812
+ /// @param splitGroups An array of split groups to set.
813
+ function setSplitGroupsOf(
814
+ uint256 projectId,
815
+ uint256 rulesetId,
816
+ JBSplitGroup[] calldata splitGroups
817
+ )
818
+ external
819
+ override
820
+ {
821
+ // Enforce permissions.
822
+ _requirePermissionFrom({
823
+ account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.SET_SPLIT_GROUPS
824
+ });
825
+
826
+ // Set the split groups.
827
+ SPLITS.setSplitGroupsOf({projectId: projectId, rulesetId: rulesetId, splitGroups: splitGroups});
828
+ }
829
+
830
+ /// @notice Set a project's token. If the project's token is already set, this will revert.
831
+ /// @dev Can only be called by the project's owner or an address with the owner's permission to `SET_TOKEN`.
832
+ /// @param projectId The ID of the project to set the token of.
833
+ /// @param token The new token's address.
834
+ function setTokenFor(uint256 projectId, IJBToken token) external override {
835
+ // Enforce permissions.
836
+ _requirePermissionFrom({
837
+ account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.SET_TOKEN
838
+ });
839
+
840
+ // Get a reference to the current ruleset.
841
+ JBRuleset memory ruleset = _currentRulesetOf(projectId);
842
+
843
+ // If there's no current ruleset, get a reference to the upcoming one.
844
+ if (ruleset.id == 0) ruleset = _upcomingRulesetOf(projectId);
845
+
846
+ // If owner minting is disabled for the ruleset, the owner cannot change the token.
847
+ if (!ruleset.allowSetCustomToken()) revert JBController_RulesetSetTokenNotAllowed(projectId);
848
+
849
+ TOKENS.setTokenFor({projectId: projectId, token: token});
850
+ }
851
+
852
+ /// @notice Set a project's metadata URI.
853
+ /// @dev This is typically an IPFS hash, optionally with an `ipfs://` prefix.
854
+ /// @dev Can only be called by the project's owner or an address with the owner's permission to
855
+ /// `SET_PROJECT_URI`.
856
+ /// @param projectId The ID of the project to set the metadata URI of.
857
+ /// @param uri The metadata URI to set.
858
+ function setUriOf(uint256 projectId, string calldata uri) external override {
859
+ // Enforce permissions.
860
+ _requirePermissionFrom({
861
+ account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.SET_PROJECT_URI
862
+ });
863
+
864
+ // Set the project's metadata URI.
865
+ uriOf[projectId] = uri;
866
+
867
+ emit SetUri({projectId: projectId, uri: uri, caller: _msgSender()});
868
+ }
869
+
870
+ /// @notice Allows a credit holder to transfer credits to another address.
871
+ /// @dev Can only be called by the credit holder or an address with the holder's permission to `TRANSFER_CREDITS`.
872
+ /// @param holder The address to transfer credits from.
873
+ /// @param projectId The ID of the project whose credits are being transferred.
874
+ /// @param recipient The address to transfer credits to.
875
+ /// @param creditCount The number of credits to transfer.
876
+ function transferCreditsFrom(
877
+ address holder,
878
+ uint256 projectId,
879
+ address recipient,
880
+ uint256 creditCount
881
+ )
882
+ external
883
+ override
884
+ {
885
+ // Enforce permissions.
886
+ _requirePermissionFrom({account: holder, projectId: projectId, permissionId: JBPermissionIds.TRANSFER_CREDITS});
887
+
888
+ // Get a reference to the project's ruleset.
889
+ JBRuleset memory ruleset = _currentRulesetOf(projectId);
890
+
891
+ // Credit transfers must not be paused.
892
+ if (ruleset.pauseCreditTransfers()) revert JBController_CreditTransfersPaused();
893
+
894
+ TOKENS.transferCreditsFrom({holder: holder, projectId: projectId, recipient: recipient, count: creditCount});
895
+ }
896
+
897
+ //*********************************************************************//
898
+ // ------------------------ internal functions ----------------------- //
899
+ //*********************************************************************//
900
+
901
+ /// @notice Set up a project's terminals.
902
+ /// @param projectId The ID of the project to set up terminals for.
903
+ /// @param terminalConfigurations The terminals to set up.
904
+ function _configureTerminals(uint256 projectId, JBTerminalConfig[] calldata terminalConfigurations) internal {
905
+ // Initialize an array of terminals to populate.
906
+ IJBTerminal[] memory terminals = new IJBTerminal[](terminalConfigurations.length);
907
+
908
+ for (uint256 i; i < terminalConfigurations.length; i++) {
909
+ // Set the terminal configuration being iterated on.
910
+ JBTerminalConfig memory terminalConfig = terminalConfigurations[i];
911
+
912
+ // Add the accounting contexts for the specified tokens.
913
+ terminalConfig.terminal
914
+ .addAccountingContextsFor({
915
+ projectId: projectId, accountingContexts: terminalConfig.accountingContextsToAccept
916
+ });
917
+
918
+ // Add the terminal.
919
+ terminals[i] = terminalConfig.terminal;
920
+ }
921
+
922
+ // Set the terminals in the directory.
923
+ if (terminalConfigurations.length > 0) {
924
+ DIRECTORY.setTerminalsOf({projectId: projectId, terminals: terminals});
925
+ }
926
+ }
927
+
928
+ /// @notice Queues one or more rulesets and stores information pertinent to the configuration.
929
+ /// @param projectId The ID of the project to queue rulesets for.
930
+ /// @param rulesetConfigurations The rulesets being queued.
931
+ /// @return rulesetId The ID of the last ruleset that was successfully queued.
932
+ function _queueRulesets(
933
+ uint256 projectId,
934
+ JBRulesetConfig[] calldata rulesetConfigurations
935
+ )
936
+ internal
937
+ returns (uint256 rulesetId)
938
+ {
939
+ for (uint256 i; i < rulesetConfigurations.length; i++) {
940
+ // Get a reference to the ruleset config being iterated on.
941
+ JBRulesetConfig memory rulesetConfig = rulesetConfigurations[i];
942
+
943
+ // Make sure its reserved percent is valid.
944
+ if (rulesetConfig.metadata.reservedPercent > JBConstants.MAX_RESERVED_PERCENT) {
945
+ revert JBController_InvalidReservedPercent(
946
+ rulesetConfig.metadata.reservedPercent, JBConstants.MAX_RESERVED_PERCENT
947
+ );
948
+ }
949
+
950
+ // Make sure its cash out tax rate is valid.
951
+ if (rulesetConfig.metadata.cashOutTaxRate > JBConstants.MAX_CASH_OUT_TAX_RATE) {
952
+ revert JBController_InvalidCashOutTaxRate(
953
+ rulesetConfig.metadata.cashOutTaxRate, JBConstants.MAX_CASH_OUT_TAX_RATE
954
+ );
955
+ }
956
+
957
+ // Queue its ruleset.
958
+ JBRuleset memory ruleset = RULESETS.queueFor({
959
+ projectId: projectId,
960
+ duration: rulesetConfig.duration,
961
+ weight: rulesetConfig.weight,
962
+ weightCutPercent: rulesetConfig.weightCutPercent,
963
+ approvalHook: rulesetConfig.approvalHook,
964
+ metadata: JBRulesetMetadataResolver.packRulesetMetadata(rulesetConfig.metadata),
965
+ mustStartAtOrAfter: rulesetConfig.mustStartAtOrAfter
966
+ });
967
+
968
+ // Set its split groups.
969
+ SPLITS.setSplitGroupsOf({
970
+ projectId: projectId, rulesetId: ruleset.id, splitGroups: rulesetConfig.splitGroups
971
+ });
972
+
973
+ // Set its fund access limits.
974
+ FUND_ACCESS_LIMITS.setFundAccessLimitsFor({
975
+ projectId: projectId, rulesetId: ruleset.id, fundAccessLimitGroups: rulesetConfig.fundAccessLimitGroups
976
+ });
977
+
978
+ // If this is the last configuration being queued, return the ruleset's ID.
979
+ if (i == rulesetConfigurations.length - 1) {
980
+ rulesetId = ruleset.id;
981
+ }
982
+ }
983
+ }
984
+
985
+ /// @notice Sends pending reserved tokens to the project's reserved token splits.
986
+ /// @dev If the project has no reserved token splits, or if they don't add up to 100%, leftover tokens are sent to
987
+ /// the project's owner.
988
+ /// @param projectId The ID of the project to send reserved tokens for.
989
+ /// @return tokenCount The amount of reserved tokens minted and sent.
990
+ function _sendReservedTokensToSplitsOf(uint256 projectId) internal returns (uint256 tokenCount) {
991
+ // Get a reference to the number of tokens that need to be minted.
992
+ tokenCount = pendingReservedTokenBalanceOf[projectId];
993
+
994
+ // Revert if there are no pending reserved tokens
995
+ if (tokenCount == 0) revert JBController_NoReservedTokens();
996
+
997
+ // Get the ruleset to read the reserved percent from.
998
+ JBRuleset memory ruleset = _currentRulesetOf(projectId);
999
+
1000
+ // Get a reference to the project's owner.
1001
+ address owner = PROJECTS.ownerOf(projectId);
1002
+
1003
+ // Reset the pending reserved token balance.
1004
+ pendingReservedTokenBalanceOf[projectId] = 0;
1005
+
1006
+ // Mint the tokens to this contract.
1007
+ IJBToken token = TOKENS.mintFor({holder: address(this), projectId: projectId, count: tokenCount});
1008
+
1009
+ // Send reserved tokens to splits and get a reference to the amount left after the splits have all been paid.
1010
+ uint256 leftoverTokenCount = tokenCount == 0
1011
+ ? 0
1012
+ : _sendReservedTokensToSplitGroupOf({
1013
+ projectId: projectId,
1014
+ rulesetId: ruleset.id,
1015
+ groupId: JBSplitGroupIds.RESERVED_TOKENS,
1016
+ tokenCount: tokenCount,
1017
+ token: token
1018
+ });
1019
+
1020
+ // Mint any leftover tokens to the project owner.
1021
+ if (leftoverTokenCount > 0) {
1022
+ _sendTokens({projectId: projectId, tokenCount: leftoverTokenCount, recipient: owner, token: token});
1023
+ }
1024
+
1025
+ emit SendReservedTokensToSplits({
1026
+ rulesetId: ruleset.id,
1027
+ rulesetCycleNumber: ruleset.cycleNumber,
1028
+ projectId: projectId,
1029
+ owner: owner,
1030
+ tokenCount: tokenCount,
1031
+ leftoverAmount: leftoverTokenCount,
1032
+ caller: _msgSender()
1033
+ });
1034
+ }
1035
+
1036
+ /// @notice Send project tokens to a split group.
1037
+ /// @dev This is used to send reserved tokens to the reserved token split group.
1038
+ /// @param projectId The ID of the project the splits belong to.
1039
+ /// @param rulesetId The ID of the split group's ruleset.
1040
+ /// @param groupId The ID of the split group.
1041
+ /// @param tokenCount The number of tokens to send.
1042
+ /// @param token The token to send.
1043
+ /// @return leftoverTokenCount If the split percents don't add up to 100%, the leftover amount is returned.
1044
+ function _sendReservedTokensToSplitGroupOf(
1045
+ uint256 projectId,
1046
+ uint256 rulesetId,
1047
+ uint256 groupId,
1048
+ uint256 tokenCount,
1049
+ IJBToken token
1050
+ )
1051
+ internal
1052
+ returns (uint256 leftoverTokenCount)
1053
+ {
1054
+ // Set the leftover amount to the initial amount.
1055
+ leftoverTokenCount = tokenCount;
1056
+
1057
+ // Get a reference to the split group.
1058
+ JBSplit[] memory splits = SPLITS.splitsOf({projectId: projectId, rulesetId: rulesetId, groupId: groupId});
1059
+
1060
+ // Keep a reference to the number of splits being iterated on.
1061
+ uint256 numberOfSplits = splits.length;
1062
+
1063
+ // Send the tokens to the splits.
1064
+ for (uint256 i; i < numberOfSplits; i++) {
1065
+ // Get a reference to the split being iterated on.
1066
+ JBSplit memory split = splits[i];
1067
+
1068
+ // Calculate the amount to send to the split.
1069
+ uint256 splitTokenCount = mulDiv(tokenCount, split.percent, JBConstants.SPLITS_TOTAL_PERCENT);
1070
+
1071
+ // Mints tokens for the split if needed.
1072
+ if (splitTokenCount > 0) {
1073
+ // 1. If the split has a `hook`, call the hook's `processSplitWith` function.
1074
+ // 2. Otherwise, if the split has a `projectId`, try to pay the project using the split's `beneficiary`,
1075
+ // or the `_msgSender()` if the split has no beneficiary.
1076
+ // 3. Otherwise, if the split has a beneficiary, send the tokens to the split's beneficiary.
1077
+ // 4. Otherwise, send the tokens to the `_msgSender()`.
1078
+
1079
+ // If the split has a hook, call its `processSplitWith` function.
1080
+ if (split.hook != IJBSplitHook(address(0))) {
1081
+ // Send the tokens to the split hook.
1082
+ // slither-disable-next-line reentrancy-events
1083
+ _sendTokens({
1084
+ projectId: projectId, tokenCount: splitTokenCount, recipient: address(split.hook), token: token
1085
+ });
1086
+
1087
+ // slither-disable-next-line reentrancy-events
1088
+ split.hook
1089
+ .processSplitWith(
1090
+ JBSplitHookContext({
1091
+ token: address(token),
1092
+ amount: splitTokenCount,
1093
+ decimals: 18, // Hard-coded in `JBTokens`.
1094
+ projectId: projectId,
1095
+ groupId: groupId,
1096
+ split: split
1097
+ })
1098
+ );
1099
+ // If the split has a project ID, try to pay the project. If that fails, pay the beneficiary.
1100
+ } else {
1101
+ // Pay the project using the split's beneficiary if one was provided. Otherwise, use the message
1102
+ // sender.
1103
+ address beneficiary = split.beneficiary != address(0) ? split.beneficiary : _msgSender();
1104
+
1105
+ if (split.projectId != 0) {
1106
+ // Get a reference to the receiving project's primary payment terminal for the token.
1107
+ IJBTerminal terminal = token == IJBToken(address(0))
1108
+ ? IJBTerminal(address(0))
1109
+ : DIRECTORY.primaryTerminalOf({projectId: split.projectId, token: address(token)});
1110
+
1111
+ // If the project doesn't have a token, or if the receiving project doesn't have a terminal
1112
+ // which accepts the token, send the tokens to the beneficiary.
1113
+ if (address(token) == address(0) || address(terminal) == address(0)) {
1114
+ // Mint the tokens to the beneficiary.
1115
+ // slither-disable-next-line reentrancy-events
1116
+ _sendTokens({
1117
+ projectId: projectId, tokenCount: splitTokenCount, recipient: beneficiary, token: token
1118
+ });
1119
+ } else {
1120
+ // Use the `projectId` in the pay metadata.
1121
+ // slither-disable-next-line reentrancy-events
1122
+ bytes memory metadata = bytes(abi.encodePacked(projectId));
1123
+
1124
+ // Try to fulfill the payment.
1125
+ try this.executePayReservedTokenToTerminal({
1126
+ projectId: split.projectId,
1127
+ terminal: terminal,
1128
+ token: token,
1129
+ splitTokenCount: splitTokenCount,
1130
+ beneficiary: beneficiary,
1131
+ metadata: metadata
1132
+ }) {}
1133
+ catch (bytes memory reason) {
1134
+ emit ReservedDistributionReverted({
1135
+ projectId: projectId,
1136
+ split: split,
1137
+ tokenCount: splitTokenCount,
1138
+ reason: reason,
1139
+ caller: _msgSender()
1140
+ });
1141
+
1142
+ // If it fails, transfer the tokens from this contract to the beneficiary.
1143
+ IERC20(address(token)).safeTransfer(beneficiary, splitTokenCount);
1144
+ }
1145
+ }
1146
+ } else if (beneficiary == address(0xdead)) {
1147
+ // If the split has no project ID, and the beneficiary is 0xdead, burn.
1148
+ TOKENS.burnFrom({holder: address(this), projectId: projectId, count: splitTokenCount});
1149
+ } else {
1150
+ // If the split has no project Id, send to beneficiary.
1151
+ _sendTokens({
1152
+ projectId: projectId, tokenCount: splitTokenCount, recipient: beneficiary, token: token
1153
+ });
1154
+ }
1155
+ }
1156
+
1157
+ // Subtract the amount sent from the leftover.
1158
+ leftoverTokenCount -= splitTokenCount;
1159
+ }
1160
+
1161
+ emit SendReservedTokensToSplit({
1162
+ projectId: projectId,
1163
+ rulesetId: rulesetId,
1164
+ groupId: groupId,
1165
+ split: split,
1166
+ tokenCount: splitTokenCount,
1167
+ caller: _msgSender()
1168
+ });
1169
+ }
1170
+ }
1171
+
1172
+ /// @notice Send tokens from this contract to a recipient.
1173
+ /// @param projectId The ID of the project the tokens belong to.
1174
+ /// @param tokenCount The number of tokens to send.
1175
+ /// @param recipient The address to send the tokens to.
1176
+ /// @param token The token to send, if one exists
1177
+ function _sendTokens(uint256 projectId, uint256 tokenCount, address recipient, IJBToken token) internal {
1178
+ if (token != IJBToken(address(0))) {
1179
+ IERC20(address(token)).safeTransfer({to: recipient, value: tokenCount});
1180
+ } else {
1181
+ TOKENS.transferCreditsFrom({
1182
+ holder: address(this), projectId: projectId, recipient: recipient, count: tokenCount
1183
+ });
1184
+ }
1185
+ }
1186
+ }