@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,93 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import /* {*} from */ "../../../helpers/TestBaseWorkflow.sol";
5
+ import {JBPermissionsSetup} from "./JBPermissionsSetup.sol";
6
+
7
+ contract TestHasPermissions_Local is JBPermissionsSetup {
8
+ address _op = makeAddr("operator");
9
+ address _account = makeAddr("account");
10
+ uint256 _projectId = 1;
11
+ uint256[] _permissionsArray = [256, 256];
12
+
13
+ function setUp() public {
14
+ super.permissionsSetup();
15
+ }
16
+
17
+ function test_WhenAnyPermissionIdGt255() external {
18
+ // it will revert with PERMISSION_ID_OUT_OF_BOUNDS
19
+ vm.expectRevert(abi.encodeWithSelector(JBPermissions.JBPermissions_PermissionIdOutOfBounds.selector, 256));
20
+ _permissions.hasPermissions(_op, _account, _projectId, _permissionsArray, true, true);
21
+ }
22
+
23
+ modifier whenAllPermissionIdsLt255() {
24
+ _permissionsArray = [1, 2, 3];
25
+ _;
26
+ }
27
+
28
+ function test_GivenOperatorDoesNotHaveAllPermissionsSpecified() external whenAllPermissionIdsLt255 {
29
+ // it will return false
30
+ uint256 permissions = 1 << 1;
31
+
32
+ // Find the storage slot
33
+ bytes32 permissionsOfSlot = keccak256(abi.encode(_op, uint256(0)));
34
+ bytes32 accountSlot = keccak256(abi.encode(_account, uint256(permissionsOfSlot)));
35
+ bytes32 slot = keccak256(abi.encode(_projectId, accountSlot));
36
+
37
+ // Set storage
38
+ vm.store(address(_permissions), slot, bytes32(permissions));
39
+
40
+ bool hasAll = _permissions.hasPermissions(_op, _account, _projectId, _permissionsArray, false, true);
41
+ assertEq(hasAll, false);
42
+ }
43
+
44
+ function test_GivenOperatorHasAllPermissionsSpecified() external whenAllPermissionIdsLt255 {
45
+ // it will return true
46
+ uint256 permissions = 1 << 1;
47
+ permissions |= 1 << 2;
48
+ permissions |= 1 << 3;
49
+
50
+ // Find the storage slot
51
+ bytes32 permissionsOfSlot = keccak256(abi.encode(_op, uint256(0)));
52
+ bytes32 accountSlot = keccak256(abi.encode(_account, uint256(permissionsOfSlot)));
53
+ bytes32 slot = keccak256(abi.encode(_projectId, accountSlot));
54
+
55
+ // Set storage
56
+ vm.store(address(_permissions), slot, bytes32(permissions));
57
+
58
+ bool hasAll = _permissions.hasPermissions(_op, _account, _projectId, _permissionsArray, false, false);
59
+ assertEq(hasAll, true);
60
+ }
61
+
62
+ function test_GivenOperatorHasAllPermissionsSpecifiedCounterCase() external whenAllPermissionIdsLt255 {
63
+ // it will return false
64
+ uint256 permissions = 1 << 1;
65
+ permissions |= 1 << 5;
66
+ permissions |= 1 << 7;
67
+
68
+ // Find the storage slot
69
+ bytes32 permissionsOfSlot = keccak256(abi.encode(_op, uint256(0)));
70
+ bytes32 accountSlot = keccak256(abi.encode(_account, uint256(permissionsOfSlot)));
71
+ bytes32 slot = keccak256(abi.encode(_projectId, accountSlot));
72
+
73
+ // Set storage
74
+ vm.store(address(_permissions), slot, bytes32(permissions));
75
+
76
+ bool hasAll = _permissions.hasPermissions(_op, _account, _projectId, _permissionsArray, true, true);
77
+ bool hasAll2 = _permissions.hasPermissions(_op, _account, _projectId, _permissionsArray, false, false);
78
+ bool hasAll3 = _permissions.hasPermissions(_op, _account, _projectId, _permissionsArray, true, false);
79
+ bool hasAll4 = _permissions.hasPermissions(_op, _account, _projectId, _permissionsArray, false, true);
80
+
81
+ // True as it includes root
82
+ assertEq(hasAll, true);
83
+
84
+ // Does not include root
85
+ assertEq(hasAll2, false);
86
+
87
+ // True as it includes root
88
+ assertEq(hasAll3, true);
89
+
90
+ // Does not include root
91
+ assertEq(hasAll4, false);
92
+ }
93
+ }
@@ -0,0 +1,62 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import /* {*} from */ "../../../helpers/TestBaseWorkflow.sol";
5
+ import {JBPermissionsSetup} from "./JBPermissionsSetup.sol";
6
+
7
+ contract TestSetPermissionsFor_Local is JBPermissionsSetup {
8
+ address _op = makeAddr("operator");
9
+ address _account = makeAddr("account");
10
+ uint64 _projectId = 1;
11
+
12
+ function setUp() public {
13
+ super.permissionsSetup();
14
+ }
15
+
16
+ function test_WhenCallerDoesNotHavePermission() external {
17
+ // it will revert UNAUTHORIZED
18
+ JBPermissionsData memory emptyData;
19
+
20
+ vm.expectRevert(
21
+ abi.encodeWithSelector(
22
+ JBPermissions.JBPermissions_Unauthorized.selector, _account, address(this), 0, JBPermissionIds.ROOT
23
+ )
24
+ );
25
+ _permissions.setPermissionsFor(_account, emptyData);
26
+ }
27
+
28
+ function test_WhenCallerHasPermission() external {
29
+ // it packs permissions into a bitfield, stores them, and emits OperatorPermissionsSet
30
+
31
+ // used to set our root privelage and act as our counter case later
32
+ uint256 permissions = 1 << 1;
33
+
34
+ // Find the storage slot
35
+ bytes32 permissionsOfSlot = keccak256(abi.encode(_op, uint256(0)));
36
+ bytes32 accountSlot = keccak256(abi.encode(_account, uint256(permissionsOfSlot)));
37
+ bytes32 slot = keccak256(abi.encode(_projectId, accountSlot));
38
+
39
+ // Set storage: this contract can set permissions as ROOT
40
+ vm.store(address(_permissions), slot, bytes32(permissions));
41
+
42
+ uint8[] memory array = new uint8[](3);
43
+ array[0] = 1;
44
+ array[1] = 2;
45
+ array[2] = 3;
46
+
47
+ JBPermissionsData memory data = JBPermissionsData({operator: _op, projectId: _projectId, permissionIds: array});
48
+
49
+ // call it
50
+ vm.prank(_account);
51
+ _permissions.setPermissionsFor(_account, data);
52
+
53
+ // permissions that were set during the call
54
+ uint256 afterSet = _permissions.permissionsOf(_op, _account, _projectId);
55
+
56
+ // add missing permissions to our counter case "permissions" which we used to assign root access earlier
57
+ permissions |= 1 << 2;
58
+ permissions |= 1 << 3;
59
+
60
+ assertEq(afterSet, permissions);
61
+ }
62
+ }
@@ -0,0 +1,26 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import /* {*} from */ "../../../helpers/TestBaseWorkflow.sol";
5
+
6
+ /*
7
+ Contract that deploys a target contract with other mock contracts to satisfy the constructor.
8
+ Tests relative to this contract will be dependent on mock calls/emits and stdStorage.
9
+ */
10
+ contract JBPricesSetup is JBTest {
11
+ address _owner = makeAddr("owner");
12
+
13
+ // Mocks
14
+ IJBPermissions public permissions = IJBPermissions(makeAddr("permissions"));
15
+ IJBProjects public projects = IJBProjects(makeAddr("projects"));
16
+ IJBDirectory public directory = IJBDirectory(makeAddr("directory"));
17
+ IJBRulesets public rulesets = IJBRulesets(makeAddr("rulesets"));
18
+
19
+ // Target Contract
20
+ IJBPrices public _prices;
21
+
22
+ function pricesSetup() public virtual {
23
+ // Instantiate the contract being tested
24
+ _prices = new JBPrices(directory, permissions, projects, _owner, address(0));
25
+ }
26
+ }
@@ -0,0 +1,102 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import /* {*} from */ "../../../helpers/TestBaseWorkflow.sol";
5
+ import {JBPricesSetup} from "./JBPricesSetup.sol";
6
+
7
+ contract TestAddPriceFeedFor_Local is JBPricesSetup {
8
+ IJBPriceFeed _feed = IJBPriceFeed(makeAddr("feed"));
9
+ uint256 DEFAULT_PROJECT_ID = 0;
10
+ uint256 _projectId = 1;
11
+ address _projectOneOwner = makeAddr("oneOwner");
12
+ uint256 _pricingCurrency = uint32(uint160(JBConstants.NATIVE_TOKEN));
13
+ uint256 _unitCurrency = uint32(uint160(makeAddr("someToken")));
14
+ uint256 _invalidCurrency = 0;
15
+
16
+ function setUp() public {
17
+ super.pricesSetup();
18
+ }
19
+
20
+ function test_WhenProjectIdIsTheDEFAULT_PROJECT_IDAndMsgSenderIsTheOwnerOfJBPrices() external {
21
+ // it should add the price feed without checking permissions
22
+
23
+ vm.prank(_owner);
24
+ _prices.addPriceFeedFor(DEFAULT_PROJECT_ID, _pricingCurrency, _unitCurrency, _feed);
25
+ }
26
+
27
+ function test_WhenProjectIdIsTheDEFAULT_PROJECT_IDAndMsgSenderIsTheOwnerOfProjectZero() external {
28
+ // it should add the price feed
29
+ vm.prank(_owner);
30
+ _prices.addPriceFeedFor(DEFAULT_PROJECT_ID, _pricingCurrency, _unitCurrency, _feed);
31
+ }
32
+
33
+ function test_WhenProjectIdIsTheDEFAULT_PROJECT_IDAndMsgSenderIsNotTheOwnerOfProjectZero() external {
34
+ // it should revert ONLY_OWNER()
35
+
36
+ // encode custom error
37
+ bytes4 selector = bytes4(keccak256("OwnableUnauthorizedAccount(address)"));
38
+ bytes memory expectedError = abi.encodeWithSelector(selector, address(this));
39
+
40
+ vm.expectRevert(expectedError);
41
+ _prices.addPriceFeedFor(DEFAULT_PROJECT_ID, _pricingCurrency, _unitCurrency, _feed);
42
+ }
43
+
44
+ modifier whenProjectIsNotDefaultAndHasPermissions() {
45
+ // mock controllerOf call
46
+ mockExpect(
47
+ address(directory), abi.encodeCall(IJBDirectory.controllerOf, (_projectId)), abi.encode(address(this))
48
+ );
49
+ _;
50
+ }
51
+
52
+ function test_WhenProjectIdIsNotTheDEFAULT_PROJECT_ID() external whenProjectIsNotDefaultAndHasPermissions {
53
+ // it should require ADD_PRICE_FEED permission from the project's owner or an operator
54
+
55
+ _prices.addPriceFeedFor(_projectId, _pricingCurrency, _unitCurrency, _feed);
56
+ }
57
+
58
+ function test_WhenPricingCurrencyOrUnitCurrencyIs0() external whenProjectIsNotDefaultAndHasPermissions {
59
+ // it should revert with INVALID_CURRENCY
60
+
61
+ vm.expectRevert(JBPrices.JBPrices_ZeroPricingCurrency.selector);
62
+ _prices.addPriceFeedFor(_projectId, _invalidCurrency, _unitCurrency, _feed);
63
+
64
+ vm.expectRevert(JBPrices.JBPrices_ZeroUnitCurrency.selector);
65
+ _prices.addPriceFeedFor(_projectId, _pricingCurrency, _invalidCurrency, _feed);
66
+ }
67
+
68
+ function test_WhenADefaultFeedForTheCurrencyPairOrItsInverseAlreadyExists()
69
+ external
70
+ whenProjectIsNotDefaultAndHasPermissions
71
+ {
72
+ // it should revert with PRICE_FEED_ALREADY_EXISTS
73
+
74
+ vm.prank(_owner);
75
+ _prices.addPriceFeedFor(DEFAULT_PROJECT_ID, _pricingCurrency, _unitCurrency, _feed);
76
+
77
+ vm.expectRevert(abi.encodeWithSelector(JBPrices.JBPrices_PriceFeedAlreadyExists.selector, _feed));
78
+ _prices.addPriceFeedFor(_projectId, _pricingCurrency, _unitCurrency, _feed);
79
+ }
80
+
81
+ function test_WhenThisProjectAlreadyHasFeedsForTheCurrencyPairOrItsInverse()
82
+ external
83
+ whenProjectIsNotDefaultAndHasPermissions
84
+ {
85
+ // it should revert with PRICE_FEED_ALREADY_EXISTS
86
+
87
+ _prices.addPriceFeedFor(_projectId, _pricingCurrency, _unitCurrency, _feed);
88
+
89
+ vm.expectRevert(abi.encodeWithSelector(JBPrices.JBPrices_PriceFeedAlreadyExists.selector, _feed));
90
+ _prices.addPriceFeedFor(_projectId, _pricingCurrency, _unitCurrency, _feed);
91
+ }
92
+
93
+ function test_HappyPath() external whenProjectIsNotDefaultAndHasPermissions {
94
+ // it should store the feed for the project and currency pair
95
+ // it should emit AddPriceFeed event with projectId, pricingCurrency, unitCurrency, and feed
96
+
97
+ vm.expectEmit();
98
+ emit IJBPrices.AddPriceFeed(_projectId, _pricingCurrency, _unitCurrency, _feed, address(this));
99
+
100
+ _prices.addPriceFeedFor(_projectId, _pricingCurrency, _unitCurrency, _feed);
101
+ }
102
+ }
@@ -0,0 +1,129 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import /* {*} from */ "../../../helpers/TestBaseWorkflow.sol";
5
+ import {JBPricesSetup} from "./JBPricesSetup.sol";
6
+
7
+ contract TestPricePerUnitOf_Local is JBPricesSetup {
8
+ IJBPriceFeed _feed = IJBPriceFeed(makeAddr("priceFeed"));
9
+ uint256 DEFAULT_PROJECT_ID = 0;
10
+ uint256 _projectId = 1;
11
+ uint256 _defaultDirectPrice = 1_000_000_000;
12
+ uint256 _directPrice = 2_000_000_000;
13
+ uint256 _inversePrice = 1e18;
14
+ uint256 _directDecimals = 18;
15
+ uint256 _inverseDecimals = 6;
16
+ uint256 _pricingCurrency = uint32(uint160(JBConstants.NATIVE_TOKEN));
17
+ uint256 _unitCurrency = uint32(uint160(makeAddr("someToken")));
18
+
19
+ function setUp() public {
20
+ super.pricesSetup();
21
+ }
22
+
23
+ modifier givenDirectFeedExists() {
24
+ // Find the storage slot
25
+ bytes32 priceFeedForSlot = keccak256(abi.encode(_projectId, uint256(1)));
26
+ bytes32 pricingSlot = keccak256(abi.encode(_pricingCurrency, uint256(priceFeedForSlot)));
27
+ bytes32 slot = keccak256(abi.encode(_unitCurrency, uint256(pricingSlot)));
28
+
29
+ bytes32 feedBytes = bytes32(uint256(uint160(address(_feed))));
30
+
31
+ // Set direct price feed
32
+ vm.store(address(_prices), slot, feedBytes);
33
+
34
+ // Confirm price feed was set
35
+ IJBPriceFeed feed = _prices.priceFeedFor(_projectId, _pricingCurrency, _unitCurrency);
36
+ assertEq(address(feed), address(_feed));
37
+
38
+ bytes memory currentUnitPriceCall = abi.encodeCall(IJBPriceFeed.currentUnitPrice, (_inverseDecimals));
39
+ bytes memory directReturned = abi.encode(_directPrice);
40
+
41
+ mockExpect(address(feed), currentUnitPriceCall, directReturned);
42
+ _;
43
+ }
44
+
45
+ modifier givenIndirectFeedExists() {
46
+ // Find the storage slot
47
+ bytes32 priceFeedForSlot = keccak256(abi.encode(_projectId, uint256(1)));
48
+ bytes32 pricingSlot = keccak256(abi.encode(_unitCurrency, uint256(priceFeedForSlot)));
49
+ bytes32 slot = keccak256(abi.encode(_pricingCurrency, uint256(pricingSlot)));
50
+
51
+ bytes32 feedBytes = bytes32(uint256(uint160(address(_feed))));
52
+
53
+ // Set indirect price feed
54
+ vm.store(address(_prices), slot, feedBytes);
55
+
56
+ // Confirm price feed was set
57
+ IJBPriceFeed feed = _prices.priceFeedFor(_projectId, _unitCurrency, _pricingCurrency);
58
+ assertEq(address(feed), address(_feed));
59
+
60
+ bytes memory currentUnitPriceCall = abi.encodeCall(IJBPriceFeed.currentUnitPrice, (_directDecimals));
61
+ bytes memory directReturned = abi.encode(_inversePrice);
62
+
63
+ mockExpect(address(feed), currentUnitPriceCall, directReturned);
64
+ _;
65
+ }
66
+
67
+ modifier givenOnlyDefaultDirectFeedExists() {
68
+ // Find the storage slot
69
+ bytes32 priceFeedForSlot = keccak256(abi.encode(DEFAULT_PROJECT_ID, uint256(1)));
70
+ bytes32 pricingSlot = keccak256(abi.encode(_pricingCurrency, uint256(priceFeedForSlot)));
71
+ bytes32 slot = keccak256(abi.encode(_unitCurrency, uint256(pricingSlot)));
72
+
73
+ bytes32 feedBytes = bytes32(uint256(uint160(address(_feed))));
74
+
75
+ // Set direct price feed
76
+ vm.store(address(_prices), slot, feedBytes);
77
+
78
+ // Confirm price feed was set
79
+ IJBPriceFeed feed = _prices.priceFeedFor(DEFAULT_PROJECT_ID, _pricingCurrency, _unitCurrency);
80
+ assertEq(address(feed), address(_feed));
81
+
82
+ bytes memory currentUnitPriceCall = abi.encodeCall(IJBPriceFeed.currentUnitPrice, (_inverseDecimals));
83
+ bytes memory directReturned = abi.encode(_defaultDirectPrice);
84
+
85
+ mockExpect(address(feed), currentUnitPriceCall, directReturned);
86
+ _;
87
+ }
88
+
89
+ function test_WhenPricingCurrencyIsTheSameAsUnitCurrency() external view {
90
+ // it should return 1 with requested decimals
91
+
92
+ uint256 price = _prices.pricePerUnitOf(_projectId, _pricingCurrency, _pricingCurrency, 18);
93
+ assertEq(price, 1e18);
94
+ }
95
+
96
+ function test_WhenPriceFeedExistsForProjectIdAndPricingCurrencyToUnitCurrency() external givenDirectFeedExists {
97
+ // it should return the current price from price feed
98
+
99
+ uint256 pricesPrice = _prices.pricePerUnitOf(_projectId, _pricingCurrency, _unitCurrency, 6);
100
+ assertEq(pricesPrice, _directPrice);
101
+ }
102
+
103
+ function test_WhenInversePriceFeedExistsForProjectIdAndUnitCurrencyToPricingCurrency()
104
+ external
105
+ givenIndirectFeedExists
106
+ {
107
+ // it should return the inverse of the current price from inverse price feed
108
+
109
+ uint256 inversePrice = _prices.pricePerUnitOf(_projectId, _pricingCurrency, _unitCurrency, 18);
110
+ assertEq(inversePrice, _inversePrice);
111
+ }
112
+
113
+ function test_WhenProjectIdIsNotTheDEFAULT_PROJECT_IDAndNoDirectOrInversePriceFeedIsFound()
114
+ external
115
+ givenOnlyDefaultDirectFeedExists
116
+ {
117
+ // it should attempt to use the default price feed for DEFAULT_PROJECT_ID
118
+
119
+ uint256 defaultPrice = _prices.pricePerUnitOf(_projectId, _pricingCurrency, _unitCurrency, 6);
120
+ assertEq(defaultPrice, _defaultDirectPrice);
121
+ }
122
+
123
+ function test_WhenNoPriceFeedIsFoundOrExistsIncludingDefaultCase() external {
124
+ // it should revert with PRICE_FEED_NOT_FOUND
125
+
126
+ vm.expectRevert(JBPrices.JBPrices_PriceFeedNotFound.selector);
127
+ _prices.pricePerUnitOf(_projectId, _pricingCurrency, _unitCurrency, 6);
128
+ }
129
+ }
@@ -0,0 +1,262 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ import /* {*} from */ "../../../helpers/TestBaseWorkflow.sol";
5
+ import {JBPricesSetup} from "./JBPricesSetup.sol";
6
+ import {MockPriceFeed} from "../../../mock/MockPriceFeed.sol";
7
+
8
+ /// @notice Edge case & bug-hunting tests for JBPrices.
9
+ /// Covers inverse precision, feed immutability, default fallback, and the overly-restrictive
10
+ /// default-blocks-project-specific issue.
11
+ contract TestPrices_Local is JBPricesSetup {
12
+ uint256 constant DEFAULT_PROJECT_ID = 0;
13
+ uint256 constant PROJECT_ID = 1;
14
+ uint256 _pricingCurrency = uint32(uint160(JBConstants.NATIVE_TOKEN));
15
+ uint256 _unitCurrency = uint32(uint160(makeAddr("unitToken")));
16
+
17
+ function setUp() public {
18
+ super.pricesSetup();
19
+ }
20
+
21
+ // ───────────────────── Helpers
22
+ // ─────────────────────
23
+
24
+ /// @dev Sets a mock price feed directly into storage for a given project.
25
+ function _storeFeed(uint256 projectId, uint256 pricing, uint256 unit_, address feed) internal {
26
+ bytes32 slot0 = keccak256(abi.encode(projectId, uint256(1)));
27
+ bytes32 slot1 = keccak256(abi.encode(pricing, uint256(slot0)));
28
+ bytes32 slot2 = keccak256(abi.encode(unit_, uint256(slot1)));
29
+ vm.store(address(_prices), slot2, bytes32(uint256(uint160(feed))));
30
+ }
31
+
32
+ // ───────────────────── Inverse precision tests
33
+ // ─────────────────────
34
+
35
+ /// @notice Feed returns 1 (minimum non-zero price). Inverse should be 10^(2*decimals).
36
+ function test_inversePrecision_smallPrice() external {
37
+ uint256 decimals = 18;
38
+ MockPriceFeed feed = new MockPriceFeed(1, decimals);
39
+ _storeFeed(PROJECT_ID, _unitCurrency, _pricingCurrency, address(feed));
40
+
41
+ // Query the inverse direction: pricing → unit requires inverting the unit→pricing feed.
42
+ uint256 inverse = _prices.pricePerUnitOf(PROJECT_ID, _pricingCurrency, _unitCurrency, decimals);
43
+ // inverse = 10^18 * 10^18 / 1 = 10^36, but mulDiv(10^18, 10^18, 1) = 10^36
44
+ // Wait: the formula is mulDiv(10^decimals, 10^decimals, feedPrice) = mulDiv(10^18, 10^18, 1)
45
+ assertEq(inverse, 10 ** (2 * decimals), "Inverse of price=1 should be 10^(2*decimals)");
46
+ }
47
+
48
+ /// @notice Feed returns near-max value. Inverse should not underflow to 0.
49
+ function test_inversePrecision_largePrice() external {
50
+ uint256 decimals = 18;
51
+ // Price is 10^36 (very large).
52
+ // Inverse = mulDiv(10^18, 10^18, 10^36) = 10^36 / 10^36 = 1
53
+ MockPriceFeed feed = new MockPriceFeed(10 ** 36, 18);
54
+ _storeFeed(PROJECT_ID, _unitCurrency, _pricingCurrency, address(feed));
55
+
56
+ uint256 inverse = _prices.pricePerUnitOf(PROJECT_ID, _pricingCurrency, _unitCurrency, decimals);
57
+ assertEq(inverse, 1, "Inverse of very large price should be 1 (floor)");
58
+ }
59
+
60
+ /// @notice Fuzz: price(A->B) * price(B->A) should approximate 10^(2*decimals).
61
+ /// Bounded to realistic price range where precision is expected to hold.
62
+ function testFuzz_inversePrecision_roundTrip(uint256 price) external {
63
+ uint256 decimals = 18;
64
+ // Bound price to [10^9, 10^27] — realistic range where inverse precision is reasonable.
65
+ // Outside this range, integer division precision loss is severe (see test below).
66
+ price = bound(price, 10 ** 9, 10 ** 27);
67
+
68
+ MockPriceFeed feed = new MockPriceFeed(price, decimals);
69
+
70
+ // Store feed as direct A->B feed.
71
+ _storeFeed(PROJECT_ID, _pricingCurrency, _unitCurrency, address(feed));
72
+
73
+ // Get direct price.
74
+ uint256 direct = _prices.pricePerUnitOf(PROJECT_ID, _pricingCurrency, _unitCurrency, decimals);
75
+ assertEq(direct, price, "Direct price should match feed");
76
+
77
+ // Get inverse price (B->A).
78
+ uint256 inverse = _prices.pricePerUnitOf(PROJECT_ID, _unitCurrency, _pricingCurrency, decimals);
79
+
80
+ // Round-trip: direct * inverse should approximate 10^decimals.
81
+ uint256 product = mulDiv(direct, inverse, 10 ** decimals);
82
+ assertApproxEqRel(product, 10 ** decimals, 0.01e18, "Round-trip should approximate 10^decimals");
83
+ }
84
+
85
+ /// @notice PRECISION BUG: At extreme prices (>10^27), inverse precision degrades severely.
86
+ /// For non-power-of-10 prices, round-trip error can exceed 10%.
87
+ function test_inversePrecision_degradesAtExtremes() external {
88
+ uint256 decimals = 18;
89
+ // Price of 3*10^35 — inverse = mulDiv(10^18, 10^18, 3*10^35) = floor(3.33) = 3
90
+ MockPriceFeed feed = new MockPriceFeed(3 * 10 ** 35, decimals);
91
+ _storeFeed(PROJECT_ID, _unitCurrency, _pricingCurrency, address(feed));
92
+
93
+ uint256 inverse = _prices.pricePerUnitOf(PROJECT_ID, _pricingCurrency, _unitCurrency, decimals);
94
+ // Inverse only has 1 significant digit — massive precision loss.
95
+ assertEq(inverse, 3, "Extreme price inverse has only 1 digit of precision");
96
+
97
+ // Round-trip: 3*10^35 * 3 / 10^18 = 9*10^17 (should be 10^18). 10% error.
98
+ uint256 product = mulDiv(3 * 10 ** 35, inverse, 10 ** decimals);
99
+ assertEq(product, 9 * 10 ** 17, "Round-trip at extreme prices loses 10% precision");
100
+ }
101
+
102
+ /// @notice inverse(inverse(price)) should approximately equal price (precision loss compounds).
103
+ function test_inversePrecision_asymmetry() external {
104
+ uint256 decimals = 18;
105
+ uint256 originalPrice = 3333 * 10 ** 14; // 0.3333 ETH (a price that doesn't divide evenly)
106
+
107
+ // Store A->B feed.
108
+ MockPriceFeed feed = new MockPriceFeed(originalPrice, decimals);
109
+ _storeFeed(PROJECT_ID, _pricingCurrency, _unitCurrency, address(feed));
110
+
111
+ // Get inverse (B->A).
112
+ uint256 inversePrice = _prices.pricePerUnitOf(PROJECT_ID, _unitCurrency, _pricingCurrency, decimals);
113
+
114
+ // Now set a NEW feed for B->A with the inverse price, and query A->B back via inversion.
115
+ // We need a different project to avoid the "already exists" check.
116
+ uint256 project2 = 2;
117
+ MockPriceFeed feed2 = new MockPriceFeed(inversePrice, decimals);
118
+ _storeFeed(project2, _unitCurrency, _pricingCurrency, address(feed2));
119
+
120
+ uint256 doubleInverse = _prices.pricePerUnitOf(project2, _pricingCurrency, _unitCurrency, decimals);
121
+
122
+ // Double-inverse should be approximately equal to original, but may lose precision.
123
+ // This documents the precision loss from compounding inversions.
124
+ assertApproxEqRel(doubleInverse, originalPrice, 0.01e18, "Double inverse should approximate original within 1%");
125
+ }
126
+
127
+ // ───────────────────── Feed immutability tests
128
+ // ─────────────────────
129
+
130
+ /// @notice Adding a feed for an existing pair should revert.
131
+ function test_feedImmutability_cannotReplace() external {
132
+ MockPriceFeed feed1 = new MockPriceFeed(1000e18, 18);
133
+ MockPriceFeed feed2 = new MockPriceFeed(2000e18, 18);
134
+
135
+ // Mock controller for project.
136
+ vm.mockCall(
137
+ address(directory), abi.encodeCall(IJBDirectory.controllerOf, (PROJECT_ID)), abi.encode(address(this))
138
+ );
139
+
140
+ _prices.addPriceFeedFor(PROJECT_ID, _pricingCurrency, _unitCurrency, feed1);
141
+
142
+ // Second add for same pair should revert.
143
+ vm.expectRevert(abi.encodeWithSelector(JBPrices.JBPrices_PriceFeedAlreadyExists.selector, feed1));
144
+ _prices.addPriceFeedFor(PROJECT_ID, _pricingCurrency, _unitCurrency, feed2);
145
+ }
146
+
147
+ /// @notice Adding A->B should block adding B->A for the same project.
148
+ function test_feedImmutability_inverseBlocksToo() external {
149
+ MockPriceFeed feed1 = new MockPriceFeed(1000e18, 18);
150
+ MockPriceFeed feed2 = new MockPriceFeed(2000e18, 18);
151
+
152
+ vm.mockCall(
153
+ address(directory), abi.encodeCall(IJBDirectory.controllerOf, (PROJECT_ID)), abi.encode(address(this))
154
+ );
155
+
156
+ _prices.addPriceFeedFor(PROJECT_ID, _pricingCurrency, _unitCurrency, feed1);
157
+
158
+ // Adding inverse pair should revert.
159
+ vm.expectRevert(abi.encodeWithSelector(JBPrices.JBPrices_PriceFeedAlreadyExists.selector, feed1));
160
+ _prices.addPriceFeedFor(PROJECT_ID, _unitCurrency, _pricingCurrency, feed2);
161
+ }
162
+
163
+ // ───────────────────── Default fallback tests
164
+ // ─────────────────────
165
+
166
+ /// @notice Project-specific feed takes priority over default.
167
+ function test_defaultFallback_projectFeedTakesPriority() external {
168
+ MockPriceFeed defaultFeed = new MockPriceFeed(1000e18, 18);
169
+ MockPriceFeed projectFeed = new MockPriceFeed(2000e18, 18);
170
+
171
+ // Store default feed.
172
+ _storeFeed(DEFAULT_PROJECT_ID, _pricingCurrency, _unitCurrency, address(defaultFeed));
173
+ // Store project feed.
174
+ _storeFeed(PROJECT_ID, _pricingCurrency, _unitCurrency, address(projectFeed));
175
+
176
+ uint256 price = _prices.pricePerUnitOf(PROJECT_ID, _pricingCurrency, _unitCurrency, 18);
177
+ assertEq(price, 2000e18, "Project feed should take priority over default");
178
+ }
179
+
180
+ /// @notice Default inverse feed used when no project-specific direct or inverse feed exists.
181
+ function test_defaultFallback_inverseOfDefault() external {
182
+ uint256 decimals = 18;
183
+ // Only store default feed in the inverse direction: unit->pricing.
184
+ MockPriceFeed defaultFeed = new MockPriceFeed(2e18, decimals);
185
+ _storeFeed(DEFAULT_PROJECT_ID, _unitCurrency, _pricingCurrency, address(defaultFeed));
186
+
187
+ // Query pricing->unit on a project with no feeds — should fall back to default inverse.
188
+ uint256 price = _prices.pricePerUnitOf(PROJECT_ID, _pricingCurrency, _unitCurrency, decimals);
189
+
190
+ // Expected: mulDiv(10^18, 10^18, 2*10^18) = 5*10^17
191
+ assertEq(price, 5e17, "Should use inverse of default feed");
192
+ }
193
+
194
+ // ───────────────────── Same currency
195
+ // ─────────────────────
196
+
197
+ /// @notice pricePerUnitOf(X, X, decimals) == 10^decimals.
198
+ function test_sameCurrency_returns1() external view {
199
+ uint256 price18 = _prices.pricePerUnitOf(PROJECT_ID, _pricingCurrency, _pricingCurrency, 18);
200
+ assertEq(price18, 1e18, "Same currency at 18 decimals should return 1e18");
201
+
202
+ uint256 price6 = _prices.pricePerUnitOf(PROJECT_ID, _pricingCurrency, _pricingCurrency, 6);
203
+ assertEq(price6, 1e6, "Same currency at 6 decimals should return 1e6");
204
+ }
205
+
206
+ // ───────────────────── Zero currency reverts
207
+ // ─────────────────────
208
+
209
+ /// @notice Both zero pricing and zero unit currency should revert on addPriceFeedFor.
210
+ function test_zeroCurrency_reverts() external {
211
+ MockPriceFeed feed = new MockPriceFeed(1000e18, 18);
212
+
213
+ vm.prank(_owner);
214
+ vm.expectRevert(JBPrices.JBPrices_ZeroPricingCurrency.selector);
215
+ _prices.addPriceFeedFor(DEFAULT_PROJECT_ID, 0, _unitCurrency, feed);
216
+
217
+ vm.prank(_owner);
218
+ vm.expectRevert(JBPrices.JBPrices_ZeroUnitCurrency.selector);
219
+ _prices.addPriceFeedFor(DEFAULT_PROJECT_ID, _pricingCurrency, 0, feed);
220
+ }
221
+
222
+ // ───────────────────── BUG HYPOTHESIS: default blocks project-specific
223
+ // ─────────────────────
224
+
225
+ /// @notice BUG: Adding a default A->B feed blocks ANY project from adding their own A->B feed.
226
+ /// This is overly restrictive — projects cannot use a different oracle for the same pair.
227
+ /// The check at JBPrices.sol:188-197 checks default feeds BEFORE project feeds.
228
+ function test_addFeedFor_defaultBlocksProjectSpecific() external {
229
+ MockPriceFeed defaultFeed = new MockPriceFeed(1000e18, 18);
230
+ MockPriceFeed projectFeed = new MockPriceFeed(2000e18, 18);
231
+
232
+ // Add default feed.
233
+ vm.prank(_owner);
234
+ _prices.addPriceFeedFor(DEFAULT_PROJECT_ID, _pricingCurrency, _unitCurrency, defaultFeed);
235
+
236
+ // Now try to add a project-specific feed for the SAME pair.
237
+ vm.mockCall(
238
+ address(directory), abi.encodeCall(IJBDirectory.controllerOf, (PROJECT_ID)), abi.encode(address(this))
239
+ );
240
+
241
+ // BUG CONFIRMED: This reverts because default feed blocks project-specific feeds.
242
+ vm.expectRevert(abi.encodeWithSelector(JBPrices.JBPrices_PriceFeedAlreadyExists.selector, defaultFeed));
243
+ _prices.addPriceFeedFor(PROJECT_ID, _pricingCurrency, _unitCurrency, projectFeed);
244
+ }
245
+
246
+ // ───────────────────── Fuzz: valid feeds never overflow
247
+ // ─────────────────────
248
+
249
+ /// @notice Fuzz: pricePerUnitOf should never revert for valid feed values.
250
+ function testFuzz_pricePerUnitOf_neverReverts_forValidFeed(uint256 price, uint8 decimals) external {
251
+ // Bound inputs to reasonable ranges.
252
+ decimals = uint8(bound(decimals, 1, 18));
253
+ price = bound(price, 1, type(uint128).max);
254
+
255
+ MockPriceFeed feed = new MockPriceFeed(price, decimals);
256
+ _storeFeed(PROJECT_ID, _pricingCurrency, _unitCurrency, address(feed));
257
+
258
+ // Should not revert.
259
+ uint256 result = _prices.pricePerUnitOf(PROJECT_ID, _pricingCurrency, _unitCurrency, decimals);
260
+ assertGt(result, 0, "Price should be non-zero for valid feed");
261
+ }
262
+ }