@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.
- package/LICENSE +21 -0
- package/README.md +112 -0
- package/SKILLS.md +151 -0
- package/docs/book.css +13 -0
- package/docs/book.toml +12 -0
- package/docs/solidity.min.js +74 -0
- package/docs/src/README.md +703 -0
- package/docs/src/SUMMARY.md +94 -0
- package/docs/src/src/JBChainlinkV3PriceFeed.sol/contract.JBChainlinkV3PriceFeed.md +83 -0
- package/docs/src/src/JBChainlinkV3SequencerPriceFeed.sol/contract.JBChainlinkV3SequencerPriceFeed.md +88 -0
- package/docs/src/src/JBController.sol/contract.JBController.md +1121 -0
- package/docs/src/src/JBDeadline.sol/contract.JBDeadline.md +84 -0
- package/docs/src/src/JBDirectory.sol/contract.JBDirectory.md +294 -0
- package/docs/src/src/JBERC20.sol/contract.JBERC20.md +190 -0
- package/docs/src/src/JBFeelessAddresses.sol/contract.JBFeelessAddresses.md +80 -0
- package/docs/src/src/JBFundAccessLimits.sol/contract.JBFundAccessLimits.md +253 -0
- package/docs/src/src/JBMultiTerminal.sol/contract.JBMultiTerminal.md +1472 -0
- package/docs/src/src/JBPermissions.sol/contract.JBPermissions.md +199 -0
- package/docs/src/src/JBPrices.sol/contract.JBPrices.md +154 -0
- package/docs/src/src/JBProjects.sol/contract.JBProjects.md +131 -0
- package/docs/src/src/JBRulesets.sol/contract.JBRulesets.md +677 -0
- package/docs/src/src/JBSplits.sol/contract.JBSplits.md +237 -0
- package/docs/src/src/JBTerminalStore.sol/contract.JBTerminalStore.md +591 -0
- package/docs/src/src/JBTokens.sol/contract.JBTokens.md +353 -0
- package/docs/src/src/README.md +25 -0
- package/docs/src/src/abstract/JBControlled.sol/abstract.JBControlled.md +64 -0
- package/docs/src/src/abstract/JBPermissioned.sol/abstract.JBPermissioned.md +84 -0
- package/docs/src/src/abstract/README.md +5 -0
- package/docs/src/src/enums/JBApprovalStatus.sol/enum.JBApprovalStatus.md +17 -0
- package/docs/src/src/enums/README.md +4 -0
- package/docs/src/src/interfaces/IJBCashOutHook.sol/interface.IJBCashOutHook.md +29 -0
- package/docs/src/src/interfaces/IJBCashOutTerminal.sol/interface.IJBCashOutTerminal.md +57 -0
- package/docs/src/src/interfaces/IJBControlled.sol/interface.IJBControlled.md +12 -0
- package/docs/src/src/interfaces/IJBController.sol/interface.IJBController.md +334 -0
- package/docs/src/src/interfaces/IJBDirectory.sol/interface.IJBDirectory.md +108 -0
- package/docs/src/src/interfaces/IJBDirectoryAccessControl.sol/interface.IJBDirectoryAccessControl.md +19 -0
- package/docs/src/src/interfaces/IJBFeeTerminal.sol/interface.IJBFeeTerminal.md +91 -0
- package/docs/src/src/interfaces/IJBFeelessAddresses.sol/interface.IJBFeelessAddresses.md +26 -0
- package/docs/src/src/interfaces/IJBFundAccessLimits.sol/interface.IJBFundAccessLimits.md +88 -0
- package/docs/src/src/interfaces/IJBMigratable.sol/interface.IJBMigratable.md +29 -0
- package/docs/src/src/interfaces/IJBMultiTerminal.sol/interface.IJBMultiTerminal.md +50 -0
- package/docs/src/src/interfaces/IJBPayHook.sol/interface.IJBPayHook.md +28 -0
- package/docs/src/src/interfaces/IJBPayoutTerminal.sol/interface.IJBPayoutTerminal.md +105 -0
- package/docs/src/src/interfaces/IJBPermissioned.sol/interface.IJBPermissioned.md +12 -0
- package/docs/src/src/interfaces/IJBPermissions.sol/interface.IJBPermissions.md +74 -0
- package/docs/src/src/interfaces/IJBPermitTerminal.sol/interface.IJBPermitTerminal.md +15 -0
- package/docs/src/src/interfaces/IJBPriceFeed.sol/interface.IJBPriceFeed.md +12 -0
- package/docs/src/src/interfaces/IJBPrices.sol/interface.IJBPrices.md +74 -0
- package/docs/src/src/interfaces/IJBProjectUriRegistry.sol/interface.IJBProjectUriRegistry.md +19 -0
- package/docs/src/src/interfaces/IJBProjects.sol/interface.IJBProjects.md +49 -0
- package/docs/src/src/interfaces/IJBRulesetApprovalHook.sol/interface.IJBRulesetApprovalHook.md +35 -0
- package/docs/src/src/interfaces/IJBRulesetDataHook.sol/interface.IJBRulesetDataHook.md +97 -0
- package/docs/src/src/interfaces/IJBRulesets.sol/interface.IJBRulesets.md +165 -0
- package/docs/src/src/interfaces/IJBSplitHook.sol/interface.IJBSplitHook.md +31 -0
- package/docs/src/src/interfaces/IJBSplits.sol/interface.IJBSplits.md +35 -0
- package/docs/src/src/interfaces/IJBTerminal.sol/interface.IJBTerminal.md +141 -0
- package/docs/src/src/interfaces/IJBTerminalStore.sol/interface.IJBTerminalStore.md +198 -0
- package/docs/src/src/interfaces/IJBToken.sol/interface.IJBToken.md +54 -0
- package/docs/src/src/interfaces/IJBTokenUriResolver.sol/interface.IJBTokenUriResolver.md +12 -0
- package/docs/src/src/interfaces/IJBTokens.sol/interface.IJBTokens.md +151 -0
- package/docs/src/src/interfaces/README.md +33 -0
- package/docs/src/src/libraries/JBCashOuts.sol/library.JBCashOuts.md +40 -0
- package/docs/src/src/libraries/JBConstants.sol/library.JBConstants.md +52 -0
- package/docs/src/src/libraries/JBCurrencyIds.sol/library.JBCurrencyIds.md +19 -0
- package/docs/src/src/libraries/JBFees.sol/library.JBFees.md +52 -0
- package/docs/src/src/libraries/JBFixedPointNumber.sol/library.JBFixedPointNumber.md +12 -0
- package/docs/src/src/libraries/JBMetadataResolver.sol/library.JBMetadataResolver.md +242 -0
- package/docs/src/src/libraries/JBRulesetMetadataResolver.sol/library.JBRulesetMetadataResolver.md +180 -0
- package/docs/src/src/libraries/JBSplitGroupIds.sol/library.JBSplitGroupIds.md +14 -0
- package/docs/src/src/libraries/JBSurplus.sol/library.JBSurplus.md +44 -0
- package/docs/src/src/libraries/README.md +12 -0
- package/docs/src/src/periphery/JBDeadline1Day.sol/contract.JBDeadline1Day.md +15 -0
- package/docs/src/src/periphery/JBDeadline3Days.sol/contract.JBDeadline3Days.md +15 -0
- package/docs/src/src/periphery/JBDeadline3Hours.sol/contract.JBDeadline3Hours.md +15 -0
- package/docs/src/src/periphery/JBDeadline7Days.sol/contract.JBDeadline7Days.md +15 -0
- package/docs/src/src/periphery/JBMatchingPriceFeed.sol/contract.JBMatchingPriceFeed.md +22 -0
- package/docs/src/src/periphery/README.md +8 -0
- package/docs/src/src/structs/JBAccountingContext.sol/struct.JBAccountingContext.md +20 -0
- package/docs/src/src/structs/JBAfterCashOutRecordedContext.sol/struct.JBAfterCashOutRecordedContext.md +43 -0
- package/docs/src/src/structs/JBAfterPayRecordedContext.sol/struct.JBAfterPayRecordedContext.md +42 -0
- package/docs/src/src/structs/JBBeforeCashOutRecordedContext.sol/struct.JBBeforeCashOutRecordedContext.md +45 -0
- package/docs/src/src/structs/JBBeforePayRecordedContext.sol/struct.JBBeforePayRecordedContext.md +41 -0
- package/docs/src/src/structs/JBCashOutHookSpecification.sol/struct.JBCashOutHookSpecification.md +22 -0
- package/docs/src/src/structs/JBCurrencyAmount.sol/struct.JBCurrencyAmount.md +17 -0
- package/docs/src/src/structs/JBFee.sol/struct.JBFee.md +20 -0
- package/docs/src/src/structs/JBFundAccessLimitGroup.sol/struct.JBFundAccessLimitGroup.md +39 -0
- package/docs/src/src/structs/JBPayHookSpecification.sol/struct.JBPayHookSpecification.md +22 -0
- package/docs/src/src/structs/JBPermissionsData.sol/struct.JBPermissionsData.md +21 -0
- package/docs/src/src/structs/JBRuleset.sol/struct.JBRuleset.md +55 -0
- package/docs/src/src/structs/JBRulesetConfig.sol/struct.JBRulesetConfig.md +51 -0
- package/docs/src/src/structs/JBRulesetMetadata.sol/struct.JBRulesetMetadata.md +79 -0
- package/docs/src/src/structs/JBRulesetWeightCache.sol/struct.JBRulesetWeightCache.md +16 -0
- package/docs/src/src/structs/JBRulesetWithMetadata.sol/struct.JBRulesetWithMetadata.md +16 -0
- package/docs/src/src/structs/JBSingleAllowance.sol/struct.JBSingleAllowance.md +26 -0
- package/docs/src/src/structs/JBSplit.sol/struct.JBSplit.md +49 -0
- package/docs/src/src/structs/JBSplitGroup.sol/struct.JBSplitGroup.md +17 -0
- package/docs/src/src/structs/JBSplitHookContext.sol/struct.JBSplitHookContext.md +29 -0
- package/docs/src/src/structs/JBTerminalConfig.sol/struct.JBTerminalConfig.md +16 -0
- package/docs/src/src/structs/JBTokenAmount.sol/struct.JBTokenAmount.md +23 -0
- package/docs/src/src/structs/README.md +25 -0
- package/foundry.lock +11 -0
- package/foundry.toml +41 -0
- package/package.json +38 -0
- package/remappings.txt +1 -0
- package/script/Deploy.s.sol +111 -0
- package/script/DeployPeriphery.s.sol +287 -0
- package/script/helpers/CoreDeploymentLib.sol +121 -0
- package/slither-ci.config.json +10 -0
- package/sphinx.lock +507 -0
- package/src/JBChainlinkV3PriceFeed.sol +77 -0
- package/src/JBChainlinkV3SequencerPriceFeed.sol +75 -0
- package/src/JBController.sol +1186 -0
- package/src/JBDeadline.sol +73 -0
- package/src/JBDirectory.sol +343 -0
- package/src/JBERC20.sol +131 -0
- package/src/JBFeelessAddresses.sol +54 -0
- package/src/JBFundAccessLimits.sol +308 -0
- package/src/JBMultiTerminal.sol +2024 -0
- package/src/JBPermissions.sol +252 -0
- package/src/JBPrices.sol +227 -0
- package/src/JBProjects.sol +126 -0
- package/src/JBRulesets.sol +1093 -0
- package/src/JBSplits.sol +324 -0
- package/src/JBTerminalStore.sol +908 -0
- package/src/JBTokens.sol +376 -0
- package/src/abstract/JBControlled.sol +48 -0
- package/src/abstract/JBPermissioned.sol +77 -0
- package/src/enums/JBApprovalStatus.sol +12 -0
- package/src/interfaces/IJBCashOutHook.sol +15 -0
- package/src/interfaces/IJBCashOutTerminal.sol +51 -0
- package/src/interfaces/IJBControlled.sol +10 -0
- package/src/interfaces/IJBController.sol +280 -0
- package/src/interfaces/IJBDirectory.sol +69 -0
- package/src/interfaces/IJBDirectoryAccessControl.sol +15 -0
- package/src/interfaces/IJBFeeTerminal.sol +61 -0
- package/src/interfaces/IJBFeelessAddresses.sol +17 -0
- package/src/interfaces/IJBFundAccessLimits.sol +94 -0
- package/src/interfaces/IJBMigratable.sol +24 -0
- package/src/interfaces/IJBMultiTerminal.sol +36 -0
- package/src/interfaces/IJBPayHook.sol +14 -0
- package/src/interfaces/IJBPayoutTerminal.sol +92 -0
- package/src/interfaces/IJBPermissioned.sol +10 -0
- package/src/interfaces/IJBPermissions.sol +71 -0
- package/src/interfaces/IJBPermitTerminal.sol +14 -0
- package/src/interfaces/IJBPriceFeed.sol +10 -0
- package/src/interfaces/IJBPrices.sol +65 -0
- package/src/interfaces/IJBProjectUriRegistry.sol +15 -0
- package/src/interfaces/IJBProjects.sol +27 -0
- package/src/interfaces/IJBRulesetApprovalHook.sol +21 -0
- package/src/interfaces/IJBRulesetDataHook.sol +56 -0
- package/src/interfaces/IJBRulesets.sol +151 -0
- package/src/interfaces/IJBSplitHook.sol +16 -0
- package/src/interfaces/IJBSplits.sol +28 -0
- package/src/interfaces/IJBTerminal.sol +120 -0
- package/src/interfaces/IJBTerminalStore.sol +225 -0
- package/src/interfaces/IJBToken.sol +39 -0
- package/src/interfaces/IJBTokenUriResolver.sol +10 -0
- package/src/interfaces/IJBTokens.sol +113 -0
- package/src/libraries/JBCashOuts.sol +120 -0
- package/src/libraries/JBConstants.sol +14 -0
- package/src/libraries/JBCurrencyIds.sol +7 -0
- package/src/libraries/JBFees.sol +28 -0
- package/src/libraries/JBFixedPointNumber.sol +12 -0
- package/src/libraries/JBMetadataResolver.sol +306 -0
- package/src/libraries/JBRulesetMetadataResolver.sol +160 -0
- package/src/libraries/JBSplitGroupIds.sol +7 -0
- package/src/libraries/JBSurplus.sol +40 -0
- package/src/periphery/JBDeadline1Day.sol +8 -0
- package/src/periphery/JBDeadline3Days.sol +8 -0
- package/src/periphery/JBDeadline3Hours.sol +8 -0
- package/src/periphery/JBDeadline7Days.sol +8 -0
- package/src/periphery/JBMatchingPriceFeed.sol +13 -0
- package/src/structs/JBAccountingContext.sol +12 -0
- package/src/structs/JBAfterCashOutRecordedContext.sol +30 -0
- package/src/structs/JBAfterPayRecordedContext.sol +29 -0
- package/src/structs/JBBeforeCashOutRecordedContext.sol +31 -0
- package/src/structs/JBBeforePayRecordedContext.sol +28 -0
- package/src/structs/JBCashOutHookSpecification.sol +15 -0
- package/src/structs/JBCurrencyAmount.sol +10 -0
- package/src/structs/JBFee.sol +12 -0
- package/src/structs/JBFundAccessLimitGroup.sol +28 -0
- package/src/structs/JBPayHookSpecification.sol +15 -0
- package/src/structs/JBPermissionsData.sol +13 -0
- package/src/structs/JBRuleset.sol +42 -0
- package/src/structs/JBRulesetConfig.sol +43 -0
- package/src/structs/JBRulesetMetadata.sol +56 -0
- package/src/structs/JBRulesetWeightCache.sol +9 -0
- package/src/structs/JBRulesetWithMetadata.sol +12 -0
- package/src/structs/JBSingleAllowance.sol +16 -0
- package/src/structs/JBSplit.sol +37 -0
- package/src/structs/JBSplitGroup.sol +12 -0
- package/src/structs/JBSplitHookContext.sol +20 -0
- package/src/structs/JBTerminalConfig.sol +12 -0
- package/src/structs/JBTokenAmount.sol +14 -0
- package/test/AuditExploits.t.sol +2710 -0
- package/test/ComprehensiveInvariant.t.sol +298 -0
- package/test/EconomicSimulation.t.sol +340 -0
- package/test/EntryPointPermutations.t.sol +671 -0
- package/test/FlashLoanAttacks.t.sol +792 -0
- package/test/PermissionEscalation.t.sol +679 -0
- package/test/RulesetTransitions.t.sol +699 -0
- package/test/SplitLoopTests.t.sol +731 -0
- package/test/TestAccessToFunds.sol +2644 -0
- package/test/TestCashOut.sol +185 -0
- package/test/TestCashOutCountFor.sol +272 -0
- package/test/TestCashOutHooks.sol +317 -0
- package/test/TestCashOutTimingEdge.sol +229 -0
- package/test/TestDurationUnderflow.sol +220 -0
- package/test/TestFeeProcessingFailure.sol +208 -0
- package/test/TestFees.sol +604 -0
- package/test/TestInterfaceSupport.sol +62 -0
- package/test/TestJBERC20Inheritance.sol +91 -0
- package/test/TestLaunchProject.sol +176 -0
- package/test/TestMetaTx.sol +203 -0
- package/test/TestMetadataParserLib.sol +438 -0
- package/test/TestMigrationHeldFees.sol +249 -0
- package/test/TestMintTokensOf.sol +172 -0
- package/test/TestMultiTokenSurplus.sol +206 -0
- package/test/TestMultipleAccessLimits.sol +642 -0
- package/test/TestPayBurnRedeemFlow.sol +180 -0
- package/test/TestPayHooks.sol +190 -0
- package/test/TestPermissions.sol +305 -0
- package/test/TestPermissionsEdge.sol +286 -0
- package/test/TestPermit2Terminal.sol +339 -0
- package/test/TestRulesetQueueing.sol +1001 -0
- package/test/TestRulesetQueuingStress.sol +778 -0
- package/test/TestRulesetWeightCaching.sol +177 -0
- package/test/TestSplits.sol +369 -0
- package/test/TestTerminalMigration.sol +167 -0
- package/test/TestTokenFlow.sol +174 -0
- package/test/WeirdTokenTests.t.sol +764 -0
- package/test/formal/BondingCurveProperties.t.sol +411 -0
- package/test/formal/FeeProperties.t.sol +246 -0
- package/test/helpers/JBTest.sol +129 -0
- package/test/helpers/MetadataResolverHelper.sol +116 -0
- package/test/helpers/TestBaseWorkflow.sol +317 -0
- package/test/invariants/Phase3DeepInvariant.t.sol +404 -0
- package/test/invariants/RulesetsInvariant.t.sol +115 -0
- package/test/invariants/TerminalStoreInvariant.t.sol +220 -0
- package/test/invariants/TokensInvariant.t.sol +184 -0
- package/test/invariants/handlers/ComprehensiveHandler.sol +285 -0
- package/test/invariants/handlers/EconomicHandler.sol +347 -0
- package/test/invariants/handlers/Phase3Handler.sol +414 -0
- package/test/invariants/handlers/RulesetsHandler.sol +111 -0
- package/test/invariants/handlers/TerminalStoreHandler.sol +146 -0
- package/test/invariants/handlers/TokensHandler.sol +127 -0
- package/test/mock/ERC2771ForwarderMock.sol +37 -0
- package/test/mock/MockERC20.sol +18 -0
- package/test/mock/MockMaliciousBeneficiary.sol +67 -0
- package/test/mock/MockMaliciousSplitHook.sol +42 -0
- package/test/mock/MockPriceFeed.sol +20 -0
- package/test/trees/JBController/burnTokensOf.tree +9 -0
- package/test/trees/JBController/claimTokensFor.tree +5 -0
- package/test/trees/JBController/deployERC20For.tree +5 -0
- package/test/trees/JBController/getRulesetOf.tree +5 -0
- package/test/trees/JBController/launchProjectFor.tree +12 -0
- package/test/trees/JBController/launchRulesetsFor.tree +8 -0
- package/test/trees/JBController/migrateController.tree +12 -0
- package/test/trees/JBController/mintTokensOf.tree +12 -0
- package/test/trees/JBController/payReservedTokenToTerminal.tree +8 -0
- package/test/trees/JBController/receiveMigrationFrom.tree +4 -0
- package/test/trees/JBController/sendReservedTokensToSplitsOf.tree +12 -0
- package/test/trees/JBController/setMetadataOf.tree +5 -0
- package/test/trees/JBController/setSplitGroupsOf.tree +5 -0
- package/test/trees/JBController/setTokenFor.tree +5 -0
- package/test/trees/JBController/transferCreditsFrom.tree +8 -0
- package/test/trees/JBDirectory/primaryTerminalOf.tree +8 -0
- package/test/trees/JBDirectory/setControllerOf.tree +11 -0
- package/test/trees/JBDirectory/setPrimaryTerminalOf.tree +15 -0
- package/test/trees/JBDirectory/setTerminalsOf.tree +11 -0
- package/test/trees/JBERC20/initialize.tree +7 -0
- package/test/trees/JBERC20/name.tree +5 -0
- package/test/trees/JBERC20/nonces.tree +5 -0
- package/test/trees/JBERC20/symbol.tree +5 -0
- package/test/trees/JBFeelessAddresses/setFeelessAddress.tree +5 -0
- package/test/trees/JBFeelessAddresses/supportsInterface.tree +5 -0
- package/test/trees/JBFundAccessLimits/payoutLimitOf.tree +5 -0
- package/test/trees/JBFundAccessLimits/payoutLimitsOf.tree +8 -0
- package/test/trees/JBFundAccessLimits/setFundAccessLimitsFor.tree +18 -0
- package/test/trees/JBFundAccessLimits/surplusAllowanceOf.tree +5 -0
- package/test/trees/JBFundAccessLimits/surplusAllowancesOf.tree +8 -0
- package/test/trees/JBMetadataResolver/getDataFor.tree +8 -0
- package/test/trees/JBMultiTerminal/accountingContextsOf.tree +5 -0
- package/test/trees/JBMultiTerminal/addAccountingContextsFor.tree +10 -0
- package/test/trees/JBMultiTerminal/addToBalanceOf.tree +23 -0
- package/test/trees/JBMultiTerminal/cashOutTokensOf.tree +23 -0
- package/test/trees/JBMultiTerminal/executePayout.tree +32 -0
- package/test/trees/JBMultiTerminal/executeProcessFee.tree +14 -0
- package/test/trees/JBMultiTerminal/migrateBalanceOf.tree +12 -0
- package/test/trees/JBMultiTerminal/pay.tree +23 -0
- package/test/trees/JBMultiTerminal/processHeldFeesOf.tree +8 -0
- package/test/trees/JBMultiTerminal/sendPayoutsOf.tree +34 -0
- package/test/trees/JBMultiTerminal/useAllowanceOf.tree +16 -0
- package/test/trees/JBPermissions/hasPermission.tree +8 -0
- package/test/trees/JBPermissions/hasPermissions.tree +8 -0
- package/test/trees/JBPermissions/setPermissionsFor.tree +5 -0
- package/test/trees/JBPrices/addPriceFeedFor.tree +14 -0
- package/test/trees/JBPrices/pricePerUnitOf.tree +11 -0
- package/test/trees/JBProjects/createFor.tree +11 -0
- package/test/trees/JBProjects/setTokenUriResolver.tree +5 -0
- package/test/trees/JBProjects/supportsInterface.tree +9 -0
- package/test/trees/JBProjects/tokenURI.tree +5 -0
- package/test/trees/JBRulesets/currentApprovalStatusForLatestRulesetOf.tree +8 -0
- package/test/trees/JBRulesets/currentOf.tree +12 -0
- package/test/trees/JBRulesets/getRulesetOf.tree +5 -0
- package/test/trees/JBRulesets/latestQueuedRulesetOf.tree +10 -0
- package/test/trees/JBRulesets/rulesetsOf.tree +11 -0
- package/test/trees/JBRulesets/upcomingRulesetOf.tree +20 -0
- package/test/trees/JBRulesets/updateRulesetWeightCache.tree +5 -0
- package/test/trees/JBSplits/setSplitGroupsOf.tree +17 -0
- package/test/trees/JBSplits/splitsOf.tree +5 -0
- package/test/trees/JBTerminalStore/currentReclaimableSurplusOf.tree +16 -0
- package/test/trees/JBTerminalStore/currentSurplusOf.tree +25 -0
- package/test/trees/JBTerminalStore/currentTotalSurplusOf.tree +5 -0
- package/test/trees/JBTerminalStore/recordCashOutsFor.tree +16 -0
- package/test/trees/JBTerminalStore/recordPaymentFrom.tree +14 -0
- package/test/trees/JBTerminalStore/recordPayoutFor.tree +10 -0
- package/test/trees/JBTerminalStore/recordTerminalMigration.tree +5 -0
- package/test/trees/JBTerminalStore/recordUsedAllowanceOf.tree +10 -0
- package/test/trees/JBTokens/burnFrom.tree +10 -0
- package/test/trees/JBTokens/claimTokensFor.tree +10 -0
- package/test/trees/JBTokens/deployERC20For.tree +12 -0
- package/test/trees/JBTokens/mintFor.tree +10 -0
- package/test/trees/JBTokens/setTokenFor.tree +11 -0
- package/test/trees/JBTokens/totalBalanceOf.tree +5 -0
- package/test/trees/JBTokens/totalSupplyOf.tree +5 -0
- package/test/trees/JBTokens/transferCreditsFrom.tree +8 -0
- package/test/trees/mintTokensOf.tree +12 -0
- package/test/units/static/JBChainlinkV3PriceFeed/TestPriceFeed.sol +220 -0
- package/test/units/static/JBController/JBControllerSetup.sol +40 -0
- package/test/units/static/JBController/TestBurnTokensOf.sol +107 -0
- package/test/units/static/JBController/TestClaimTokensFor.sol +60 -0
- package/test/units/static/JBController/TestDeployErc20For.sol +80 -0
- package/test/units/static/JBController/TestLaunchProjectFor.sol +282 -0
- package/test/units/static/JBController/TestLaunchRulesetsFor.sol +322 -0
- package/test/units/static/JBController/TestMigrateController.sol +148 -0
- package/test/units/static/JBController/TestMintTokensOfUnits.sol +102 -0
- package/test/units/static/JBController/TestPayReservedTokenToTerminal.sol +71 -0
- package/test/units/static/JBController/TestReceiveMigrationFrom.sol +95 -0
- package/test/units/static/JBController/TestRulesetViews.sol +219 -0
- package/test/units/static/JBController/TestSendReservedTokensToSplitsOf.sol +595 -0
- package/test/units/static/JBController/TestSetSplitGroupsOf.sol +63 -0
- package/test/units/static/JBController/TestSetTokenFor.sol +227 -0
- package/test/units/static/JBController/TestSetUriOf.sol +53 -0
- package/test/units/static/JBController/TestTransferCreditsFrom.sol +159 -0
- package/test/units/static/JBDeadline/TestDeadlineFuzz.sol +194 -0
- package/test/units/static/JBDirectory/JBDirectorySetup.sol +22 -0
- package/test/units/static/JBDirectory/TestPrimaryTerminalOf.sol +122 -0
- package/test/units/static/JBDirectory/TestSetControllerOf.sol +173 -0
- package/test/units/static/JBDirectory/TestSetControllerOfMigrationOrder.sol +98 -0
- package/test/units/static/JBDirectory/TestSetPrimaryTerminalOf.sol +169 -0
- package/test/units/static/JBDirectory/TestSetTerminalsOf.sol +128 -0
- package/test/units/static/JBERC20/JBERC20Setup.sol +20 -0
- package/test/units/static/JBERC20/SigUtils.sol +34 -0
- package/test/units/static/JBERC20/TestInitialize.sol +54 -0
- package/test/units/static/JBERC20/TestName.sol +30 -0
- package/test/units/static/JBERC20/TestNonces.sol +59 -0
- package/test/units/static/JBERC20/TestSymbol.sol +31 -0
- package/test/units/static/JBFeelessAdresses/JBFeelessSetup.sol +20 -0
- package/test/units/static/JBFeelessAdresses/TestInterfaces.sol +29 -0
- package/test/units/static/JBFeelessAdresses/TestSetFeelessAddress.sol +35 -0
- package/test/units/static/JBFees/TestFeesFuzz.sol +78 -0
- package/test/units/static/JBFixedPointNumber/TestAdjustDecimals.sol +16 -0
- package/test/units/static/JBFixedPointNumber/TestAdjustDecimalsFuzz.sol +71 -0
- package/test/units/static/JBFundAccessLimits/JBFundAccessSetup.sol +21 -0
- package/test/units/static/JBFundAccessLimits/TestFundAccessLimitsEdge.sol +159 -0
- package/test/units/static/JBFundAccessLimits/TestPayoutLimitOf.sol +56 -0
- package/test/units/static/JBFundAccessLimits/TestPayoutLimitsOf.sol +94 -0
- package/test/units/static/JBFundAccessLimits/TestSetFundAccessLimitsFor.sol +182 -0
- package/test/units/static/JBFundAccessLimits/TestSurplusAllowanceOf.sol +61 -0
- package/test/units/static/JBFundAccessLimits/TestSurplusAllowancesOf.sol +96 -0
- package/test/units/static/JBMetadataResolver/TestGetDataFor.sol +89 -0
- package/test/units/static/JBMetadataResolver/TestMetadataResolverFuzz.sol +227 -0
- package/test/units/static/JBMetadataResolver/TestMetadataResolverM20M21.sol +245 -0
- package/test/units/static/JBMultiTerminal/JBMultiTerminalSetup.sol +39 -0
- package/test/units/static/JBMultiTerminal/TestAccountingContextsOf.sol +65 -0
- package/test/units/static/JBMultiTerminal/TestAddAccountingContextsFor.sol +313 -0
- package/test/units/static/JBMultiTerminal/TestAddToBalanceOf.sol +432 -0
- package/test/units/static/JBMultiTerminal/TestCashOutTokensOf.sol +478 -0
- package/test/units/static/JBMultiTerminal/TestExecutePayout.sol +577 -0
- package/test/units/static/JBMultiTerminal/TestExecuteProcessFee.sol +176 -0
- package/test/units/static/JBMultiTerminal/TestMigrateBalanceOf.sol +190 -0
- package/test/units/static/JBMultiTerminal/TestPay.sol +514 -0
- package/test/units/static/JBMultiTerminal/TestProcessHeldFeesOf.sol +29 -0
- package/test/units/static/JBMultiTerminal/TestSendPayoutsOf.sol +243 -0
- package/test/units/static/JBMultiTerminal/TestUseAllowanceOf.sol +310 -0
- package/test/units/static/JBPermissions/JBPermissionsSetup.sol +18 -0
- package/test/units/static/JBPermissions/TestHasPermission.sol +50 -0
- package/test/units/static/JBPermissions/TestHasPermissions.sol +93 -0
- package/test/units/static/JBPermissions/TestSetPermissionsFor.sol +62 -0
- package/test/units/static/JBPrices/JBPricesSetup.sol +26 -0
- package/test/units/static/JBPrices/TestAddPriceFeedFor.sol +102 -0
- package/test/units/static/JBPrices/TestPricePerUnitOf.sol +129 -0
- package/test/units/static/JBPrices/TestPrices.sol +262 -0
- package/test/units/static/JBProjects/JBProjectsSetup.sol +20 -0
- package/test/units/static/JBProjects/TestCreateFor.sol +69 -0
- package/test/units/static/JBProjects/TestInitialProject.sol +19 -0
- package/test/units/static/JBProjects/TestInterfaces.sol +27 -0
- package/test/units/static/JBProjects/TestSetResolver.sol +36 -0
- package/test/units/static/JBProjects/TestTokenUri.sol +38 -0
- package/test/units/static/JBRulesetMetadataResolver/TestSetCashOutTaxRateTo.sol +99 -0
- package/test/units/static/JBRulesets/JBRulesetsSetup.sol +21 -0
- package/test/units/static/JBRulesets/TestCurrentApprovalStatusForLatestRulesetOf.sol +257 -0
- package/test/units/static/JBRulesets/TestCurrentOf.sol +231 -0
- package/test/units/static/JBRulesets/TestGetRulesetOf.sol +94 -0
- package/test/units/static/JBRulesets/TestLatestQueuedRulesetOf.sol +252 -0
- package/test/units/static/JBRulesets/TestRulesets.sol +617 -0
- package/test/units/static/JBRulesets/TestRulesetsOf.sol +37 -0
- package/test/units/static/JBRulesets/TestUpcomingRulesetOf.sol +526 -0
- package/test/units/static/JBRulesets/TestUpdateRulesetWeightCache.sol +91 -0
- package/test/units/static/JBSplits/JBSplitsSetup.sol +23 -0
- package/test/units/static/JBSplits/TestSelfManagedSplitGroups.sol +502 -0
- package/test/units/static/JBSplits/TestSetSplitGroupsOf.sol +370 -0
- package/test/units/static/JBSplits/TestSplitsLockedEdge.sol +262 -0
- package/test/units/static/JBSplits/TestSplitsOf.sol +24 -0
- package/test/units/static/JBSplits/TestSplitsPacking.sol +33 -0
- package/test/units/static/JBSurplus/TestSurplusFuzz.sol +125 -0
- package/test/units/static/JBTerminalStore/JBTerminalStoreSetup.sol +23 -0
- package/test/units/static/JBTerminalStore/TestCurrentReclaimableSurplusOf.sol +434 -0
- package/test/units/static/JBTerminalStore/TestCurrentSurplusOf.sol +428 -0
- package/test/units/static/JBTerminalStore/TestCurrentTotalSurplusOf.sol +65 -0
- package/test/units/static/JBTerminalStore/TestRecordCashOutsFor.sol +479 -0
- package/test/units/static/JBTerminalStore/TestRecordPaymentFrom.sol +508 -0
- package/test/units/static/JBTerminalStore/TestRecordPayoutFor.sol +257 -0
- package/test/units/static/JBTerminalStore/TestRecordTerminalMigration.sol +131 -0
- package/test/units/static/JBTerminalStore/TestRecordUsedAllowanceOf.sol +390 -0
- package/test/units/static/JBTerminalStore/TestUint224Overflow.sol +187 -0
- package/test/units/static/JBTokens/JBTokensSetup.sol +23 -0
- package/test/units/static/JBTokens/TestBurnFrom.sol +104 -0
- package/test/units/static/JBTokens/TestClaimTokensFor.sol +107 -0
- package/test/units/static/JBTokens/TestDeployERC20ForUnits.sol +89 -0
- package/test/units/static/JBTokens/TestMintFor.sol +97 -0
- package/test/units/static/JBTokens/TestSetTokenFor.sol +95 -0
- package/test/units/static/JBTokens/TestTotalBalanceOf.sol +65 -0
- package/test/units/static/JBTokens/TestTotalSupplyOf.sol +56 -0
- package/test/units/static/JBTokens/TestTransferCreditsFrom.sol +54 -0
|
@@ -0,0 +1,1093 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.23;
|
|
3
|
+
|
|
4
|
+
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
5
|
+
|
|
6
|
+
import {JBControlled} from "./abstract/JBControlled.sol";
|
|
7
|
+
import {JBApprovalStatus} from "./enums/JBApprovalStatus.sol";
|
|
8
|
+
import {IJBDirectory} from "./interfaces/IJBDirectory.sol";
|
|
9
|
+
import {IJBRulesetApprovalHook} from "./interfaces/IJBRulesetApprovalHook.sol";
|
|
10
|
+
import {IJBRulesets} from "./interfaces/IJBRulesets.sol";
|
|
11
|
+
import {JBConstants} from "./libraries/JBConstants.sol";
|
|
12
|
+
import {JBRuleset} from "./structs/JBRuleset.sol";
|
|
13
|
+
import {JBRulesetWeightCache} from "./structs/JBRulesetWeightCache.sol";
|
|
14
|
+
|
|
15
|
+
/// @notice Manages rulesets and queuing.
|
|
16
|
+
/// @dev Rulesets dictate how a project behaves for a period of time. To learn more about their functionality, see the
|
|
17
|
+
/// `JBRuleset` data structure.
|
|
18
|
+
/// @dev Throughout this contract, `rulesetId` is an identifier for each ruleset. The `rulesetId` is the unix timestamp
|
|
19
|
+
/// when the ruleset was initialized.
|
|
20
|
+
/// @dev `approvable` means a ruleset which may or may not be approved.
|
|
21
|
+
contract JBRulesets is JBControlled, IJBRulesets {
|
|
22
|
+
//*********************************************************************//
|
|
23
|
+
// --------------------------- custom errors ------------------------- //
|
|
24
|
+
//*********************************************************************//
|
|
25
|
+
|
|
26
|
+
error JBRulesets_InvalidRulesetApprovalHook(IJBRulesetApprovalHook hook);
|
|
27
|
+
error JBRulesets_InvalidRulesetDuration(uint256 duration, uint256 limit);
|
|
28
|
+
error JBRulesets_InvalidRulesetEndTime(uint256 timestamp, uint256 limit);
|
|
29
|
+
error JBRulesets_InvalidWeight(uint256 weight, uint256 limit);
|
|
30
|
+
error JBRulesets_InvalidWeightCutPercent(uint256 percent);
|
|
31
|
+
error JBRulesets_WeightCacheRequired(uint256 projectId);
|
|
32
|
+
|
|
33
|
+
//*********************************************************************//
|
|
34
|
+
// ------------------------- internal constants ----------------------- //
|
|
35
|
+
//*********************************************************************//
|
|
36
|
+
|
|
37
|
+
/// @notice The maximum number of weight cut iterations allowed per call.
|
|
38
|
+
/// If more cycles are needed, callers must populate the cache via updateRulesetWeightCache() first.
|
|
39
|
+
uint256 internal constant _WEIGHT_CUT_MULTIPLE_CACHE_LOOKUP_THRESHOLD = 20_000;
|
|
40
|
+
|
|
41
|
+
//*********************************************************************//
|
|
42
|
+
// --------------------- public stored properties -------------------- //
|
|
43
|
+
//*********************************************************************//
|
|
44
|
+
|
|
45
|
+
/// @notice The ID of the ruleset with the latest start time for a specific project, whether the ruleset has been
|
|
46
|
+
/// approved or not.
|
|
47
|
+
/// @dev If a project has multiple rulesets queued, the `latestRulesetIdOf` will be the last one. This is the
|
|
48
|
+
/// "changeable" cycle.
|
|
49
|
+
/// @custom:param projectId The ID of the project to get the latest ruleset ID of.
|
|
50
|
+
/// @return latestRulesetIdOf The `rulesetId` of the project's latest ruleset.
|
|
51
|
+
mapping(uint256 projectId => uint256) public override latestRulesetIdOf;
|
|
52
|
+
|
|
53
|
+
//*********************************************************************//
|
|
54
|
+
// --------------------- internal stored properties ------------------- //
|
|
55
|
+
//*********************************************************************//
|
|
56
|
+
|
|
57
|
+
/// @notice The metadata for each ruleset, packed into one storage slot.
|
|
58
|
+
/// @custom:param projectId The ID of the project to get metadata of.
|
|
59
|
+
/// @custom:param rulesetId The ID of the ruleset to get metadata of.
|
|
60
|
+
mapping(uint256 projectId => mapping(uint256 rulesetId => uint256)) internal _metadataOf;
|
|
61
|
+
|
|
62
|
+
/// @notice The mechanism-added properties to manage and schedule each ruleset, packed into one storage slot.
|
|
63
|
+
/// @custom:param projectId The ID of the project to get the intrinsic properties of.
|
|
64
|
+
/// @custom:param rulesetId The ID of the ruleset to get the intrinsic properties of.
|
|
65
|
+
mapping(uint256 projectId => mapping(uint256 rulesetId => uint256)) internal _packedIntrinsicPropertiesOf;
|
|
66
|
+
|
|
67
|
+
/// @notice The user-defined properties of each ruleset, packed into one storage slot.
|
|
68
|
+
/// @custom:param projectId The ID of the project to get the user-defined properties of.
|
|
69
|
+
/// @custom:param rulesetId The ID of the ruleset to get the user-defined properties of.
|
|
70
|
+
mapping(uint256 projectId => mapping(uint256 rulesetId => uint256)) internal _packedUserPropertiesOf;
|
|
71
|
+
|
|
72
|
+
/// @notice Cached weight values to derive rulesets from.
|
|
73
|
+
/// @custom:param projectId The ID of the project to which the cache applies.
|
|
74
|
+
/// @custom:param rulesetId The ID of the ruleset to which the cache applies.
|
|
75
|
+
mapping(uint256 projectId => mapping(uint256 rulesetId => JBRulesetWeightCache)) internal _weightCacheOf;
|
|
76
|
+
|
|
77
|
+
//*********************************************************************//
|
|
78
|
+
// -------------------------- constructor ---------------------------- //
|
|
79
|
+
//*********************************************************************//
|
|
80
|
+
|
|
81
|
+
/// @param directory A contract storing directories of terminals and controllers for each project.
|
|
82
|
+
// solhint-disable-next-line no-empty-blocks
|
|
83
|
+
constructor(IJBDirectory directory) JBControlled(directory) {}
|
|
84
|
+
|
|
85
|
+
//*********************************************************************//
|
|
86
|
+
// ------------------------- external views -------------------------- //
|
|
87
|
+
//*********************************************************************//
|
|
88
|
+
|
|
89
|
+
/// @notice Get an array of a project's rulesets up to a maximum array size, sorted from latest to earliest.
|
|
90
|
+
/// @param projectId The ID of the project to get the rulesets of.
|
|
91
|
+
/// @param startingId The ID of the ruleset to begin with. This will be the latest ruleset in the result. If 0 is
|
|
92
|
+
/// passed, the project's latest ruleset will be used.
|
|
93
|
+
/// @param size The maximum number of rulesets to return.
|
|
94
|
+
/// @return rulesets The rulesets as an array of `JBRuleset` structs.
|
|
95
|
+
function allOf(
|
|
96
|
+
uint256 projectId,
|
|
97
|
+
uint256 startingId,
|
|
98
|
+
uint256 size
|
|
99
|
+
)
|
|
100
|
+
external
|
|
101
|
+
view
|
|
102
|
+
override
|
|
103
|
+
returns (JBRuleset[] memory rulesets)
|
|
104
|
+
{
|
|
105
|
+
// If no starting ID was provided, set it to the latest ruleset's ID.
|
|
106
|
+
if (startingId == 0) startingId = latestRulesetIdOf[projectId];
|
|
107
|
+
|
|
108
|
+
// Keep a reference to the number of rulesets being returned.
|
|
109
|
+
uint256 count = 0;
|
|
110
|
+
|
|
111
|
+
// Keep a reference to the starting ruleset.
|
|
112
|
+
JBRuleset memory ruleset = _getStructFor({projectId: projectId, rulesetId: startingId});
|
|
113
|
+
|
|
114
|
+
// First, count the number of rulesets to include in the result by iterating backwards from the starting
|
|
115
|
+
// ruleset.
|
|
116
|
+
while (ruleset.id != 0 && count < size) {
|
|
117
|
+
// Increment the counter.
|
|
118
|
+
count++;
|
|
119
|
+
|
|
120
|
+
// Iterate to the ruleset it was based on.
|
|
121
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: ruleset.basedOnId});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Keep a reference to the array of rulesets that'll be populated.
|
|
125
|
+
rulesets = new JBRuleset[](count);
|
|
126
|
+
|
|
127
|
+
// Return an empty array if there are no rulesets to return.
|
|
128
|
+
if (count == 0) {
|
|
129
|
+
return rulesets;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Reset the ruleset being iterated on to the starting ruleset.
|
|
133
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: startingId});
|
|
134
|
+
|
|
135
|
+
// Set the counter.
|
|
136
|
+
uint256 i;
|
|
137
|
+
|
|
138
|
+
// Populate the array of rulesets to return.
|
|
139
|
+
while (i < count) {
|
|
140
|
+
// Add the ruleset to the array.
|
|
141
|
+
rulesets[i++] = ruleset;
|
|
142
|
+
|
|
143
|
+
// Get the ruleset it was based on if needed.
|
|
144
|
+
if (i != count) ruleset = _getStructFor({projectId: projectId, rulesetId: ruleset.basedOnId});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/// @notice The current approval status of a given project's latest ruleset.
|
|
149
|
+
/// @param projectId The ID of the project to check the approval status of.
|
|
150
|
+
/// @return The project's current approval status.
|
|
151
|
+
function currentApprovalStatusForLatestRulesetOf(uint256 projectId)
|
|
152
|
+
external
|
|
153
|
+
view
|
|
154
|
+
override
|
|
155
|
+
returns (JBApprovalStatus)
|
|
156
|
+
{
|
|
157
|
+
// Get a reference to the latest ruleset ID.
|
|
158
|
+
uint256 rulesetId = latestRulesetIdOf[projectId];
|
|
159
|
+
|
|
160
|
+
// Resolve the struct for the latest ruleset.
|
|
161
|
+
JBRuleset memory ruleset = _getStructFor({projectId: projectId, rulesetId: rulesetId});
|
|
162
|
+
|
|
163
|
+
return _approvalStatusOf({projectId: projectId, ruleset: ruleset});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// @notice The ruleset that is currently active for the specified project.
|
|
167
|
+
/// @dev If a current ruleset of the project is not found, returns an empty ruleset with all properties set to 0.
|
|
168
|
+
/// @param projectId The ID of the project to get the current ruleset of.
|
|
169
|
+
/// @return ruleset The project's current ruleset.
|
|
170
|
+
function currentOf(uint256 projectId) external view override returns (JBRuleset memory ruleset) {
|
|
171
|
+
// If the project does not have a ruleset, return an empty struct.
|
|
172
|
+
// slither-disable-next-line incorrect-equality
|
|
173
|
+
if (latestRulesetIdOf[projectId] == 0) return _getStructFor({projectId: 0, rulesetId: 0});
|
|
174
|
+
|
|
175
|
+
// Get a reference to the currently approvable ruleset's ID.
|
|
176
|
+
uint256 rulesetId = _currentlyApprovableRulesetIdOf(projectId);
|
|
177
|
+
|
|
178
|
+
// If a currently approvable ruleset exists...
|
|
179
|
+
if (rulesetId != 0) {
|
|
180
|
+
// Resolve the struct for the currently approvable ruleset.
|
|
181
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: rulesetId});
|
|
182
|
+
|
|
183
|
+
// Get a reference to the approval status.
|
|
184
|
+
JBApprovalStatus approvalStatus = _approvalStatusOf({projectId: projectId, ruleset: ruleset});
|
|
185
|
+
|
|
186
|
+
// Check to see if this ruleset's approval hook is approved if it exists.
|
|
187
|
+
// If so, return it.
|
|
188
|
+
// slither-disable-next-line incorrect-equality
|
|
189
|
+
if (approvalStatus == JBApprovalStatus.Approved || approvalStatus == JBApprovalStatus.Empty) {
|
|
190
|
+
return ruleset;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// If it hasn't been approved, set the ruleset configuration to be the configuration of the ruleset that
|
|
194
|
+
// it's based on,
|
|
195
|
+
// which carries the last approved configuration.
|
|
196
|
+
rulesetId = ruleset.basedOnId;
|
|
197
|
+
|
|
198
|
+
// Keep a reference to its ruleset.
|
|
199
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: rulesetId});
|
|
200
|
+
} else {
|
|
201
|
+
// No upcoming ruleset found that is currently approvable,
|
|
202
|
+
// so use the latest ruleset ID.
|
|
203
|
+
rulesetId = latestRulesetIdOf[projectId];
|
|
204
|
+
|
|
205
|
+
// Get the struct for the latest ID.
|
|
206
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: rulesetId});
|
|
207
|
+
|
|
208
|
+
// Get a reference to the approval status.
|
|
209
|
+
JBApprovalStatus approvalStatus = _approvalStatusOf({projectId: projectId, ruleset: ruleset});
|
|
210
|
+
|
|
211
|
+
// While the ruleset has a approval hook that isn't approved or if it hasn't yet started, get a reference to
|
|
212
|
+
// the ruleset that the latest is based on, which has the latest approved configuration.
|
|
213
|
+
while (
|
|
214
|
+
(approvalStatus != JBApprovalStatus.Approved && approvalStatus != JBApprovalStatus.Empty)
|
|
215
|
+
|| block.timestamp < ruleset.start
|
|
216
|
+
) {
|
|
217
|
+
rulesetId = ruleset.basedOnId;
|
|
218
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: rulesetId});
|
|
219
|
+
approvalStatus = _approvalStatusOf({projectId: projectId, ruleset: ruleset});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// If the base has no duration, it's still the current one.
|
|
224
|
+
// slither-disable-next-line incorrect-equality
|
|
225
|
+
if (ruleset.duration == 0) return ruleset;
|
|
226
|
+
|
|
227
|
+
// Return a simulation of the current ruleset.
|
|
228
|
+
return _simulateCycledRulesetBasedOn({projectId: projectId, baseRuleset: ruleset, allowMidRuleset: true});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/// @notice Get the ruleset struct for a given `rulesetId` and `projectId`.
|
|
232
|
+
/// @param projectId The ID of the project to which the ruleset belongs.
|
|
233
|
+
/// @param rulesetId The ID of the ruleset to get the struct of.
|
|
234
|
+
/// @return ruleset The ruleset struct.
|
|
235
|
+
function getRulesetOf(
|
|
236
|
+
uint256 projectId,
|
|
237
|
+
uint256 rulesetId
|
|
238
|
+
)
|
|
239
|
+
external
|
|
240
|
+
view
|
|
241
|
+
override
|
|
242
|
+
returns (JBRuleset memory ruleset)
|
|
243
|
+
{
|
|
244
|
+
return _getStructFor({projectId: projectId, rulesetId: rulesetId});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/// @notice The latest ruleset queued for a project. Returns the ruleset's struct and its current approval status.
|
|
248
|
+
/// @dev Returns struct and status for the ruleset initialized furthest in the future (at the end of the ruleset
|
|
249
|
+
/// queue).
|
|
250
|
+
/// @param projectId The ID of the project to get the latest queued ruleset of.
|
|
251
|
+
/// @return ruleset The project's latest queued ruleset's struct.
|
|
252
|
+
/// @return approvalStatus The approval hook's status for the ruleset.
|
|
253
|
+
function latestQueuedOf(uint256 projectId)
|
|
254
|
+
external
|
|
255
|
+
view
|
|
256
|
+
override
|
|
257
|
+
returns (JBRuleset memory ruleset, JBApprovalStatus approvalStatus)
|
|
258
|
+
{
|
|
259
|
+
// Get a reference to the latest ruleset's ID.
|
|
260
|
+
uint256 rulesetId = latestRulesetIdOf[projectId];
|
|
261
|
+
|
|
262
|
+
// Resolve the struct for the latest ruleset.
|
|
263
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: rulesetId});
|
|
264
|
+
|
|
265
|
+
// Resolve the approval status.
|
|
266
|
+
approvalStatus = _approvalStatusOf({projectId: projectId, ruleset: ruleset});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/// @notice The ruleset that's up next for a project.
|
|
270
|
+
/// @dev If an upcoming ruleset is not found for the project, returns an empty ruleset with all properties set to 0.
|
|
271
|
+
/// @param projectId The ID of the project to get the upcoming ruleset of.
|
|
272
|
+
/// @return ruleset The struct for the project's upcoming ruleset.
|
|
273
|
+
function upcomingOf(uint256 projectId) external view override returns (JBRuleset memory ruleset) {
|
|
274
|
+
// If the project does not have a latest ruleset, return an empty struct.
|
|
275
|
+
// slither-disable-next-line incorrect-equality
|
|
276
|
+
if (latestRulesetIdOf[projectId] == 0) return _getStructFor({projectId: 0, rulesetId: 0});
|
|
277
|
+
|
|
278
|
+
// Get a reference to the upcoming approvable ruleset's ID.
|
|
279
|
+
uint256 upcomingApprovableRulesetId = _upcomingApprovableRulesetIdOf(projectId);
|
|
280
|
+
|
|
281
|
+
// Keep a reference to its approval status.
|
|
282
|
+
JBApprovalStatus approvalStatus;
|
|
283
|
+
|
|
284
|
+
// If an upcoming approvable ruleset has been queued, and it's approval status is Approved or ApprovalExpected,
|
|
285
|
+
// return its ruleset struct
|
|
286
|
+
if (upcomingApprovableRulesetId != 0) {
|
|
287
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: upcomingApprovableRulesetId});
|
|
288
|
+
|
|
289
|
+
// Get a reference to the approval status.
|
|
290
|
+
approvalStatus = _approvalStatusOf({projectId: projectId, ruleset: ruleset});
|
|
291
|
+
|
|
292
|
+
// If the approval hook is empty, expects approval, or has approved the ruleset, return it.
|
|
293
|
+
if (
|
|
294
|
+
// slither-disable-next-line incorrect-equality
|
|
295
|
+
approvalStatus == JBApprovalStatus.Approved || approvalStatus == JBApprovalStatus.ApprovalExpected
|
|
296
|
+
|| approvalStatus == JBApprovalStatus.Empty
|
|
297
|
+
) return ruleset;
|
|
298
|
+
|
|
299
|
+
// Resolve the ruleset for the ruleset the upcoming approvable ruleset was based on.
|
|
300
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: ruleset.basedOnId});
|
|
301
|
+
} else {
|
|
302
|
+
// Resolve the ruleset for the latest queued ruleset.
|
|
303
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: latestRulesetIdOf[projectId]});
|
|
304
|
+
|
|
305
|
+
// If the latest ruleset starts in the future, it must start in the distant future
|
|
306
|
+
// Since its not the upcoming approvable ruleset. In this case, base the upcoming ruleset on the base
|
|
307
|
+
// ruleset.
|
|
308
|
+
while (ruleset.start > block.timestamp) {
|
|
309
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: ruleset.basedOnId});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// There's no queued if the current has a duration of 0.
|
|
314
|
+
// slither-disable-next-line incorrect-equality
|
|
315
|
+
if (ruleset.duration == 0) return _getStructFor({projectId: 0, rulesetId: 0});
|
|
316
|
+
|
|
317
|
+
// Get a reference to the approval status.
|
|
318
|
+
approvalStatus = _approvalStatusOf({projectId: projectId, ruleset: ruleset});
|
|
319
|
+
|
|
320
|
+
// Check to see if this ruleset's approval hook hasn't failed.
|
|
321
|
+
// If so, return a ruleset based on it.
|
|
322
|
+
// slither-disable-next-line incorrect-equality
|
|
323
|
+
if (approvalStatus == JBApprovalStatus.Approved || approvalStatus == JBApprovalStatus.Empty) {
|
|
324
|
+
return _simulateCycledRulesetBasedOn({projectId: projectId, baseRuleset: ruleset, allowMidRuleset: false});
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Get the ruleset of its base ruleset, which carries the last approved configuration.
|
|
328
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: ruleset.basedOnId});
|
|
329
|
+
|
|
330
|
+
// There's no queued if the base, which must still be the current, has a duration of 0.
|
|
331
|
+
// slither-disable-next-line incorrect-equality
|
|
332
|
+
if (ruleset.duration == 0) return _getStructFor({projectId: 0, rulesetId: 0});
|
|
333
|
+
|
|
334
|
+
// Return a simulated cycled ruleset.
|
|
335
|
+
return _simulateCycledRulesetBasedOn({projectId: projectId, baseRuleset: ruleset, allowMidRuleset: false});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
//*********************************************************************//
|
|
339
|
+
// --------------------------- public views -------------------------- //
|
|
340
|
+
//*********************************************************************//
|
|
341
|
+
|
|
342
|
+
/// @notice The cycle number of the next ruleset given the specified ruleset.
|
|
343
|
+
/// @dev Each time a ruleset starts, whether it was queued or cycled over, the cycle number is incremented by 1.
|
|
344
|
+
/// @param baseRulesetCycleNumber The cycle number of the base ruleset.
|
|
345
|
+
/// @param baseRulesetStart The start time of the base ruleset.
|
|
346
|
+
/// @param baseRulesetDuration The duration of the base ruleset.
|
|
347
|
+
/// @param start The start time of the ruleset to derive a cycle number for.
|
|
348
|
+
/// @return The ruleset's cycle number.
|
|
349
|
+
function deriveCycleNumberFrom(
|
|
350
|
+
uint256 baseRulesetCycleNumber,
|
|
351
|
+
uint256 baseRulesetStart,
|
|
352
|
+
uint256 baseRulesetDuration,
|
|
353
|
+
uint256 start
|
|
354
|
+
)
|
|
355
|
+
public
|
|
356
|
+
pure
|
|
357
|
+
returns (uint256)
|
|
358
|
+
{
|
|
359
|
+
// A subsequent ruleset to one with a duration of 0 should be the next number.
|
|
360
|
+
// slither-disable-next-line incorrect-equality
|
|
361
|
+
if (baseRulesetDuration == 0) {
|
|
362
|
+
return baseRulesetCycleNumber + 1;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// The difference between the start of the base ruleset and the proposed start.
|
|
366
|
+
uint256 startDistance = start - baseRulesetStart;
|
|
367
|
+
|
|
368
|
+
// Find the number of base rulesets that fit in the start distance.
|
|
369
|
+
return baseRulesetCycleNumber + (startDistance / baseRulesetDuration);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/// @notice The date that is the nearest multiple of the base ruleset's duration from the start of the next cycle.
|
|
373
|
+
/// @param baseRulesetStart The start time of the base ruleset.
|
|
374
|
+
/// @param baseRulesetDuration The duration of the base ruleset.
|
|
375
|
+
/// @param mustStartAtOrAfter The earliest time the next ruleset can start. The ruleset cannot start before this
|
|
376
|
+
/// timestamp.
|
|
377
|
+
/// @return start The next start time.
|
|
378
|
+
function deriveStartFrom(
|
|
379
|
+
uint256 baseRulesetStart,
|
|
380
|
+
uint256 baseRulesetDuration,
|
|
381
|
+
uint256 mustStartAtOrAfter
|
|
382
|
+
)
|
|
383
|
+
public
|
|
384
|
+
pure
|
|
385
|
+
returns (uint256 start)
|
|
386
|
+
{
|
|
387
|
+
// A subsequent ruleset to one with a duration of 0 should start as soon as possible.
|
|
388
|
+
// slither-disable-next-line incorrect-equality
|
|
389
|
+
if (baseRulesetDuration == 0) return mustStartAtOrAfter;
|
|
390
|
+
|
|
391
|
+
// The time when the ruleset immediately after the specified ruleset starts.
|
|
392
|
+
uint256 nextImmediateStart = baseRulesetStart + baseRulesetDuration;
|
|
393
|
+
|
|
394
|
+
// If the next immediate start is now or in the future, return it.
|
|
395
|
+
if (nextImmediateStart >= mustStartAtOrAfter) {
|
|
396
|
+
return nextImmediateStart;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// The amount of seconds since the `mustStartAtOrAfter` time which results in a start time that might satisfy
|
|
400
|
+
// the specified limits.
|
|
401
|
+
// slither-disable-next-line weak-prng
|
|
402
|
+
uint256 timeFromImmediateStartMultiple = (mustStartAtOrAfter - nextImmediateStart) % baseRulesetDuration;
|
|
403
|
+
|
|
404
|
+
// A reference to the first possible start timestamp.
|
|
405
|
+
start = mustStartAtOrAfter - timeFromImmediateStartMultiple;
|
|
406
|
+
|
|
407
|
+
// Add increments of duration as necessary to satisfy the threshold.
|
|
408
|
+
while (mustStartAtOrAfter > start) {
|
|
409
|
+
start += baseRulesetDuration;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/// @notice The accumulated weight change since the specified ruleset.
|
|
414
|
+
/// @param projectId The ID of the project to which the ruleset weights apply.
|
|
415
|
+
/// @param baseRulesetStart The start time of the base ruleset.
|
|
416
|
+
/// @param baseRulesetDuration The duration of the base ruleset.
|
|
417
|
+
/// @param baseRulesetWeight The weight of the base ruleset.
|
|
418
|
+
/// @param baseRulesetWeightCutPercent The weight cut percent of the base ruleset.
|
|
419
|
+
/// @param baseRulesetCacheId The ID of the ruleset to base the calculation on (the previous ruleset).
|
|
420
|
+
/// @param start The start time of the ruleset to derive a weight for.
|
|
421
|
+
/// @return weight The derived weight, as a fixed point number with 18 decimals.
|
|
422
|
+
function deriveWeightFrom(
|
|
423
|
+
uint256 projectId,
|
|
424
|
+
uint256 baseRulesetStart,
|
|
425
|
+
uint256 baseRulesetDuration,
|
|
426
|
+
uint256 baseRulesetWeight,
|
|
427
|
+
uint256 baseRulesetWeightCutPercent,
|
|
428
|
+
uint256 baseRulesetCacheId,
|
|
429
|
+
uint256 start
|
|
430
|
+
)
|
|
431
|
+
public
|
|
432
|
+
view
|
|
433
|
+
returns (uint256 weight)
|
|
434
|
+
{
|
|
435
|
+
// A subsequent ruleset to one with a duration of 0 should have the next possible weight.
|
|
436
|
+
// slither-disable-next-line incorrect-equality
|
|
437
|
+
if (baseRulesetDuration == 0) {
|
|
438
|
+
return mulDiv(
|
|
439
|
+
baseRulesetWeight,
|
|
440
|
+
JBConstants.MAX_WEIGHT_CUT_PERCENT - baseRulesetWeightCutPercent,
|
|
441
|
+
JBConstants.MAX_WEIGHT_CUT_PERCENT
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// The weight should be based off the base ruleset's weight.
|
|
446
|
+
weight = baseRulesetWeight;
|
|
447
|
+
|
|
448
|
+
// If the weight cut percent is 0, the weight doesn't change.
|
|
449
|
+
// slither-disable-next-line incorrect-equality
|
|
450
|
+
if (baseRulesetWeightCutPercent == 0) return weight;
|
|
451
|
+
|
|
452
|
+
// The difference between the start of the base ruleset and the proposed start.
|
|
453
|
+
uint256 startDistance = start - baseRulesetStart;
|
|
454
|
+
|
|
455
|
+
// Apply the base ruleset's weight cut percent for each ruleset that has passed.
|
|
456
|
+
uint256 weightCutMultiple;
|
|
457
|
+
unchecked {
|
|
458
|
+
weightCutMultiple = startDistance / baseRulesetDuration; // Non-null duration is excluded above
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Check the cache if needed.
|
|
462
|
+
if (baseRulesetCacheId > 0 && weightCutMultiple > _WEIGHT_CUT_MULTIPLE_CACHE_LOOKUP_THRESHOLD) {
|
|
463
|
+
// Get a cached weight for the rulesetId.
|
|
464
|
+
JBRulesetWeightCache memory cache = _weightCacheOf[projectId][baseRulesetCacheId];
|
|
465
|
+
|
|
466
|
+
// If a cached value is available, use it.
|
|
467
|
+
if (cache.weightCutMultiple > 0) {
|
|
468
|
+
// Set the starting weight to be the cached value.
|
|
469
|
+
weight = cache.weight;
|
|
470
|
+
|
|
471
|
+
// Set the weight cut multiple to be the difference between the cached value and the total weight cut
|
|
472
|
+
// multiple that should be applied.
|
|
473
|
+
weightCutMultiple -= cache.weightCutMultiple;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// If too many iterations remain after cache lookup, require the cache to be populated first.
|
|
478
|
+
// This prevents gas exhaustion for short-duration rulesets with large cycle counts.
|
|
479
|
+
if (weightCutMultiple > _WEIGHT_CUT_MULTIPLE_CACHE_LOOKUP_THRESHOLD) {
|
|
480
|
+
revert JBRulesets_WeightCacheRequired(projectId);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
for (uint256 i; i < weightCutMultiple; i++) {
|
|
484
|
+
// The number of times to apply the weight cut percent.
|
|
485
|
+
// Base the new weight on the specified ruleset's weight.
|
|
486
|
+
weight = mulDiv(
|
|
487
|
+
weight,
|
|
488
|
+
JBConstants.MAX_WEIGHT_CUT_PERCENT - baseRulesetWeightCutPercent,
|
|
489
|
+
JBConstants.MAX_WEIGHT_CUT_PERCENT
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
// The calculation doesn't need to continue if the weight is 0.
|
|
493
|
+
if (weight == 0) break;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
//*********************************************************************//
|
|
498
|
+
// -------------------------- internal views ------------------------- //
|
|
499
|
+
//*********************************************************************//
|
|
500
|
+
|
|
501
|
+
/// @notice The approval status of a given ruleset for a given project ID.
|
|
502
|
+
/// @param projectId The ID of the project the ruleset belongs to.
|
|
503
|
+
/// @param ruleset The ruleset to get the approval status of.
|
|
504
|
+
/// @return The approval status of the project.
|
|
505
|
+
function _approvalStatusOf(uint256 projectId, JBRuleset memory ruleset) internal view returns (JBApprovalStatus) {
|
|
506
|
+
// If there is no ruleset ID to check the approval hook of, the approval hook is empty.
|
|
507
|
+
// slither-disable-next-line incorrect-equality
|
|
508
|
+
if (ruleset.basedOnId == 0) return JBApprovalStatus.Empty;
|
|
509
|
+
|
|
510
|
+
// Get the struct of the ruleset with the approval hook.
|
|
511
|
+
JBRuleset memory approvalHookRuleset = _getStructFor({projectId: projectId, rulesetId: ruleset.basedOnId});
|
|
512
|
+
|
|
513
|
+
// If there is no approval hook, it's considered empty.
|
|
514
|
+
if (approvalHookRuleset.approvalHook == IJBRulesetApprovalHook(address(0))) {
|
|
515
|
+
return JBApprovalStatus.Empty;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Return the approval hook's approval status.
|
|
519
|
+
// Wrap in try/catch to prevent a reverting approval hook from permanently freezing the project.
|
|
520
|
+
// Note: A malicious hook that consumes all gas (e.g. infinite loop) could still DoS via gas exhaustion.
|
|
521
|
+
// This is accepted risk since the project owner chose their own approval hook.
|
|
522
|
+
// slither-disable-next-line calls-loop
|
|
523
|
+
try approvalHookRuleset.approvalHook.approvalStatusOf({projectId: projectId, ruleset: ruleset}) returns (
|
|
524
|
+
JBApprovalStatus status
|
|
525
|
+
) {
|
|
526
|
+
return status;
|
|
527
|
+
} catch {
|
|
528
|
+
return JBApprovalStatus.Failed;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/// @notice The ID of the ruleset which has started and hasn't expired yet, whether or not it has been approved, for
|
|
533
|
+
/// a given project. If approved, this is the active ruleset.
|
|
534
|
+
/// @dev A value of 0 is returned if no ruleset was found.
|
|
535
|
+
/// @dev Assumes the project has a latest ruleset.
|
|
536
|
+
/// @param projectId The ID of the project to check for a currently approvable ruleset.
|
|
537
|
+
/// @return The ID of a currently approvable ruleset if one exists, or 0 if one doesn't exist.
|
|
538
|
+
function _currentlyApprovableRulesetIdOf(uint256 projectId) internal view returns (uint256) {
|
|
539
|
+
// Get a reference to the project's latest ruleset.
|
|
540
|
+
uint256 rulesetId = latestRulesetIdOf[projectId];
|
|
541
|
+
|
|
542
|
+
// Get the struct for the latest ruleset.
|
|
543
|
+
JBRuleset memory ruleset = _getStructFor({projectId: projectId, rulesetId: rulesetId});
|
|
544
|
+
|
|
545
|
+
// Loop through all most recently queued rulesets until an approvable one is found, or we've proven one can't
|
|
546
|
+
// exist.
|
|
547
|
+
do {
|
|
548
|
+
// If the latest ruleset is expired, return an empty ruleset.
|
|
549
|
+
// A ruleset with a duration of 0 cannot expire.
|
|
550
|
+
if (ruleset.duration != 0 && block.timestamp >= ruleset.start + ruleset.duration) {
|
|
551
|
+
return 0;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Return the ruleset's `rulesetId` if it has started.
|
|
555
|
+
if (block.timestamp >= ruleset.start) {
|
|
556
|
+
return ruleset.id;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: ruleset.basedOnId});
|
|
560
|
+
} while (ruleset.cycleNumber != 0);
|
|
561
|
+
|
|
562
|
+
return 0;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/// @notice Unpack a ruleset's packed stored values into an easy-to-work-with ruleset struct.
|
|
566
|
+
/// @param projectId The ID of the project the ruleset belongs to.
|
|
567
|
+
/// @param rulesetId The ID of the ruleset to get the full struct for.
|
|
568
|
+
/// @return ruleset A ruleset struct.
|
|
569
|
+
function _getStructFor(uint256 projectId, uint256 rulesetId) internal view returns (JBRuleset memory ruleset) {
|
|
570
|
+
// Return an empty ruleset if the specified `rulesetId` is 0.
|
|
571
|
+
// slither-disable-next-line incorrect-equality
|
|
572
|
+
if (rulesetId == 0) return ruleset;
|
|
573
|
+
|
|
574
|
+
ruleset.id = uint48(rulesetId);
|
|
575
|
+
|
|
576
|
+
uint256 packedIntrinsicProperties = _packedIntrinsicPropertiesOf[projectId][rulesetId];
|
|
577
|
+
|
|
578
|
+
// `weight` in bits 0-111 bits.
|
|
579
|
+
ruleset.weight = uint112(packedIntrinsicProperties);
|
|
580
|
+
// `basedOnId` in bits 112-159 bits.
|
|
581
|
+
ruleset.basedOnId = uint48(packedIntrinsicProperties >> 112);
|
|
582
|
+
// `start` in bits 160-207 bits.
|
|
583
|
+
ruleset.start = uint48(packedIntrinsicProperties >> 160);
|
|
584
|
+
// `cycleNumber` in bits 208-255 bits.
|
|
585
|
+
ruleset.cycleNumber = uint48(packedIntrinsicProperties >> 208);
|
|
586
|
+
|
|
587
|
+
uint256 packedUserProperties = _packedUserPropertiesOf[projectId][rulesetId];
|
|
588
|
+
|
|
589
|
+
// approval hook in bits 0-159 bits.
|
|
590
|
+
ruleset.approvalHook = IJBRulesetApprovalHook(address(uint160(packedUserProperties)));
|
|
591
|
+
// `duration` in bits 160-191 bits.
|
|
592
|
+
ruleset.duration = uint32(packedUserProperties >> 160);
|
|
593
|
+
// weight cut percent in bits 192-223 bits.
|
|
594
|
+
ruleset.weightCutPercent = uint32(packedUserProperties >> 192);
|
|
595
|
+
|
|
596
|
+
ruleset.metadata = _metadataOf[projectId][rulesetId];
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/// @notice A simulated view of the ruleset that would be created if the provided one cycled over (if the project
|
|
600
|
+
/// doesn't queue a new ruleset).
|
|
601
|
+
/// @dev Returns an empty ruleset if a ruleset can't be simulated based on the provided one.
|
|
602
|
+
/// @dev Assumes a simulated ruleset will never be based on a ruleset with a duration of 0.
|
|
603
|
+
/// @param projectId The ID of the project of the ruleset.
|
|
604
|
+
/// @param baseRuleset The ruleset that the simulated ruleset should be based on.
|
|
605
|
+
/// @param allowMidRuleset A flag indicating if the simulated ruleset is allowed to already be mid ruleset.
|
|
606
|
+
/// @return A simulated ruleset struct: the next ruleset by default. This will be overwritten if a new ruleset is
|
|
607
|
+
/// queued for the project.
|
|
608
|
+
function _simulateCycledRulesetBasedOn(
|
|
609
|
+
uint256 projectId,
|
|
610
|
+
JBRuleset memory baseRuleset,
|
|
611
|
+
bool allowMidRuleset
|
|
612
|
+
)
|
|
613
|
+
internal
|
|
614
|
+
view
|
|
615
|
+
returns (JBRuleset memory)
|
|
616
|
+
{
|
|
617
|
+
// Get the distance from the current time to the start of the next possible ruleset.
|
|
618
|
+
// If the simulated ruleset must not yet have started, the start time of the simulated ruleset must be in the
|
|
619
|
+
// future.
|
|
620
|
+
uint256 mustStartAtOrAfter = !allowMidRuleset
|
|
621
|
+
? block.timestamp + 1
|
|
622
|
+
: baseRuleset.duration >= block.timestamp ? 1 : block.timestamp - baseRuleset.duration + 1;
|
|
623
|
+
|
|
624
|
+
// Calculate what the start time should be.
|
|
625
|
+
uint256 start = deriveStartFrom({
|
|
626
|
+
baseRulesetStart: baseRuleset.start,
|
|
627
|
+
baseRulesetDuration: baseRuleset.duration,
|
|
628
|
+
mustStartAtOrAfter: mustStartAtOrAfter
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
// Calculate what the cycle number should be.
|
|
632
|
+
uint256 rulesetCycleNumber = deriveCycleNumberFrom({
|
|
633
|
+
baseRulesetCycleNumber: baseRuleset.cycleNumber,
|
|
634
|
+
baseRulesetStart: baseRuleset.start,
|
|
635
|
+
baseRulesetDuration: baseRuleset.duration,
|
|
636
|
+
start: start
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
return JBRuleset({
|
|
640
|
+
cycleNumber: uint48(rulesetCycleNumber),
|
|
641
|
+
id: baseRuleset.id,
|
|
642
|
+
basedOnId: baseRuleset.basedOnId,
|
|
643
|
+
start: uint48(start),
|
|
644
|
+
duration: baseRuleset.duration,
|
|
645
|
+
weight: uint112(
|
|
646
|
+
deriveWeightFrom({
|
|
647
|
+
projectId: projectId,
|
|
648
|
+
baseRulesetStart: baseRuleset.start,
|
|
649
|
+
baseRulesetDuration: baseRuleset.duration,
|
|
650
|
+
baseRulesetWeight: baseRuleset.weight,
|
|
651
|
+
baseRulesetWeightCutPercent: baseRuleset.weightCutPercent,
|
|
652
|
+
baseRulesetCacheId: baseRuleset.id,
|
|
653
|
+
start: start
|
|
654
|
+
})
|
|
655
|
+
),
|
|
656
|
+
weightCutPercent: baseRuleset.weightCutPercent,
|
|
657
|
+
approvalHook: baseRuleset.approvalHook,
|
|
658
|
+
metadata: baseRuleset.metadata
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/// @notice The ruleset up next for a project, if one exists, whether or not that ruleset has been approved.
|
|
663
|
+
/// @dev A value of 0 is returned if no ruleset was found.
|
|
664
|
+
/// @dev Assumes the project has a `latestRulesetIdOf` value.
|
|
665
|
+
/// @param projectId The ID of the project to check for an upcoming approvable ruleset.
|
|
666
|
+
/// @return rulesetId The `rulesetId` of the upcoming approvable ruleset if one exists, or 0 if one doesn't exist.
|
|
667
|
+
function _upcomingApprovableRulesetIdOf(uint256 projectId) internal view returns (uint256 rulesetId) {
|
|
668
|
+
// Get a reference to the ID of the project's latest ruleset.
|
|
669
|
+
rulesetId = latestRulesetIdOf[projectId];
|
|
670
|
+
|
|
671
|
+
// Get the struct for the latest ruleset.
|
|
672
|
+
JBRuleset memory ruleset = _getStructFor({projectId: projectId, rulesetId: rulesetId});
|
|
673
|
+
|
|
674
|
+
// There is no upcoming ruleset if the latest ruleset has already started.
|
|
675
|
+
// slither-disable-next-line incorrect-equality
|
|
676
|
+
if (block.timestamp >= ruleset.start) return 0;
|
|
677
|
+
|
|
678
|
+
// If this is the first ruleset, it is queued.
|
|
679
|
+
// slither-disable-next-line incorrect-equality
|
|
680
|
+
if (ruleset.cycleNumber == 1) return rulesetId;
|
|
681
|
+
|
|
682
|
+
// Get a reference to the ID of the ruleset the latest ruleset was based on.
|
|
683
|
+
uint256 basedOnId = ruleset.basedOnId;
|
|
684
|
+
|
|
685
|
+
// Get the necessary properties for the base ruleset.
|
|
686
|
+
JBRuleset memory baseRuleset;
|
|
687
|
+
|
|
688
|
+
// Find the base ruleset that is not still queued.
|
|
689
|
+
while (true) {
|
|
690
|
+
baseRuleset = _getStructFor({projectId: projectId, rulesetId: basedOnId});
|
|
691
|
+
|
|
692
|
+
// If the base ruleset starts in the future,
|
|
693
|
+
if (block.timestamp < baseRuleset.start) {
|
|
694
|
+
// Set the `rulesetId` to the one found.
|
|
695
|
+
rulesetId = baseRuleset.id;
|
|
696
|
+
// Check the ruleset it was based on in the next iteration.
|
|
697
|
+
basedOnId = baseRuleset.basedOnId;
|
|
698
|
+
} else {
|
|
699
|
+
// Break out of the loop when a base ruleset which has already started is found.
|
|
700
|
+
break;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// Get the ruleset struct for the ID found.
|
|
705
|
+
ruleset = _getStructFor({projectId: projectId, rulesetId: rulesetId});
|
|
706
|
+
|
|
707
|
+
// If the latest ruleset doesn't start until after another base ruleset return 0.
|
|
708
|
+
if (baseRuleset.duration != 0 && block.timestamp < ruleset.start - baseRuleset.duration) {
|
|
709
|
+
return 0;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
//*********************************************************************//
|
|
714
|
+
// ---------------------- external transactions ---------------------- //
|
|
715
|
+
//*********************************************************************//
|
|
716
|
+
|
|
717
|
+
/// @notice Queues the upcoming approvable ruleset for the specified project.
|
|
718
|
+
/// @dev Only a project's current controller can queue its rulesets.
|
|
719
|
+
/// @param projectId The ID of the project to queue the ruleset for.
|
|
720
|
+
/// @param duration The number of seconds the ruleset lasts for, after which a new ruleset starts.
|
|
721
|
+
/// - A `duration` of 0 means this ruleset will remain active until the project owner queues a new ruleset. That new
|
|
722
|
+
/// ruleset will start immediately.
|
|
723
|
+
/// - A ruleset with a non-zero `duration` applies until the duration ends – any newly queued rulesets will be
|
|
724
|
+
/// *queued* to take effect afterwards.
|
|
725
|
+
/// - If a duration ends and no new rulesets are queued, the ruleset rolls over to a new ruleset with the same rules
|
|
726
|
+
/// (except for a new `start` timestamp and a cut `weight`).
|
|
727
|
+
/// @param weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on.
|
|
728
|
+
/// Payment terminals generally use this to determine how many tokens should be minted when the project is paid.
|
|
729
|
+
/// @param weightCutPercent A fraction (out of `JBConstants.MAX_WEIGHT_CUT_PERCENT`) to reduce the next ruleset's
|
|
730
|
+
/// `weight`
|
|
731
|
+
/// by.
|
|
732
|
+
/// - If a ruleset specifies a non-zero `weight`, the `weightCutPercent` does not apply.
|
|
733
|
+
/// - If the `weightCutPercent` is 0, the `weight` stays the same.
|
|
734
|
+
/// - If the `weightCutPercent` is 10% of `JBConstants.MAX_WEIGHT_CUT_PERCENT`, next ruleset's `weight` will be 90%
|
|
735
|
+
/// of the
|
|
736
|
+
/// current
|
|
737
|
+
/// one.
|
|
738
|
+
/// @param approvalHook A contract which dictates whether a proposed ruleset should be accepted or rejected. It can
|
|
739
|
+
/// be used to constrain a project owner's ability to change ruleset parameters over time.
|
|
740
|
+
/// @param metadata Arbitrary extra data to associate with this ruleset. This metadata is not used by `JBRulesets`.
|
|
741
|
+
/// @param mustStartAtOrAfter The earliest time the ruleset can start. The ruleset cannot start before this
|
|
742
|
+
/// timestamp.
|
|
743
|
+
/// @return The struct of the new ruleset.
|
|
744
|
+
function queueFor(
|
|
745
|
+
uint256 projectId,
|
|
746
|
+
uint256 duration,
|
|
747
|
+
uint256 weight,
|
|
748
|
+
uint256 weightCutPercent,
|
|
749
|
+
IJBRulesetApprovalHook approvalHook,
|
|
750
|
+
uint256 metadata,
|
|
751
|
+
uint256 mustStartAtOrAfter
|
|
752
|
+
)
|
|
753
|
+
external
|
|
754
|
+
override
|
|
755
|
+
onlyControllerOf(projectId)
|
|
756
|
+
returns (JBRuleset memory)
|
|
757
|
+
{
|
|
758
|
+
// Duration must fit in a uint32.
|
|
759
|
+
if (duration > type(uint32).max) revert JBRulesets_InvalidRulesetDuration(duration, type(uint32).max);
|
|
760
|
+
|
|
761
|
+
// Weight cut percent must be less than or equal to 100%.
|
|
762
|
+
if (weightCutPercent > JBConstants.MAX_WEIGHT_CUT_PERCENT) {
|
|
763
|
+
revert JBRulesets_InvalidWeightCutPercent(weightCutPercent);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// Weight must fit into a uint112.
|
|
767
|
+
if (weight > type(uint112).max) revert JBRulesets_InvalidWeight(weight, type(uint112).max);
|
|
768
|
+
|
|
769
|
+
// If the start date is not set, set it to be the current timestamp.
|
|
770
|
+
if (mustStartAtOrAfter == 0) {
|
|
771
|
+
mustStartAtOrAfter = block.timestamp;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// Make sure the min start date fits in a uint48, and that the start date of the following ruleset will also fit
|
|
775
|
+
// within the max.
|
|
776
|
+
if (mustStartAtOrAfter + duration > type(uint48).max) {
|
|
777
|
+
revert JBRulesets_InvalidRulesetEndTime(mustStartAtOrAfter + duration, type(uint48).max);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// Approval hook should be a valid contract, supporting the correct interface
|
|
781
|
+
if (approvalHook != IJBRulesetApprovalHook(address(0))) {
|
|
782
|
+
// Revert if there isn't a contract at the address
|
|
783
|
+
if (address(approvalHook).code.length == 0) revert JBRulesets_InvalidRulesetApprovalHook(approvalHook);
|
|
784
|
+
|
|
785
|
+
// Make sure the approval hook supports the expected interface.
|
|
786
|
+
try approvalHook.supportsInterface(type(IJBRulesetApprovalHook).interfaceId) returns (bool doesSupport) {
|
|
787
|
+
if (!doesSupport) revert JBRulesets_InvalidRulesetApprovalHook(approvalHook); // Contract exists at the
|
|
788
|
+
// address but
|
|
789
|
+
// with the
|
|
790
|
+
// wrong interface
|
|
791
|
+
} catch {
|
|
792
|
+
revert JBRulesets_InvalidRulesetApprovalHook(approvalHook); // No ERC165 support
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// Get a reference to the latest ruleset's ID.
|
|
797
|
+
uint256 latestId = latestRulesetIdOf[projectId];
|
|
798
|
+
|
|
799
|
+
// The new rulesetId timestamp is now, or an increment from now if the current timestamp is taken.
|
|
800
|
+
uint256 rulesetId = latestId >= block.timestamp ? latestId + 1 : block.timestamp;
|
|
801
|
+
|
|
802
|
+
// Set up the ruleset by configuring intrinsic properties.
|
|
803
|
+
_configureIntrinsicPropertiesFor({
|
|
804
|
+
projectId: projectId, rulesetId: rulesetId, weight: weight, mustStartAtOrAfter: mustStartAtOrAfter
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
// Efficiently stores the ruleset's user-defined properties.
|
|
808
|
+
// If all user config properties are zero, no need to store anything as the default value will have the same
|
|
809
|
+
// outcome.
|
|
810
|
+
if (approvalHook != IJBRulesetApprovalHook(address(0)) || duration > 0 || weightCutPercent > 0) {
|
|
811
|
+
// approval hook in bits 0-159 bytes.
|
|
812
|
+
uint256 packed = uint160(address(approvalHook));
|
|
813
|
+
|
|
814
|
+
// duration in bits 160-191 bytes.
|
|
815
|
+
packed |= duration << 160;
|
|
816
|
+
|
|
817
|
+
// weightCutPercent in bits 192-223 bytes.
|
|
818
|
+
packed |= weightCutPercent << 192;
|
|
819
|
+
|
|
820
|
+
// Set in storage.
|
|
821
|
+
_packedUserPropertiesOf[projectId][rulesetId] = packed;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// Set the metadata if needed.
|
|
825
|
+
if (metadata > 0) _metadataOf[projectId][rulesetId] = metadata;
|
|
826
|
+
|
|
827
|
+
emit RulesetQueued({
|
|
828
|
+
rulesetId: rulesetId,
|
|
829
|
+
projectId: projectId,
|
|
830
|
+
duration: duration,
|
|
831
|
+
weight: weight,
|
|
832
|
+
weightCutPercent: weightCutPercent,
|
|
833
|
+
approvalHook: approvalHook,
|
|
834
|
+
metadata: metadata,
|
|
835
|
+
mustStartAtOrAfter: mustStartAtOrAfter,
|
|
836
|
+
caller: msg.sender
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
// Return the struct for the new ruleset's ID.
|
|
840
|
+
return _getStructFor({projectId: projectId, rulesetId: rulesetId});
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/// @notice Cache the value of the ruleset weight.
|
|
844
|
+
/// @param projectId The ID of the project having its ruleset weight cached.
|
|
845
|
+
function updateRulesetWeightCache(uint256 projectId) external override {
|
|
846
|
+
// Keep a reference to the struct for the latest queued ruleset.
|
|
847
|
+
// The cached value will be based on this struct.
|
|
848
|
+
JBRuleset memory latestQueuedRuleset =
|
|
849
|
+
_getStructFor({projectId: projectId, rulesetId: latestRulesetIdOf[projectId]});
|
|
850
|
+
|
|
851
|
+
// Nothing to cache if the latest ruleset doesn't have a duration or a weight cut percent.
|
|
852
|
+
// slither-disable-next-line incorrect-equality
|
|
853
|
+
if (latestQueuedRuleset.duration == 0 || latestQueuedRuleset.weightCutPercent == 0) return;
|
|
854
|
+
|
|
855
|
+
// Get a reference to the current cache.
|
|
856
|
+
JBRulesetWeightCache storage cache = _weightCacheOf[projectId][latestQueuedRuleset.id];
|
|
857
|
+
|
|
858
|
+
// Determine the largest start timestamp the cache can be filled to.
|
|
859
|
+
// Cap the advance to the cache lookup threshold per call to stay within the iteration limit in
|
|
860
|
+
// deriveWeightFrom.
|
|
861
|
+
// Multiple calls are needed to advance the cache for large cycle gaps.
|
|
862
|
+
uint256 maxStart = latestQueuedRuleset.start
|
|
863
|
+
+ (cache.weightCutMultiple + _WEIGHT_CUT_MULTIPLE_CACHE_LOOKUP_THRESHOLD) * latestQueuedRuleset.duration;
|
|
864
|
+
|
|
865
|
+
// Determine the start timestamp to derive a weight from for the cache.
|
|
866
|
+
uint256 start = block.timestamp < maxStart ? block.timestamp : maxStart;
|
|
867
|
+
|
|
868
|
+
// The difference between the start of the latest queued ruleset and the start of the ruleset we're caching the
|
|
869
|
+
// weight of.
|
|
870
|
+
uint256 startDistance = start - latestQueuedRuleset.start;
|
|
871
|
+
|
|
872
|
+
// Calculate the weight cut multiple.
|
|
873
|
+
uint168 weightCutMultiple;
|
|
874
|
+
unchecked {
|
|
875
|
+
weightCutMultiple = uint168(startDistance / latestQueuedRuleset.duration);
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// Store the new values.
|
|
879
|
+
cache.weight = uint112(
|
|
880
|
+
deriveWeightFrom({
|
|
881
|
+
projectId: projectId,
|
|
882
|
+
baseRulesetStart: latestQueuedRuleset.start,
|
|
883
|
+
baseRulesetDuration: latestQueuedRuleset.duration,
|
|
884
|
+
baseRulesetWeight: latestQueuedRuleset.weight,
|
|
885
|
+
baseRulesetWeightCutPercent: latestQueuedRuleset.weightCutPercent,
|
|
886
|
+
baseRulesetCacheId: latestQueuedRuleset.id,
|
|
887
|
+
start: start
|
|
888
|
+
})
|
|
889
|
+
);
|
|
890
|
+
cache.weightCutMultiple = weightCutMultiple;
|
|
891
|
+
|
|
892
|
+
emit WeightCacheUpdated({
|
|
893
|
+
projectId: projectId, weight: cache.weight, weightCutMultiple: weightCutMultiple, caller: msg.sender
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
//*********************************************************************//
|
|
898
|
+
// ------------------------ internal functions ----------------------- //
|
|
899
|
+
//*********************************************************************//
|
|
900
|
+
|
|
901
|
+
/// @notice Updates the latest ruleset for this project if it exists. If there is no ruleset, initializes one.
|
|
902
|
+
/// @param projectId The ID of the project to update the latest ruleset for.
|
|
903
|
+
/// @param rulesetId The timestamp of when the ruleset was queued.
|
|
904
|
+
/// @param weight The weight to store in the queued ruleset.
|
|
905
|
+
/// @param mustStartAtOrAfter The earliest time the ruleset can start. The ruleset cannot start before this
|
|
906
|
+
/// timestamp.
|
|
907
|
+
function _configureIntrinsicPropertiesFor(
|
|
908
|
+
uint256 projectId,
|
|
909
|
+
uint256 rulesetId,
|
|
910
|
+
uint256 weight,
|
|
911
|
+
uint256 mustStartAtOrAfter
|
|
912
|
+
)
|
|
913
|
+
internal
|
|
914
|
+
{
|
|
915
|
+
// Keep a reference to the project's latest ruleset's ID.
|
|
916
|
+
uint256 latestId = latestRulesetIdOf[projectId];
|
|
917
|
+
|
|
918
|
+
// If the project doesn't have a ruleset yet, initialize one.
|
|
919
|
+
// slither-disable-next-line incorrect-equality
|
|
920
|
+
if (latestId == 0) {
|
|
921
|
+
// Use an empty ruleset as the base.
|
|
922
|
+
return _initializeRulesetFor({
|
|
923
|
+
projectId: projectId,
|
|
924
|
+
baseRuleset: _getStructFor({projectId: 0, rulesetId: 0}),
|
|
925
|
+
rulesetId: rulesetId,
|
|
926
|
+
mustStartAtOrAfter: mustStartAtOrAfter,
|
|
927
|
+
weight: weight
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// Get a reference to the latest ruleset's struct.
|
|
932
|
+
JBRuleset memory baseRuleset = _getStructFor({projectId: projectId, rulesetId: latestId});
|
|
933
|
+
|
|
934
|
+
// Get a reference to the approval status.
|
|
935
|
+
JBApprovalStatus approvalStatus = _approvalStatusOf({projectId: projectId, ruleset: baseRuleset});
|
|
936
|
+
|
|
937
|
+
// If the base ruleset has started but wasn't approved if a approval hook exists
|
|
938
|
+
// OR it hasn't started but is currently approved
|
|
939
|
+
// OR it hasn't started but it is likely to be approved and takes place before the proposed one,
|
|
940
|
+
// set the struct to be the ruleset it's based on, which carries the latest approved ruleset.
|
|
941
|
+
if (
|
|
942
|
+
(block.timestamp >= baseRuleset.start
|
|
943
|
+
&& approvalStatus != JBApprovalStatus.Approved
|
|
944
|
+
&& approvalStatus != JBApprovalStatus.Empty)
|
|
945
|
+
|| (block.timestamp < baseRuleset.start
|
|
946
|
+
&& mustStartAtOrAfter < baseRuleset.start + baseRuleset.duration
|
|
947
|
+
&& approvalStatus != JBApprovalStatus.Approved)
|
|
948
|
+
|| (block.timestamp < baseRuleset.start
|
|
949
|
+
&& mustStartAtOrAfter >= baseRuleset.start + baseRuleset.duration
|
|
950
|
+
&& approvalStatus != JBApprovalStatus.Approved
|
|
951
|
+
&& approvalStatus != JBApprovalStatus.ApprovalExpected
|
|
952
|
+
&& approvalStatus != JBApprovalStatus.Empty)
|
|
953
|
+
) {
|
|
954
|
+
baseRuleset = _getStructFor({projectId: projectId, rulesetId: baseRuleset.basedOnId});
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// Make sure the ruleset starts after the base ruleset.
|
|
958
|
+
if (baseRuleset.start > mustStartAtOrAfter) mustStartAtOrAfter = baseRuleset.start;
|
|
959
|
+
|
|
960
|
+
// The time when the duration of the base ruleset's approval hook has finished.
|
|
961
|
+
// If the provided ruleset has no approval hook, return 0 (no constraint on start time).
|
|
962
|
+
uint256 timestampAfterApprovalHook;
|
|
963
|
+
if (baseRuleset.approvalHook != IJBRulesetApprovalHook(address(0))) {
|
|
964
|
+
try baseRuleset.approvalHook.DURATION() returns (uint256 duration) {
|
|
965
|
+
timestampAfterApprovalHook = rulesetId + duration;
|
|
966
|
+
} catch {
|
|
967
|
+
// If DURATION() reverts, treat as no approval hook constraint.
|
|
968
|
+
timestampAfterApprovalHook = 0;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
_initializeRulesetFor({
|
|
973
|
+
projectId: projectId,
|
|
974
|
+
baseRuleset: baseRuleset,
|
|
975
|
+
rulesetId: rulesetId,
|
|
976
|
+
// Can only start after the approval hook.
|
|
977
|
+
mustStartAtOrAfter: timestampAfterApprovalHook > mustStartAtOrAfter
|
|
978
|
+
? timestampAfterApprovalHook
|
|
979
|
+
: mustStartAtOrAfter,
|
|
980
|
+
weight: weight
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/// @notice Initializes a ruleset with the specified properties.
|
|
985
|
+
/// @param projectId The ID of the project to initialize the ruleset for.
|
|
986
|
+
/// @param baseRuleset The ruleset struct to base the newly initialized one on.
|
|
987
|
+
/// @param rulesetId The `rulesetId` for the ruleset being initialized.
|
|
988
|
+
/// @param mustStartAtOrAfter The earliest time the ruleset can start. The ruleset cannot start before this
|
|
989
|
+
/// timestamp.
|
|
990
|
+
/// @param weight The weight to give the newly initialized ruleset.
|
|
991
|
+
function _initializeRulesetFor(
|
|
992
|
+
uint256 projectId,
|
|
993
|
+
JBRuleset memory baseRuleset,
|
|
994
|
+
uint256 rulesetId,
|
|
995
|
+
uint256 mustStartAtOrAfter,
|
|
996
|
+
uint256 weight
|
|
997
|
+
)
|
|
998
|
+
internal
|
|
999
|
+
{
|
|
1000
|
+
// If there is no base, initialize a first ruleset.
|
|
1001
|
+
// slither-disable-next-line incorrect-equality
|
|
1002
|
+
if (baseRuleset.cycleNumber == 0) {
|
|
1003
|
+
// Set fresh intrinsic properties.
|
|
1004
|
+
_packAndStoreIntrinsicPropertiesOf({
|
|
1005
|
+
rulesetId: rulesetId,
|
|
1006
|
+
projectId: projectId,
|
|
1007
|
+
rulesetCycleNumber: 1,
|
|
1008
|
+
weight: weight,
|
|
1009
|
+
basedOnId: baseRuleset.id,
|
|
1010
|
+
start: mustStartAtOrAfter
|
|
1011
|
+
});
|
|
1012
|
+
} else {
|
|
1013
|
+
// Derive the correct next start time from the base.
|
|
1014
|
+
uint256 start = deriveStartFrom({
|
|
1015
|
+
baseRulesetStart: baseRuleset.start,
|
|
1016
|
+
baseRulesetDuration: baseRuleset.duration,
|
|
1017
|
+
mustStartAtOrAfter: mustStartAtOrAfter
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
// A weight of 1 is a special case that represents inheriting the cut weight of the previous
|
|
1021
|
+
// ruleset.
|
|
1022
|
+
weight = weight == 1
|
|
1023
|
+
? deriveWeightFrom({
|
|
1024
|
+
projectId: projectId,
|
|
1025
|
+
baseRulesetStart: baseRuleset.start,
|
|
1026
|
+
baseRulesetDuration: baseRuleset.duration,
|
|
1027
|
+
baseRulesetWeight: baseRuleset.weight,
|
|
1028
|
+
baseRulesetWeightCutPercent: baseRuleset.weightCutPercent,
|
|
1029
|
+
baseRulesetCacheId: baseRuleset.id,
|
|
1030
|
+
start: start
|
|
1031
|
+
})
|
|
1032
|
+
: weight;
|
|
1033
|
+
|
|
1034
|
+
// Derive the correct ruleset cycle number.
|
|
1035
|
+
uint256 rulesetCycleNumber = deriveCycleNumberFrom({
|
|
1036
|
+
baseRulesetCycleNumber: baseRuleset.cycleNumber,
|
|
1037
|
+
baseRulesetStart: baseRuleset.start,
|
|
1038
|
+
baseRulesetDuration: baseRuleset.duration,
|
|
1039
|
+
start: start
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
// Update the intrinsic properties.
|
|
1043
|
+
_packAndStoreIntrinsicPropertiesOf({
|
|
1044
|
+
rulesetId: rulesetId,
|
|
1045
|
+
projectId: projectId,
|
|
1046
|
+
rulesetCycleNumber: rulesetCycleNumber,
|
|
1047
|
+
weight: weight,
|
|
1048
|
+
basedOnId: baseRuleset.id,
|
|
1049
|
+
start: start
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// Set the project's latest ruleset configuration.
|
|
1054
|
+
latestRulesetIdOf[projectId] = rulesetId;
|
|
1055
|
+
|
|
1056
|
+
emit RulesetInitialized({
|
|
1057
|
+
rulesetId: rulesetId, projectId: projectId, basedOnId: baseRuleset.id, caller: msg.sender
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
/// @notice Efficiently stores the provided intrinsic properties of a ruleset.
|
|
1062
|
+
/// @param rulesetId The `rulesetId` of the ruleset to pack and store for.
|
|
1063
|
+
/// @param projectId The ID of the project the ruleset belongs to.
|
|
1064
|
+
/// @param rulesetCycleNumber The cycle number of the ruleset.
|
|
1065
|
+
/// @param weight The weight of the ruleset.
|
|
1066
|
+
/// @param basedOnId The `rulesetId` of the ruleset this ruleset was based on.
|
|
1067
|
+
/// @param start The start time of this ruleset.
|
|
1068
|
+
function _packAndStoreIntrinsicPropertiesOf(
|
|
1069
|
+
uint256 rulesetId,
|
|
1070
|
+
uint256 projectId,
|
|
1071
|
+
uint256 rulesetCycleNumber,
|
|
1072
|
+
uint256 weight,
|
|
1073
|
+
uint256 basedOnId,
|
|
1074
|
+
uint256 start
|
|
1075
|
+
)
|
|
1076
|
+
internal
|
|
1077
|
+
{
|
|
1078
|
+
// `weight` in bits 0-111.
|
|
1079
|
+
uint256 packed = weight;
|
|
1080
|
+
|
|
1081
|
+
// `basedOnId` in bits 112-159.
|
|
1082
|
+
packed |= basedOnId << 112;
|
|
1083
|
+
|
|
1084
|
+
// `start` in bits 160-207.
|
|
1085
|
+
packed |= start << 160;
|
|
1086
|
+
|
|
1087
|
+
// cycle number in bits 208-255.
|
|
1088
|
+
packed |= rulesetCycleNumber << 208;
|
|
1089
|
+
|
|
1090
|
+
// Store the packed value.
|
|
1091
|
+
_packedIntrinsicPropertiesOf[projectId][rulesetId] = packed;
|
|
1092
|
+
}
|
|
1093
|
+
}
|