@bananapus/core-v6 0.0.37 → 0.0.39
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/foundry.lock +1 -7
- package/foundry.toml +1 -1
- package/package.json +19 -7
- package/src/JBChainlinkV3PriceFeed.sol +4 -1
- package/src/JBChainlinkV3SequencerPriceFeed.sol +4 -2
- package/src/JBController.sol +71 -44
- package/src/JBDeadline.sol +4 -4
- package/src/JBDirectory.sol +34 -32
- package/src/JBERC20.sol +5 -4
- package/src/JBFeelessAddresses.sol +6 -3
- package/src/JBFundAccessLimits.sol +25 -21
- package/src/JBMultiTerminal.sol +121 -84
- package/src/JBPermissions.sol +34 -37
- package/src/JBPrices.sol +23 -18
- package/src/JBProjects.sol +6 -3
- package/src/JBRulesets.sol +44 -41
- package/src/JBSplits.sol +18 -16
- package/src/JBTerminalStore.sol +32 -25
- package/src/JBTokens.sol +36 -26
- package/src/abstract/JBControlled.sol +3 -1
- package/src/abstract/JBPermissioned.sol +3 -1
- package/src/enums/JBApprovalStatus.sol +7 -1
- package/src/interfaces/IJBController.sol +7 -3
- package/src/interfaces/IJBDirectory.sol +3 -1
- package/src/interfaces/IJBMultiTerminal.sol +3 -2
- package/src/interfaces/IJBPermissions.sol +2 -1
- package/src/interfaces/IJBPrices.sol +3 -1
- package/src/interfaces/IJBRulesets.sol +2 -1
- package/src/interfaces/IJBSplits.sol +2 -1
- package/src/interfaces/IJBTerminal.sol +3 -1
- package/src/interfaces/IJBTerminalStore.sol +3 -1
- package/src/interfaces/IJBTokens.sol +2 -1
- package/src/libraries/JBCashOuts.sol +6 -1
- package/src/libraries/JBConstants.sol +12 -3
- package/src/libraries/JBCurrencyIds.sol +2 -0
- package/src/libraries/JBFees.sol +52 -10
- package/src/libraries/JBFixedPointNumber.sol +2 -0
- package/src/libraries/JBPayoutSplitGroupLib.sol +7 -4
- package/src/libraries/JBRulesetMetadataResolver.sol +4 -0
- package/src/libraries/JBSplitGroupIds.sol +2 -1
- package/src/libraries/JBSurplus.sol +3 -1
- package/src/periphery/JBMatchingPriceFeed.sol +3 -1
- package/src/structs/JBAccountingContext.sol +7 -4
- package/src/structs/JBFundAccessLimitGroup.sol +10 -17
- package/src/structs/JBRuleset.sol +18 -26
- package/src/structs/JBRulesetConfig.sol +13 -25
- package/src/structs/JBRulesetMetadata.sol +25 -32
- package/test/mock/MockMaliciousBeneficiary.sol +15 -15
- package/ADMINISTRATION.md +0 -103
- package/ARCHITECTURE.md +0 -133
- package/AUDIT_INSTRUCTIONS.md +0 -139
- package/RISKS.md +0 -215
- package/SKILLS.md +0 -55
- package/STYLE_GUIDE.md +0 -610
- package/USER_JOURNEYS.md +0 -215
- package/script/Deploy.s.sol +0 -124
- package/script/DeployPeriphery.s.sol +0 -354
- package/slither-ci.config.json +0 -10
- package/test/AuditFixes.t.sol +0 -808
- package/test/ComprehensiveInvariant.t.sol +0 -306
- package/test/CoreExploitTests.t.sol +0 -2741
- package/test/EconomicSimulation.t.sol +0 -348
- package/test/EntryPointPermutations.t.sol +0 -684
- package/test/FlashLoanAttacks.t.sol +0 -797
- package/test/PermissionEscalation.t.sol +0 -711
- package/test/PermissionsInvariant.t.sol +0 -403
- package/test/RulesetTransitions.t.sol +0 -713
- package/test/SplitLoopTests.t.sol +0 -752
- package/test/TestAccessToFunds.sol +0 -2683
- package/test/TestAuditResponseDesignProofs.sol +0 -434
- package/test/TestCashOut.sol +0 -198
- package/test/TestCashOutCountFor.sol +0 -271
- package/test/TestCashOutHooks.sol +0 -351
- package/test/TestCashOutTimingEdge.sol +0 -241
- package/test/TestDataHookFuzzing.sol +0 -524
- package/test/TestDurationUnderflow.sol +0 -233
- package/test/TestFeeFreeCashOutBypass.sol +0 -949
- package/test/TestFeeProcessingFailure.sol +0 -218
- package/test/TestFees.sol +0 -619
- package/test/TestForwardedTokenConsumption.sol +0 -425
- package/test/TestInterfaceSupport.sol +0 -81
- package/test/TestJBERC20Inheritance.sol +0 -103
- package/test/TestL2SequencerPriceFeed.sol +0 -292
- package/test/TestLaunchProject.sol +0 -188
- package/test/TestMetaTx.sol +0 -217
- package/test/TestMetadataOffsetOverflow.sol +0 -179
- package/test/TestMetadataParserLib.sol +0 -471
- package/test/TestMigrationHeldFees.sol +0 -255
- package/test/TestMintTokensOf.sol +0 -185
- package/test/TestMultiTerminalSurplus.sol +0 -348
- package/test/TestMultiTokenSurplus.sol +0 -202
- package/test/TestMultipleAccessLimits.sol +0 -664
- package/test/TestPayBurnRedeemFlow.sol +0 -195
- package/test/TestPayHooks.sol +0 -209
- package/test/TestPermissions.sol +0 -324
- package/test/TestPermissionsEdge.sol +0 -290
- package/test/TestPermit2DataHook.t.sol +0 -360
- package/test/TestPermit2Terminal.sol +0 -372
- package/test/TestRulesetQueueing.sol +0 -1025
- package/test/TestRulesetQueuingStress.sol +0 -806
- package/test/TestRulesetWeightCaching.sol +0 -178
- package/test/TestSplits.sol +0 -391
- package/test/TestTerminalMigration.sol +0 -274
- package/test/TestTerminalPreviewParity.sol +0 -208
- package/test/TestTokenFlow.sol +0 -191
- package/test/TestWeightCacheStaleAfterRejection.sol +0 -303
- package/test/WeirdTokenTests.t.sol +0 -817
- package/test/audit/CashOutReenterPay.t.sol +0 -501
- package/test/audit/CodexHeldFeeRounding.t.sol +0 -159
- package/test/audit/CodexMigrationFeeFailure.t.sol +0 -163
- package/test/audit/CrossTerminalSurplusSpoof.t.sol +0 -140
- package/test/audit/CycledSurplusAllowanceReset.t.sol +0 -184
- package/test/audit/FeeFreeSurplusLifecycle.t.sol +0 -399
- package/test/audit/FeeFreeSurplusStale.t.sol +0 -248
- package/test/audit/USDTVoidReturnCompat.t.sol +0 -525
- package/test/fork/TestChainlinkPriceFeedFork.sol +0 -254
- package/test/fork/TestSequencerPriceFeedFork.sol +0 -168
- package/test/fork/TestTerminalPreviewParityFork.sol +0 -108
- package/test/formal/BondingCurveProperties.t.sol +0 -420
- package/test/formal/FeeProperties.t.sol +0 -252
- package/test/invariants/Phase3DeepInvariant.t.sol +0 -412
- package/test/invariants/RulesetsInvariant.t.sol +0 -125
- package/test/invariants/TerminalStoreInvariant.t.sol +0 -227
- package/test/invariants/TokensInvariant.t.sol +0 -195
- package/test/invariants/handlers/ComprehensiveHandler.sol +0 -303
- package/test/invariants/handlers/EconomicHandler.sol +0 -377
- package/test/invariants/handlers/Phase3Handler.sol +0 -443
- package/test/invariants/handlers/RulesetsHandler.sol +0 -115
- package/test/invariants/handlers/TerminalStoreHandler.sol +0 -151
- package/test/invariants/handlers/TokensHandler.sol +0 -126
- package/test/regression/HoldFeesCashOutReserved.t.sol +0 -415
- package/test/regression/WeightCacheBoundary.t.sol +0 -291
- package/test/trees/JBController/burnTokensOf.tree +0 -9
- package/test/trees/JBController/claimTokensFor.tree +0 -5
- package/test/trees/JBController/deployERC20For.tree +0 -5
- package/test/trees/JBController/getRulesetOf.tree +0 -5
- package/test/trees/JBController/launchProjectFor.tree +0 -12
- package/test/trees/JBController/launchRulesetsFor.tree +0 -8
- package/test/trees/JBController/migrateController.tree +0 -12
- package/test/trees/JBController/mintTokensOf.tree +0 -12
- package/test/trees/JBController/payReservedTokenToTerminal.tree +0 -8
- package/test/trees/JBController/receiveMigrationFrom.tree +0 -4
- package/test/trees/JBController/sendReservedTokensToSplitsOf.tree +0 -12
- package/test/trees/JBController/setMetadataOf.tree +0 -5
- package/test/trees/JBController/setSplitGroupsOf.tree +0 -5
- package/test/trees/JBController/setTokenFor.tree +0 -5
- package/test/trees/JBController/transferCreditsFrom.tree +0 -8
- package/test/trees/JBDirectory/primaryTerminalOf.tree +0 -8
- package/test/trees/JBDirectory/setControllerOf.tree +0 -11
- package/test/trees/JBDirectory/setPrimaryTerminalOf.tree +0 -15
- package/test/trees/JBDirectory/setTerminalsOf.tree +0 -11
- package/test/trees/JBERC20/initialize.tree +0 -7
- package/test/trees/JBERC20/name.tree +0 -5
- package/test/trees/JBERC20/nonces.tree +0 -5
- package/test/trees/JBERC20/symbol.tree +0 -5
- package/test/trees/JBFeelessAddresses/setFeelessAddress.tree +0 -5
- package/test/trees/JBFeelessAddresses/supportsInterface.tree +0 -5
- package/test/trees/JBFundAccessLimits/payoutLimitOf.tree +0 -5
- package/test/trees/JBFundAccessLimits/payoutLimitsOf.tree +0 -8
- package/test/trees/JBFundAccessLimits/setFundAccessLimitsFor.tree +0 -18
- package/test/trees/JBFundAccessLimits/surplusAllowanceOf.tree +0 -5
- package/test/trees/JBFundAccessLimits/surplusAllowancesOf.tree +0 -8
- package/test/trees/JBMetadataResolver/getDataFor.tree +0 -8
- package/test/trees/JBMultiTerminal/accountingContextsOf.tree +0 -5
- package/test/trees/JBMultiTerminal/addAccountingContextsFor.tree +0 -10
- package/test/trees/JBMultiTerminal/addToBalanceOf.tree +0 -23
- package/test/trees/JBMultiTerminal/cashOutTokensOf.tree +0 -23
- package/test/trees/JBMultiTerminal/executePayout.tree +0 -32
- package/test/trees/JBMultiTerminal/executeProcessFee.tree +0 -14
- package/test/trees/JBMultiTerminal/migrateBalanceOf.tree +0 -12
- package/test/trees/JBMultiTerminal/pay.tree +0 -23
- package/test/trees/JBMultiTerminal/processHeldFeesOf.tree +0 -8
- package/test/trees/JBMultiTerminal/sendPayoutsOf.tree +0 -34
- package/test/trees/JBMultiTerminal/useAllowanceOf.tree +0 -16
- package/test/trees/JBPermissions/hasPermission.tree +0 -8
- package/test/trees/JBPermissions/hasPermissions.tree +0 -8
- package/test/trees/JBPermissions/setPermissionsFor.tree +0 -5
- package/test/trees/JBPrices/addPriceFeedFor.tree +0 -14
- package/test/trees/JBPrices/pricePerUnitOf.tree +0 -11
- package/test/trees/JBProjects/createFor.tree +0 -11
- package/test/trees/JBProjects/setTokenUriResolver.tree +0 -5
- package/test/trees/JBProjects/supportsInterface.tree +0 -9
- package/test/trees/JBProjects/tokenURI.tree +0 -5
- package/test/trees/JBRulesets/currentApprovalStatusForLatestRulesetOf.tree +0 -8
- package/test/trees/JBRulesets/currentOf.tree +0 -12
- package/test/trees/JBRulesets/getRulesetOf.tree +0 -5
- package/test/trees/JBRulesets/latestQueuedRulesetOf.tree +0 -10
- package/test/trees/JBRulesets/rulesetsOf.tree +0 -11
- package/test/trees/JBRulesets/upcomingRulesetOf.tree +0 -20
- package/test/trees/JBRulesets/updateRulesetWeightCache.tree +0 -5
- package/test/trees/JBSplits/setSplitGroupsOf.tree +0 -17
- package/test/trees/JBSplits/splitsOf.tree +0 -5
- package/test/trees/JBTerminalStore/currentReclaimableSurplusOf.tree +0 -16
- package/test/trees/JBTerminalStore/currentSurplusOf.tree +0 -25
- package/test/trees/JBTerminalStore/currentTotalSurplusOf.tree +0 -5
- package/test/trees/JBTerminalStore/recordCashOutsFor.tree +0 -16
- package/test/trees/JBTerminalStore/recordPaymentFrom.tree +0 -14
- package/test/trees/JBTerminalStore/recordPayoutFor.tree +0 -10
- package/test/trees/JBTerminalStore/recordTerminalMigration.tree +0 -5
- package/test/trees/JBTerminalStore/recordUsedAllowanceOf.tree +0 -10
- package/test/trees/JBTokens/burnFrom.tree +0 -10
- package/test/trees/JBTokens/claimTokensFor.tree +0 -10
- package/test/trees/JBTokens/deployERC20For.tree +0 -12
- package/test/trees/JBTokens/mintFor.tree +0 -10
- package/test/trees/JBTokens/setTokenFor.tree +0 -11
- package/test/trees/JBTokens/totalBalanceOf.tree +0 -5
- package/test/trees/JBTokens/totalSupplyOf.tree +0 -5
- package/test/trees/JBTokens/transferCreditsFrom.tree +0 -8
- package/test/trees/mintTokensOf.tree +0 -12
- package/test/units/static/JBChainlinkV3PriceFeed/TestPriceFeed.sol +0 -223
- package/test/units/static/JBController/JBControllerSetup.sol +0 -50
- package/test/units/static/JBController/TestBurnTokensOf.sol +0 -114
- package/test/units/static/JBController/TestClaimTokensFor.sol +0 -63
- package/test/units/static/JBController/TestDeployErc20For.sol +0 -86
- package/test/units/static/JBController/TestLaunchProjectFor.sol +0 -302
- package/test/units/static/JBController/TestLaunchRulesetsFor.sol +0 -342
- package/test/units/static/JBController/TestMigrateController.sol +0 -157
- package/test/units/static/JBController/TestMintTokensOfUnits.sol +0 -111
- package/test/units/static/JBController/TestOmnichainRulesetOperator.sol +0 -324
- package/test/units/static/JBController/TestPayReservedTokenToTerminal.sol +0 -74
- package/test/units/static/JBController/TestPreviewMintOf.sol +0 -117
- package/test/units/static/JBController/TestReceiveMigrationFrom.sol +0 -99
- package/test/units/static/JBController/TestRulesetViews.sol +0 -225
- package/test/units/static/JBController/TestSendReservedTokensToSplitsOf.sol +0 -615
- package/test/units/static/JBController/TestSetSplitGroupsOf.sol +0 -68
- package/test/units/static/JBController/TestSetTokenFor.sol +0 -239
- package/test/units/static/JBController/TestSetUriOf.sol +0 -57
- package/test/units/static/JBController/TestTransferCreditsFrom.sol +0 -169
- package/test/units/static/JBDeadline/TestDeadlineFuzz.sol +0 -211
- package/test/units/static/JBDirectory/JBDirectorySetup.sol +0 -26
- package/test/units/static/JBDirectory/TestPrimaryTerminalOf.sol +0 -126
- package/test/units/static/JBDirectory/TestSetControllerOf.sol +0 -183
- package/test/units/static/JBDirectory/TestSetControllerOfMigrationOrder.sol +0 -104
- package/test/units/static/JBDirectory/TestSetPrimaryTerminalOf.sol +0 -179
- package/test/units/static/JBDirectory/TestSetTerminalsOf.sol +0 -137
- package/test/units/static/JBERC20/JBERC20Setup.sol +0 -34
- package/test/units/static/JBERC20/SigUtils.sol +0 -36
- package/test/units/static/JBERC20/TestInitialize.sol +0 -60
- package/test/units/static/JBERC20/TestName.sol +0 -30
- package/test/units/static/JBERC20/TestNonces.sol +0 -62
- package/test/units/static/JBERC20/TestSymbol.sol +0 -31
- package/test/units/static/JBFeelessAdresses/JBFeelessSetup.sol +0 -22
- package/test/units/static/JBFeelessAdresses/TestInterfaces.sol +0 -30
- package/test/units/static/JBFeelessAdresses/TestSetFeelessAddress.sol +0 -35
- package/test/units/static/JBFees/TestFeesFuzz.sol +0 -79
- package/test/units/static/JBFixedPointNumber/TestAdjustDecimals.sol +0 -16
- package/test/units/static/JBFixedPointNumber/TestAdjustDecimalsFuzz.sol +0 -71
- package/test/units/static/JBFundAccessLimits/JBFundAccessSetup.sol +0 -24
- package/test/units/static/JBFundAccessLimits/TestFundAccessLimitsEdge.sol +0 -163
- package/test/units/static/JBFundAccessLimits/TestPayoutLimitOf.sol +0 -59
- package/test/units/static/JBFundAccessLimits/TestPayoutLimitsOf.sol +0 -101
- package/test/units/static/JBFundAccessLimits/TestSetFundAccessLimitsFor.sol +0 -189
- package/test/units/static/JBFundAccessLimits/TestSurplusAllowanceOf.sol +0 -64
- package/test/units/static/JBFundAccessLimits/TestSurplusAllowancesOf.sol +0 -102
- package/test/units/static/JBMetadataResolver/TestGetDataFor.sol +0 -90
- package/test/units/static/JBMetadataResolver/TestMetadataResolverEdgeCases.sol +0 -247
- package/test/units/static/JBMetadataResolver/TestMetadataResolverFuzz.sol +0 -229
- package/test/units/static/JBMultiTerminal/JBMultiTerminalSetup.sol +0 -50
- package/test/units/static/JBMultiTerminal/TestAccountingContextsOf.sol +0 -72
- package/test/units/static/JBMultiTerminal/TestAddAccountingContextsFor.sol +0 -289
- package/test/units/static/JBMultiTerminal/TestAddToBalanceOf.sol +0 -474
- package/test/units/static/JBMultiTerminal/TestCashOutTokensOf.sol +0 -624
- package/test/units/static/JBMultiTerminal/TestExecutePayout.sol +0 -578
- package/test/units/static/JBMultiTerminal/TestExecuteProcessFee.sol +0 -202
- package/test/units/static/JBMultiTerminal/TestMigrateBalanceOf.sol +0 -222
- package/test/units/static/JBMultiTerminal/TestPay.sol +0 -604
- package/test/units/static/JBMultiTerminal/TestPreviewCashOutFrom.sol +0 -117
- package/test/units/static/JBMultiTerminal/TestPreviewPayFor.sol +0 -114
- package/test/units/static/JBMultiTerminal/TestProcessHeldFeesOf.sol +0 -228
- package/test/units/static/JBMultiTerminal/TestSelfPayRevert.sol +0 -55
- package/test/units/static/JBMultiTerminal/TestSendPayoutsOf.sol +0 -257
- package/test/units/static/JBMultiTerminal/TestUseAllowanceOf.sol +0 -611
- package/test/units/static/JBPermissions/JBPermissionsSetup.sol +0 -20
- package/test/units/static/JBPermissions/TestHasPermission.sol +0 -50
- package/test/units/static/JBPermissions/TestHasPermissions.sol +0 -93
- package/test/units/static/JBPermissions/TestSetPermissionsFor.sol +0 -64
- package/test/units/static/JBPrices/JBPricesSetup.sol +0 -32
- package/test/units/static/JBPrices/TestAddPriceFeedFor.sol +0 -107
- package/test/units/static/JBPrices/TestPricePerUnitOf.sol +0 -132
- package/test/units/static/JBPrices/TestPrices.sol +0 -265
- package/test/units/static/JBProjects/JBProjectsSetup.sol +0 -22
- package/test/units/static/JBProjects/TestCreateFor.sol +0 -71
- package/test/units/static/JBProjects/TestInitialProject.sol +0 -21
- package/test/units/static/JBProjects/TestInterfaces.sol +0 -26
- package/test/units/static/JBProjects/TestSetResolver.sol +0 -37
- package/test/units/static/JBProjects/TestTokenUri.sol +0 -40
- package/test/units/static/JBRulesetMetadataResolver/TestSetCashOutTaxRateTo.sol +0 -108
- package/test/units/static/JBRulesets/JBRulesetsSetup.sol +0 -24
- package/test/units/static/JBRulesets/TestCurrentApprovalStatusForLatestRulesetOf.sol +0 -265
- package/test/units/static/JBRulesets/TestCurrentOf.sol +0 -242
- package/test/units/static/JBRulesets/TestGetRulesetOf.sol +0 -100
- package/test/units/static/JBRulesets/TestLatestQueuedRulesetOf.sol +0 -260
- package/test/units/static/JBRulesets/TestRulesets.sol +0 -632
- package/test/units/static/JBRulesets/TestRulesetsOf.sol +0 -37
- package/test/units/static/JBRulesets/TestUpcomingRulesetOf.sol +0 -522
- package/test/units/static/JBRulesets/TestUpdateRulesetWeightCache.sol +0 -96
- package/test/units/static/JBSplits/JBSplitsSetup.sol +0 -26
- package/test/units/static/JBSplits/TestSelfManagedSplitGroups.sol +0 -552
- package/test/units/static/JBSplits/TestSetSplitGroupsOf.sol +0 -377
- package/test/units/static/JBSplits/TestSplitsLockedEdge.sol +0 -267
- package/test/units/static/JBSplits/TestSplitsOf.sol +0 -24
- package/test/units/static/JBSplits/TestSplitsPacking.sol +0 -36
- package/test/units/static/JBSurplus/TestSurplusFuzz.sol +0 -160
- package/test/units/static/JBTerminalStore/JBTerminalStoreSetup.sol +0 -45
- package/test/units/static/JBTerminalStore/TestCurrentReclaimableSurplusOf.sol +0 -536
- package/test/units/static/JBTerminalStore/TestCurrentSurplusOf.sol +0 -463
- package/test/units/static/JBTerminalStore/TestCurrentTotalSurplusOf.sol +0 -135
- package/test/units/static/JBTerminalStore/TestPreviewCashOutFrom.sol +0 -476
- package/test/units/static/JBTerminalStore/TestPreviewPayFrom.sol +0 -494
- package/test/units/static/JBTerminalStore/TestRecordCashOutsFor.sol +0 -652
- package/test/units/static/JBTerminalStore/TestRecordPaymentFrom.sol +0 -744
- package/test/units/static/JBTerminalStore/TestRecordPayoutFor.sol +0 -289
- package/test/units/static/JBTerminalStore/TestRecordTerminalMigration.sol +0 -138
- package/test/units/static/JBTerminalStore/TestRecordUsedAllowanceOf.sol +0 -415
- package/test/units/static/JBTerminalStore/TestUint224Overflow.sol +0 -219
- package/test/units/static/JBTokens/JBTokensSetup.sol +0 -32
- package/test/units/static/JBTokens/TestBurnFrom.sol +0 -107
- package/test/units/static/JBTokens/TestClaimTokensFor.sol +0 -110
- package/test/units/static/JBTokens/TestDeployERC20ForUnits.sol +0 -92
- package/test/units/static/JBTokens/TestMintFor.sol +0 -100
- package/test/units/static/JBTokens/TestSetTokenFor.sol +0 -98
- package/test/units/static/JBTokens/TestTotalBalanceOf.sol +0 -65
- package/test/units/static/JBTokens/TestTotalSupplyOf.sol +0 -56
- package/test/units/static/JBTokens/TestTransferCreditsFrom.sol +0 -56
package/test/AuditFixes.t.sol
DELETED
|
@@ -1,808 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity ^0.8.6;
|
|
3
|
-
|
|
4
|
-
import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
|
|
5
|
-
import {JBMultiTerminal} from "../src/JBMultiTerminal.sol";
|
|
6
|
-
import {JBTerminalStore} from "../src/JBTerminalStore.sol";
|
|
7
|
-
import {JBTokens} from "../src/JBTokens.sol";
|
|
8
|
-
import {IJBController} from "../src/interfaces/IJBController.sol";
|
|
9
|
-
import {IJBPayHook} from "../src/interfaces/IJBPayHook.sol";
|
|
10
|
-
import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
11
|
-
import {IJBRulesetDataHook} from "../src/interfaces/IJBRulesetDataHook.sol";
|
|
12
|
-
import {IJBSplitHook} from "../src/interfaces/IJBSplitHook.sol";
|
|
13
|
-
import {IJBTerminal} from "../src/interfaces/IJBTerminal.sol";
|
|
14
|
-
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
15
|
-
import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
|
|
16
|
-
import {JBCurrencyAmount} from "../src/structs/JBCurrencyAmount.sol";
|
|
17
|
-
import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
|
|
18
|
-
import {JBPayHookSpecification} from "../src/structs/JBPayHookSpecification.sol";
|
|
19
|
-
import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
|
|
20
|
-
import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
|
|
21
|
-
import {JBSplit} from "../src/structs/JBSplit.sol";
|
|
22
|
-
import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
|
|
23
|
-
import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
|
|
24
|
-
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
25
|
-
|
|
26
|
-
/// @notice Tests for three audit fixes: F-3, F-4, and F-5.
|
|
27
|
-
/// F-5: Saturating subtraction in _tokenSurplusFrom prevents underflow when usedPayoutLimit > payoutLimit.amount.
|
|
28
|
-
/// F-3: _capFeeFreeSurplus after _efficientPay in executePayout caps fee-free surplus at STORE.balanceOf.
|
|
29
|
-
/// F-4: _capFeeFreeSurplus after hook fulfillment in _cashOutTokensOf caps fee-free surplus at remaining balance.
|
|
30
|
-
contract AuditFixesTest is TestBaseWorkflow {
|
|
31
|
-
// --- Core protocol references ---
|
|
32
|
-
IJBController private _controller;
|
|
33
|
-
JBMultiTerminal private _terminal;
|
|
34
|
-
JBTerminalStore private _store;
|
|
35
|
-
JBTokens private _tokens;
|
|
36
|
-
address private _projectOwner;
|
|
37
|
-
|
|
38
|
-
// Token issuance weight: 1000 tokens per ETH.
|
|
39
|
-
uint112 private constant WEIGHT = 1000 * 10 ** 18;
|
|
40
|
-
|
|
41
|
-
// Storage slot index for _feeFreeSurplusOf in JBMultiTerminal.
|
|
42
|
-
// This is the first state variable in the contract (slot 0).
|
|
43
|
-
uint256 private constant FEE_FREE_SURPLUS_SLOT = 0;
|
|
44
|
-
|
|
45
|
-
function setUp() public override {
|
|
46
|
-
super.setUp();
|
|
47
|
-
|
|
48
|
-
_controller = jbController();
|
|
49
|
-
_terminal = jbMultiTerminal();
|
|
50
|
-
_store = jbTerminalStore();
|
|
51
|
-
_tokens = jbTokens();
|
|
52
|
-
_projectOwner = multisig();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// ==========================================
|
|
56
|
-
// F-5: Saturating subtraction in _tokenSurplusFrom
|
|
57
|
-
// ==========================================
|
|
58
|
-
|
|
59
|
-
/// @notice When a new ruleset activates with a lower payout limit than what was already used under a previous
|
|
60
|
-
/// ruleset (same cycle number), `currentSurplusOf` must not revert. The saturating subtraction clamps
|
|
61
|
-
/// (used - limit) to zero instead of underflowing.
|
|
62
|
-
/// @dev Setup:
|
|
63
|
-
/// 1. Launch a project with duration=1 day and a high payout limit (10 ETH).
|
|
64
|
-
/// 2. Pay in and use some of the payout limit (5 ETH).
|
|
65
|
-
/// 3. Queue a new ruleset with a much lower payout limit (1 ETH) and no approval hook (takes effect immediately
|
|
66
|
-
/// as the replacement for the next cycle derived from the queued config).
|
|
67
|
-
/// 4. Warp forward to the next cycle so the new ruleset activates. The usedPayoutLimitOf from the previous cycle
|
|
68
|
-
/// is keyed by cycleNumber, so the new cycle starts fresh. However, if the new ruleset had duration=0 and
|
|
69
|
-
/// replaced mid-cycle, the used amount could exceed the new limit.
|
|
70
|
-
///
|
|
71
|
-
/// NOTE: In practice, triggering usedPayoutLimit > payoutLimit.amount is difficult because:
|
|
72
|
-
/// - For cycling rulesets (duration > 0), usedPayoutLimitOf resets each cycle.
|
|
73
|
-
/// - For duration=0 rulesets, queueing a replacement takes effect immediately with cycleNumber=1.
|
|
74
|
-
/// The saturating subtraction is defensive coding that prevents edge cases from DOS-ing the view function.
|
|
75
|
-
/// This test verifies the view function works correctly under normal conditions and does not revert.
|
|
76
|
-
function test_F5_currentSurplusOfDoesNotRevertWithLowerPayoutLimit() external {
|
|
77
|
-
// --- Fee project (project #1) ---
|
|
78
|
-
_launchFeeProject();
|
|
79
|
-
|
|
80
|
-
// --- Main project: duration=1 day, high payout limit ---
|
|
81
|
-
uint224 highPayoutLimit = 10 ether;
|
|
82
|
-
uint32 cycleDuration = 1 days;
|
|
83
|
-
|
|
84
|
-
JBFundAccessLimitGroup[] memory fundAccess = _makeFundAccessLimitGroup(highPayoutLimit);
|
|
85
|
-
|
|
86
|
-
JBRulesetConfig[] memory rulesetConfig = new JBRulesetConfig[](1);
|
|
87
|
-
rulesetConfig[0] = _makeRulesetConfig({
|
|
88
|
-
duration: cycleDuration,
|
|
89
|
-
metadata: _defaultMetadata(),
|
|
90
|
-
splitGroups: new JBSplitGroup[](0),
|
|
91
|
-
fundAccessLimitGroups: fundAccess
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
JBTerminalConfig[] memory termConfigs = _makeTerminalConfig();
|
|
95
|
-
|
|
96
|
-
uint256 projectId = _controller.launchProjectFor({
|
|
97
|
-
owner: _projectOwner,
|
|
98
|
-
projectUri: "f5-project",
|
|
99
|
-
rulesetConfigurations: rulesetConfig,
|
|
100
|
-
terminalConfigurations: termConfigs,
|
|
101
|
-
memo: ""
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// Pay 20 ETH into the project.
|
|
105
|
-
address payer = makeAddr("f5-payer");
|
|
106
|
-
vm.deal(payer, 20 ether);
|
|
107
|
-
vm.prank(payer);
|
|
108
|
-
_terminal.pay{value: 20 ether}({
|
|
109
|
-
projectId: projectId,
|
|
110
|
-
amount: 20 ether,
|
|
111
|
-
token: JBConstants.NATIVE_TOKEN,
|
|
112
|
-
beneficiary: payer,
|
|
113
|
-
minReturnedTokens: 0,
|
|
114
|
-
memo: "",
|
|
115
|
-
metadata: new bytes(0)
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// Use 5 ETH of the 10 ETH payout limit.
|
|
119
|
-
_terminal.sendPayoutsOf({
|
|
120
|
-
projectId: projectId,
|
|
121
|
-
token: JBConstants.NATIVE_TOKEN,
|
|
122
|
-
amount: 5 ether,
|
|
123
|
-
currency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
124
|
-
minTokensPaidOut: 0
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// Queue a new ruleset with a much lower payout limit (1 ETH).
|
|
128
|
-
JBFundAccessLimitGroup[] memory lowFundAccess = _makeFundAccessLimitGroup(1 ether);
|
|
129
|
-
JBRulesetConfig[] memory newRulesetConfig = new JBRulesetConfig[](1);
|
|
130
|
-
newRulesetConfig[0] = _makeRulesetConfig({
|
|
131
|
-
duration: cycleDuration,
|
|
132
|
-
metadata: _defaultMetadata(),
|
|
133
|
-
splitGroups: new JBSplitGroup[](0),
|
|
134
|
-
fundAccessLimitGroups: lowFundAccess
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
vm.prank(_projectOwner);
|
|
138
|
-
_controller.queueRulesetsOf({projectId: projectId, rulesetConfigurations: newRulesetConfig, memo: ""});
|
|
139
|
-
|
|
140
|
-
// Warp to next cycle so the new ruleset activates.
|
|
141
|
-
vm.warp(block.timestamp + cycleDuration);
|
|
142
|
-
|
|
143
|
-
// KEY ASSERTION: currentSurplusOf must NOT revert.
|
|
144
|
-
// If the saturating subtraction were missing and somehow used > limit, this would underflow.
|
|
145
|
-
// Even though in this specific setup the cycle resets used to 0, this test verifies the view
|
|
146
|
-
// function works correctly after a payout limit reduction.
|
|
147
|
-
IJBTerminal[] memory terminals = new IJBTerminal[](1);
|
|
148
|
-
terminals[0] = IJBTerminal(address(_terminal));
|
|
149
|
-
address[] memory tokensToCheck = new address[](1);
|
|
150
|
-
tokensToCheck[0] = JBConstants.NATIVE_TOKEN;
|
|
151
|
-
|
|
152
|
-
uint256 surplus = _store.currentSurplusOf({
|
|
153
|
-
projectId: projectId,
|
|
154
|
-
terminals: terminals,
|
|
155
|
-
tokens: tokensToCheck,
|
|
156
|
-
decimals: 18,
|
|
157
|
-
currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// After paying out 5 ETH from 20 ETH, balance is 15 ETH. New payout limit is 1 ETH.
|
|
161
|
-
// Surplus = balance - payoutLimitRemaining = 15 ETH - 1 ETH = 14 ETH.
|
|
162
|
-
assertEq(surplus, 14 ether, "Surplus should be balance minus new (lower) payout limit");
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/// @notice Verify that currentSurplusOf does not revert when the project has zero payout limits in the new ruleset
|
|
166
|
-
/// (meaning all balance is surplus). This is a simpler version of the F-5 scenario.
|
|
167
|
-
function test_F5_currentSurplusOfWithZeroPayoutLimit() external {
|
|
168
|
-
// Fee project.
|
|
169
|
-
_launchFeeProject();
|
|
170
|
-
|
|
171
|
-
// Launch project with payout limit, use it, then queue ruleset with no limits.
|
|
172
|
-
uint224 payoutLimit = 5 ether;
|
|
173
|
-
JBFundAccessLimitGroup[] memory fundAccess = _makeFundAccessLimitGroup(payoutLimit);
|
|
174
|
-
|
|
175
|
-
JBRulesetConfig[] memory rulesetConfig = new JBRulesetConfig[](1);
|
|
176
|
-
rulesetConfig[0] = _makeRulesetConfig({
|
|
177
|
-
duration: 1 days,
|
|
178
|
-
metadata: _defaultMetadata(),
|
|
179
|
-
splitGroups: new JBSplitGroup[](0),
|
|
180
|
-
fundAccessLimitGroups: fundAccess
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
uint256 projectId = _controller.launchProjectFor({
|
|
184
|
-
owner: _projectOwner,
|
|
185
|
-
projectUri: "f5-zero-limit",
|
|
186
|
-
rulesetConfigurations: rulesetConfig,
|
|
187
|
-
terminalConfigurations: _makeTerminalConfig(),
|
|
188
|
-
memo: ""
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
// Pay in and use the full payout limit.
|
|
192
|
-
address payer = makeAddr("f5-payer2");
|
|
193
|
-
vm.deal(payer, 10 ether);
|
|
194
|
-
vm.prank(payer);
|
|
195
|
-
_terminal.pay{value: 10 ether}({
|
|
196
|
-
projectId: projectId,
|
|
197
|
-
amount: 10 ether,
|
|
198
|
-
token: JBConstants.NATIVE_TOKEN,
|
|
199
|
-
beneficiary: payer,
|
|
200
|
-
minReturnedTokens: 0,
|
|
201
|
-
memo: "",
|
|
202
|
-
metadata: new bytes(0)
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
_terminal.sendPayoutsOf({
|
|
206
|
-
projectId: projectId,
|
|
207
|
-
token: JBConstants.NATIVE_TOKEN,
|
|
208
|
-
amount: payoutLimit,
|
|
209
|
-
currency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
210
|
-
minTokensPaidOut: 0
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
// Queue a new ruleset with zero payout limits (all balance is surplus).
|
|
214
|
-
JBRulesetConfig[] memory newRulesetConfig = new JBRulesetConfig[](1);
|
|
215
|
-
newRulesetConfig[0] = _makeRulesetConfig({
|
|
216
|
-
duration: 1 days,
|
|
217
|
-
metadata: _defaultMetadata(),
|
|
218
|
-
splitGroups: new JBSplitGroup[](0),
|
|
219
|
-
fundAccessLimitGroups: new JBFundAccessLimitGroup[](0)
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
vm.prank(_projectOwner);
|
|
223
|
-
_controller.queueRulesetsOf({projectId: projectId, rulesetConfigurations: newRulesetConfig, memo: ""});
|
|
224
|
-
|
|
225
|
-
// Warp to next cycle.
|
|
226
|
-
vm.warp(block.timestamp + 1 days);
|
|
227
|
-
|
|
228
|
-
// currentSurplusOf must not revert. With zero limits, surplus = entire balance.
|
|
229
|
-
IJBTerminal[] memory terminals = new IJBTerminal[](1);
|
|
230
|
-
terminals[0] = IJBTerminal(address(_terminal));
|
|
231
|
-
address[] memory tokensToCheck = new address[](1);
|
|
232
|
-
tokensToCheck[0] = JBConstants.NATIVE_TOKEN;
|
|
233
|
-
|
|
234
|
-
uint256 surplus = _store.currentSurplusOf({
|
|
235
|
-
projectId: projectId,
|
|
236
|
-
terminals: terminals,
|
|
237
|
-
tokens: tokensToCheck,
|
|
238
|
-
decimals: 18,
|
|
239
|
-
currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// Balance after paying out 5 ETH from 10 ETH is 5 ETH. No payout limits = all surplus.
|
|
243
|
-
assertEq(surplus, 5 ether, "Surplus should equal full remaining balance with zero payout limits");
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// ==========================================
|
|
247
|
-
// F-3: _capFeeFreeSurplus after _efficientPay in executePayout
|
|
248
|
-
// ==========================================
|
|
249
|
-
|
|
250
|
-
/// @notice When project A pays out to project B via a same-terminal split (not addToBalance), and project B has
|
|
251
|
-
/// a data hook that diverts some of the payment to pay hooks, the store only records a partial balance increase.
|
|
252
|
-
/// The fix ensures _feeFreeSurplusOf[B] is capped at STORE.balanceOf[B] after the pay.
|
|
253
|
-
/// @dev Setup:
|
|
254
|
-
/// 1. Project B: has a data hook that returns a pay hook specification diverting 50% of the payment.
|
|
255
|
-
/// 2. Project A: has 100% split paying project B (same terminal, preferAddToBalance=false).
|
|
256
|
-
/// 3. After sendPayoutsOf, verify _feeFreeSurplusOf[B] <= STORE.balanceOf[B].
|
|
257
|
-
/// 4. Verify a subsequent zero-tax cashout from B charges correct fees (not overcharged).
|
|
258
|
-
function test_F3_feeFreeSurplusCappedWhenDataHookDivertsFunds() external {
|
|
259
|
-
// --- Fee project ---
|
|
260
|
-
_launchFeeProject();
|
|
261
|
-
|
|
262
|
-
// --- Setup data hook and pay hook mocks ---
|
|
263
|
-
address dataHook = makeAddr("data-hook-f3");
|
|
264
|
-
address payHook = makeAddr("pay-hook-f3");
|
|
265
|
-
|
|
266
|
-
// --- Project B: zero tax, data hook enabled for pay ---
|
|
267
|
-
JBRulesetMetadata memory metadataB = _defaultMetadata();
|
|
268
|
-
metadataB.useDataHookForPay = true;
|
|
269
|
-
metadataB.dataHook = dataHook;
|
|
270
|
-
|
|
271
|
-
JBRulesetConfig[] memory rulesetConfigB = new JBRulesetConfig[](1);
|
|
272
|
-
rulesetConfigB[0] = _makeRulesetConfig({
|
|
273
|
-
duration: 0,
|
|
274
|
-
metadata: metadataB,
|
|
275
|
-
splitGroups: new JBSplitGroup[](0),
|
|
276
|
-
fundAccessLimitGroups: new JBFundAccessLimitGroup[](0)
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
uint256 projectIdB = _controller.launchProjectFor({
|
|
280
|
-
owner: _projectOwner,
|
|
281
|
-
projectUri: "project-b-f3",
|
|
282
|
-
rulesetConfigurations: rulesetConfigB,
|
|
283
|
-
terminalConfigurations: _makeTerminalConfig(),
|
|
284
|
-
memo: ""
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
// Deploy ERC-20 for project B so we can cash out.
|
|
288
|
-
vm.prank(_projectOwner);
|
|
289
|
-
_controller.deployERC20For(projectIdB, "ProjectB", "PB", bytes32(0));
|
|
290
|
-
|
|
291
|
-
// --- Project A: 100% split to project B, preferAddToBalance=false ---
|
|
292
|
-
uint224 payoutLimit = 10 ether;
|
|
293
|
-
|
|
294
|
-
JBSplit[] memory splits = new JBSplit[](1);
|
|
295
|
-
splits[0] = JBSplit({
|
|
296
|
-
preferAddToBalance: false,
|
|
297
|
-
percent: JBConstants.SPLITS_TOTAL_PERCENT,
|
|
298
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
299
|
-
projectId: uint64(projectIdB),
|
|
300
|
-
beneficiary: payable(makeAddr("split-beneficiary")),
|
|
301
|
-
lockedUntil: 0,
|
|
302
|
-
hook: IJBSplitHook(address(0))
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
JBSplitGroup[] memory splitGroups = new JBSplitGroup[](1);
|
|
306
|
-
splitGroups[0] = JBSplitGroup({groupId: uint32(uint160(JBConstants.NATIVE_TOKEN)), splits: splits});
|
|
307
|
-
|
|
308
|
-
JBFundAccessLimitGroup[] memory fundAccess = _makeFundAccessLimitGroup(payoutLimit);
|
|
309
|
-
|
|
310
|
-
JBRulesetConfig[] memory rulesetConfigA = new JBRulesetConfig[](1);
|
|
311
|
-
rulesetConfigA[0] = _makeRulesetConfig({
|
|
312
|
-
duration: 0, metadata: _defaultMetadata(), splitGroups: splitGroups, fundAccessLimitGroups: fundAccess
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
uint256 projectIdA = _controller.launchProjectFor({
|
|
316
|
-
owner: _projectOwner,
|
|
317
|
-
projectUri: "project-a-f3",
|
|
318
|
-
rulesetConfigurations: rulesetConfigA,
|
|
319
|
-
terminalConfigurations: _makeTerminalConfig(),
|
|
320
|
-
memo: ""
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
// --- Mock the data hook to divert 50% of payments to a pay hook ---
|
|
324
|
-
// The data hook returns a pay hook specification that takes 50% of the payment amount.
|
|
325
|
-
// This means the store only records 50% as project B's balance.
|
|
326
|
-
// We need to mock the data hook's beforePayRecordedWith and the pay hook's afterPayRecordedWith.
|
|
327
|
-
// The data hook must also support ERC-165.
|
|
328
|
-
|
|
329
|
-
// Mock ERC-165 support for IJBRulesetDataHook.
|
|
330
|
-
vm.mockCall(dataHook, abi.encodeWithSelector(bytes4(keccak256("supportsInterface(bytes4)"))), abi.encode(true));
|
|
331
|
-
|
|
332
|
-
// Mock hasMintPermissionFor to return false (not needed for this test).
|
|
333
|
-
vm.mockCall(
|
|
334
|
-
dataHook, abi.encodeWithSelector(IJBRulesetDataHook.hasMintPermissionFor.selector), abi.encode(false)
|
|
335
|
-
);
|
|
336
|
-
|
|
337
|
-
// The data hook will be called when project B receives the payment via _efficientPay.
|
|
338
|
-
// We need to return a weight and pay hook specifications.
|
|
339
|
-
// The pay hook spec diverts 50% of the payment to the pay hook.
|
|
340
|
-
// We use a wildcard mock: any call to beforePayRecordedWith returns our response.
|
|
341
|
-
//
|
|
342
|
-
// NOTE: We can't predict the exact calldata because the `amount.value` depends on payout calculations.
|
|
343
|
-
// So we use a broad mock that always returns the same response for any beforePayRecordedWith call.
|
|
344
|
-
// The diversion amount will be calculated as 50% of whatever is sent.
|
|
345
|
-
|
|
346
|
-
// We'll use a helper approach: mock the data hook to return weight=WEIGHT and a pay hook spec
|
|
347
|
-
// that takes 5 ETH (half of the 10 ETH payout).
|
|
348
|
-
JBPayHookSpecification[] memory hookSpecs = new JBPayHookSpecification[](1);
|
|
349
|
-
hookSpecs[0] = JBPayHookSpecification({
|
|
350
|
-
hook: IJBPayHook(payHook),
|
|
351
|
-
noop: false,
|
|
352
|
-
amount: 5 ether, // Divert 50% (5 ETH of the 10 ETH payout)
|
|
353
|
-
metadata: new bytes(0)
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
vm.mockCall(
|
|
357
|
-
dataHook,
|
|
358
|
-
abi.encodeWithSelector(IJBRulesetDataHook.beforePayRecordedWith.selector),
|
|
359
|
-
abi.encode(WEIGHT, hookSpecs)
|
|
360
|
-
);
|
|
361
|
-
|
|
362
|
-
// Mock the pay hook to accept the call without reverting.
|
|
363
|
-
vm.mockCall(payHook, abi.encodeWithSelector(IJBPayHook.afterPayRecordedWith.selector), abi.encode());
|
|
364
|
-
|
|
365
|
-
// --- Fund project A and send payouts ---
|
|
366
|
-
address payer = makeAddr("f3-payer");
|
|
367
|
-
vm.deal(payer, 10 ether);
|
|
368
|
-
vm.prank(payer);
|
|
369
|
-
_terminal.pay{value: 10 ether}({
|
|
370
|
-
projectId: projectIdA,
|
|
371
|
-
amount: 10 ether,
|
|
372
|
-
token: JBConstants.NATIVE_TOKEN,
|
|
373
|
-
beneficiary: payer,
|
|
374
|
-
minReturnedTokens: 0,
|
|
375
|
-
memo: "",
|
|
376
|
-
metadata: new bytes(0)
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
// Send payouts from project A: 10 ETH goes to project B via the split.
|
|
380
|
-
// The data hook diverts 5 ETH to the pay hook, so STORE.balanceOf[B] only increases by 5 ETH.
|
|
381
|
-
// But _feeFreeSurplusOf[B] was incremented by the full 10 ETH before the pay.
|
|
382
|
-
// After the fix (F-3), _capFeeFreeSurplus caps it at 5 ETH.
|
|
383
|
-
_terminal.sendPayoutsOf({
|
|
384
|
-
projectId: projectIdA,
|
|
385
|
-
token: JBConstants.NATIVE_TOKEN,
|
|
386
|
-
amount: payoutLimit,
|
|
387
|
-
currency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
388
|
-
minTokensPaidOut: 0
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
// --- Verify invariant: _feeFreeSurplusOf[B] <= STORE.balanceOf[B] ---
|
|
392
|
-
uint256 feeFreeSurplus = _readFeeFreeSurplus(projectIdB, JBConstants.NATIVE_TOKEN);
|
|
393
|
-
uint256 storeBalance = _store.balanceOf(address(_terminal), projectIdB, JBConstants.NATIVE_TOKEN);
|
|
394
|
-
|
|
395
|
-
assertLe(
|
|
396
|
-
feeFreeSurplus,
|
|
397
|
-
storeBalance,
|
|
398
|
-
"F-3: _feeFreeSurplusOf must not exceed STORE.balanceOf after data hook diverts funds"
|
|
399
|
-
);
|
|
400
|
-
|
|
401
|
-
// The store should have recorded only the portion not diverted to the pay hook.
|
|
402
|
-
// With 10 ETH payout and 5 ETH diverted: store balance = 5 ETH.
|
|
403
|
-
assertEq(storeBalance, 5 ether, "Store balance should be payment minus pay hook diversion");
|
|
404
|
-
assertEq(feeFreeSurplus, 5 ether, "Fee-free surplus should be capped at store balance");
|
|
405
|
-
|
|
406
|
-
// Verify zero-tax cashout charges correct fees via helper (avoids stack-too-deep).
|
|
407
|
-
_verifyCashOutFees(projectIdB);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
/// @dev Helper to verify cashout fees for F-3 (extracted to reduce stack depth).
|
|
411
|
-
function _verifyCashOutFees(uint256 projectIdB) private {
|
|
412
|
-
address splitBeneficiary = makeAddr("split-beneficiary");
|
|
413
|
-
uint256 beneficiaryTokens = _tokens.totalBalanceOf(splitBeneficiary, projectIdB);
|
|
414
|
-
|
|
415
|
-
if (beneficiaryTokens > 0) {
|
|
416
|
-
vm.prank(splitBeneficiary);
|
|
417
|
-
uint256 reclaimAmount = _terminal.cashOutTokensOf({
|
|
418
|
-
holder: splitBeneficiary,
|
|
419
|
-
projectId: projectIdB,
|
|
420
|
-
cashOutCount: beneficiaryTokens,
|
|
421
|
-
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
422
|
-
minTokensReclaimed: 0,
|
|
423
|
-
beneficiary: payable(splitBeneficiary),
|
|
424
|
-
metadata: new bytes(0)
|
|
425
|
-
});
|
|
426
|
-
|
|
427
|
-
// With cashOutTaxRate = 0, the fee is charged on the feeFreeSurplus portion (5 ETH).
|
|
428
|
-
// Fee = 2.5% of 5 ETH = 0.125 ETH. Net = 5 - 0.125 = 4.875 ETH.
|
|
429
|
-
uint256 expectedFee = mulDiv(5 ether, 25, 1000);
|
|
430
|
-
uint256 expectedNet = 5 ether - expectedFee;
|
|
431
|
-
assertApproxEqAbs(
|
|
432
|
-
reclaimAmount,
|
|
433
|
-
expectedNet,
|
|
434
|
-
2,
|
|
435
|
-
"F-3: Cashout should charge correct fee (2.5% of capped fee-free surplus)"
|
|
436
|
-
);
|
|
437
|
-
|
|
438
|
-
// Crucially, the fee should NOT be calculated on the full 10 ETH payout amount.
|
|
439
|
-
// Without the fix, feeFreeSurplus would be 10 ETH but balance only 5 ETH,
|
|
440
|
-
// causing an overcharge.
|
|
441
|
-
assertLt(reclaimAmount, 5 ether, "F-3: Fee must be deducted from cashout");
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// ==========================================
|
|
446
|
-
// F-4: _capFeeFreeSurplus after hook fulfillment in _cashOutTokensOf
|
|
447
|
-
// ==========================================
|
|
448
|
-
|
|
449
|
-
/// @notice After a cashout, _feeFreeSurplusOf is capped at the remaining STORE.balanceOf.
|
|
450
|
-
/// This prevents stale _feeFreeSurplusOf from overcharging fees on subsequent zero-tax cashouts.
|
|
451
|
-
/// @dev Setup:
|
|
452
|
-
/// 1. Project A pays out to project B (same terminal) to build up _feeFreeSurplusOf[B].
|
|
453
|
-
/// 2. Some users pay B directly (increasing balance but not fee-free surplus).
|
|
454
|
-
/// 3. Cash out from B. After the cashout, _feeFreeSurplusOf[B] should be capped at remaining balance.
|
|
455
|
-
/// 4. Subsequent direct-pay cashout should be fee-free (no remaining fee-free surplus).
|
|
456
|
-
function test_F4_feeFreeSurplusCappedAfterCashOut() external {
|
|
457
|
-
// --- Fee project ---
|
|
458
|
-
_launchFeeProject();
|
|
459
|
-
|
|
460
|
-
// Launch project B and project A with payout split to B.
|
|
461
|
-
(uint256 projectIdA, uint256 projectIdB) = _launchPayoutPairForF4("f4-cap");
|
|
462
|
-
|
|
463
|
-
// Step 1: Pay into project A and trigger payout to B.
|
|
464
|
-
_payAndSendPayouts(projectIdA, 10 ether, 10 ether);
|
|
465
|
-
|
|
466
|
-
// B now has: balance = 10 ETH, _feeFreeSurplusOf = 10 ETH.
|
|
467
|
-
assertEq(
|
|
468
|
-
_readFeeFreeSurplus(projectIdB, JBConstants.NATIVE_TOKEN),
|
|
469
|
-
_store.balanceOf(address(_terminal), projectIdB, JBConstants.NATIVE_TOKEN),
|
|
470
|
-
"Initial: fee-free surplus should equal balance"
|
|
471
|
-
);
|
|
472
|
-
|
|
473
|
-
// Step 2: Pay project B directly (increases balance but NOT fee-free surplus).
|
|
474
|
-
_payProject(projectIdB, makeAddr("f4-direct-payer"), 10 ether);
|
|
475
|
-
|
|
476
|
-
// B now has: balance = 20 ETH, _feeFreeSurplusOf = 10 ETH.
|
|
477
|
-
assertEq(
|
|
478
|
-
_store.balanceOf(address(_terminal), projectIdB, JBConstants.NATIVE_TOKEN),
|
|
479
|
-
20 ether,
|
|
480
|
-
"Balance should be 20 ETH after direct payment"
|
|
481
|
-
);
|
|
482
|
-
|
|
483
|
-
// Step 3: Cash out half of the direct payer's tokens and verify the invariant.
|
|
484
|
-
_cashOutHalfAndVerifyInvariant(projectIdB, makeAddr("f4-direct-payer"));
|
|
485
|
-
|
|
486
|
-
// Step 4: Cash out remaining tokens and verify again.
|
|
487
|
-
_cashOutRemainingAndVerifyInvariant(projectIdB, makeAddr("f4-direct-payer"));
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/// @dev Cash out half of a holder's tokens and assert the fee-free surplus invariant.
|
|
491
|
-
function _cashOutHalfAndVerifyInvariant(uint256 projectId, address holder) private {
|
|
492
|
-
uint256 holderTokens = _tokens.totalBalanceOf(holder, projectId);
|
|
493
|
-
uint256 halfTokens = holderTokens / 2;
|
|
494
|
-
|
|
495
|
-
vm.prank(holder);
|
|
496
|
-
uint256 reclaim = _terminal.cashOutTokensOf({
|
|
497
|
-
holder: holder,
|
|
498
|
-
projectId: projectId,
|
|
499
|
-
cashOutCount: halfTokens,
|
|
500
|
-
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
501
|
-
minTokensReclaimed: 0,
|
|
502
|
-
beneficiary: payable(holder),
|
|
503
|
-
metadata: new bytes(0)
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
assertLe(
|
|
507
|
-
_readFeeFreeSurplus(projectId, JBConstants.NATIVE_TOKEN),
|
|
508
|
-
_store.balanceOf(address(_terminal), projectId, JBConstants.NATIVE_TOKEN),
|
|
509
|
-
"F-4: _feeFreeSurplusOf must be <= STORE.balanceOf after partial cashout"
|
|
510
|
-
);
|
|
511
|
-
assertGt(reclaim, 0, "Partial cashout should reclaim something");
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
/// @dev Cash out remaining tokens for a holder and assert the fee-free surplus invariant.
|
|
515
|
-
function _cashOutRemainingAndVerifyInvariant(uint256 projectId, address holder) private {
|
|
516
|
-
uint256 remaining = _tokens.totalBalanceOf(holder, projectId);
|
|
517
|
-
if (remaining == 0) return;
|
|
518
|
-
|
|
519
|
-
vm.prank(holder);
|
|
520
|
-
uint256 reclaim = _terminal.cashOutTokensOf({
|
|
521
|
-
holder: holder,
|
|
522
|
-
projectId: projectId,
|
|
523
|
-
cashOutCount: remaining,
|
|
524
|
-
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
525
|
-
minTokensReclaimed: 0,
|
|
526
|
-
beneficiary: payable(holder),
|
|
527
|
-
metadata: new bytes(0)
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
assertLe(
|
|
531
|
-
_readFeeFreeSurplus(projectId, JBConstants.NATIVE_TOKEN),
|
|
532
|
-
_store.balanceOf(address(_terminal), projectId, JBConstants.NATIVE_TOKEN),
|
|
533
|
-
"F-4: _feeFreeSurplusOf must be <= STORE.balanceOf after second cashout"
|
|
534
|
-
);
|
|
535
|
-
assertGt(reclaim, 0, "Second cashout should reclaim something");
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
/// @notice After a cashout that fully drains a project's balance, _feeFreeSurplusOf should be zero.
|
|
539
|
-
/// This prevents overcharging fees on subsequent direct payments.
|
|
540
|
-
function test_F4_feeFreeSurplusZeroAfterFullDrain() external {
|
|
541
|
-
// Fee project.
|
|
542
|
-
_launchFeeProject();
|
|
543
|
-
|
|
544
|
-
// Launch project B and project A with payout split to B.
|
|
545
|
-
(uint256 projectIdA, uint256 projectIdB) = _launchPayoutPairForF4("f4-drain");
|
|
546
|
-
|
|
547
|
-
// Pay project A, send payouts to B.
|
|
548
|
-
_payAndSendPayouts(projectIdA, 10 ether, 10 ether);
|
|
549
|
-
|
|
550
|
-
// B: balance = 10 ETH, feeFreeSurplus = 10 ETH. No token holders in B (addToBalance doesn't mint).
|
|
551
|
-
// To cash out, we need someone to pay B directly first so they get tokens.
|
|
552
|
-
_payProject(projectIdB, makeAddr("f4-casher"), 10 ether);
|
|
553
|
-
|
|
554
|
-
// B: balance = 20 ETH, feeFreeSurplus = 10 ETH.
|
|
555
|
-
// Cash out ALL tokens (this is the only holder, so they get the full balance).
|
|
556
|
-
_cashOutAll(projectIdB, makeAddr("f4-casher"));
|
|
557
|
-
|
|
558
|
-
// After full drain, fee-free surplus should be capped at 0 (or whatever balance remains after fees).
|
|
559
|
-
uint256 feeFreeSurplusAfterDrain = _readFeeFreeSurplus(projectIdB, JBConstants.NATIVE_TOKEN);
|
|
560
|
-
uint256 balanceAfterDrain = _store.balanceOf(address(_terminal), projectIdB, JBConstants.NATIVE_TOKEN);
|
|
561
|
-
|
|
562
|
-
assertLe(
|
|
563
|
-
feeFreeSurplusAfterDrain, balanceAfterDrain, "F-4: fee-free surplus must be <= balance after full drain"
|
|
564
|
-
);
|
|
565
|
-
|
|
566
|
-
// Now pay B again directly. This should be fee-free since fee-free surplus was cleared.
|
|
567
|
-
_payProject(projectIdB, makeAddr("f4-fresh-user"), 5 ether);
|
|
568
|
-
|
|
569
|
-
// Cash out and verify it's fee-free.
|
|
570
|
-
_verifyFeeFreeCashOut(projectIdB, makeAddr("f4-fresh-user"), 5 ether);
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
// ==========================================
|
|
574
|
-
// Helper functions
|
|
575
|
-
// ==========================================
|
|
576
|
-
|
|
577
|
-
/// @dev Launch a pair of projects for the F-4 drain test: project B (zero tax) and project A (100% split to B).
|
|
578
|
-
function _launchPayoutPairForF4(string memory label) private returns (uint256 projectIdA, uint256 projectIdB) {
|
|
579
|
-
// Project B: zero tax.
|
|
580
|
-
JBRulesetConfig[] memory rulesetConfigB = new JBRulesetConfig[](1);
|
|
581
|
-
rulesetConfigB[0] = _makeRulesetConfig({
|
|
582
|
-
duration: 0,
|
|
583
|
-
metadata: _defaultMetadata(),
|
|
584
|
-
splitGroups: new JBSplitGroup[](0),
|
|
585
|
-
fundAccessLimitGroups: new JBFundAccessLimitGroup[](0)
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
projectIdB = _controller.launchProjectFor({
|
|
589
|
-
owner: _projectOwner,
|
|
590
|
-
projectUri: string.concat("project-b-", label),
|
|
591
|
-
rulesetConfigurations: rulesetConfigB,
|
|
592
|
-
terminalConfigurations: _makeTerminalConfig(),
|
|
593
|
-
memo: ""
|
|
594
|
-
});
|
|
595
|
-
|
|
596
|
-
vm.prank(_projectOwner);
|
|
597
|
-
_controller.deployERC20For(projectIdB, "PBDrain", "PBD", bytes32(0));
|
|
598
|
-
|
|
599
|
-
// Project A: 100% split to B (addToBalance).
|
|
600
|
-
JBSplit[] memory splits = new JBSplit[](1);
|
|
601
|
-
splits[0] = JBSplit({
|
|
602
|
-
preferAddToBalance: true,
|
|
603
|
-
percent: JBConstants.SPLITS_TOTAL_PERCENT,
|
|
604
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
605
|
-
projectId: uint64(projectIdB),
|
|
606
|
-
beneficiary: payable(address(0)),
|
|
607
|
-
lockedUntil: 0,
|
|
608
|
-
hook: IJBSplitHook(address(0))
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
JBSplitGroup[] memory splitGroups = new JBSplitGroup[](1);
|
|
612
|
-
splitGroups[0] = JBSplitGroup({groupId: uint32(uint160(JBConstants.NATIVE_TOKEN)), splits: splits});
|
|
613
|
-
|
|
614
|
-
JBFundAccessLimitGroup[] memory fundAccess = _makeFundAccessLimitGroup(10 ether);
|
|
615
|
-
|
|
616
|
-
JBRulesetConfig[] memory rulesetConfigA = new JBRulesetConfig[](1);
|
|
617
|
-
rulesetConfigA[0] = _makeRulesetConfig({
|
|
618
|
-
duration: 0, metadata: _defaultMetadata(), splitGroups: splitGroups, fundAccessLimitGroups: fundAccess
|
|
619
|
-
});
|
|
620
|
-
|
|
621
|
-
projectIdA = _controller.launchProjectFor({
|
|
622
|
-
owner: _projectOwner,
|
|
623
|
-
projectUri: string.concat("project-a-", label),
|
|
624
|
-
rulesetConfigurations: rulesetConfigA,
|
|
625
|
-
terminalConfigurations: _makeTerminalConfig(),
|
|
626
|
-
memo: ""
|
|
627
|
-
});
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
/// @dev Pay a project and then send payouts for the given amount.
|
|
631
|
-
function _payAndSendPayouts(uint256 projectId, uint256 payAmount, uint224 payoutAmount) private {
|
|
632
|
-
address payer = makeAddr("pay-and-send-payer");
|
|
633
|
-
vm.deal(payer, payAmount);
|
|
634
|
-
vm.prank(payer);
|
|
635
|
-
_terminal.pay{value: payAmount}({
|
|
636
|
-
projectId: projectId,
|
|
637
|
-
amount: payAmount,
|
|
638
|
-
token: JBConstants.NATIVE_TOKEN,
|
|
639
|
-
beneficiary: payer,
|
|
640
|
-
minReturnedTokens: 0,
|
|
641
|
-
memo: "",
|
|
642
|
-
metadata: new bytes(0)
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
_terminal.sendPayoutsOf({
|
|
646
|
-
projectId: projectId,
|
|
647
|
-
token: JBConstants.NATIVE_TOKEN,
|
|
648
|
-
amount: payoutAmount,
|
|
649
|
-
currency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
650
|
-
minTokensPaidOut: 0
|
|
651
|
-
});
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
/// @dev Pay ETH directly into a project as the given user.
|
|
655
|
-
function _payProject(uint256 projectId, address user, uint256 amount) private {
|
|
656
|
-
vm.deal(user, amount);
|
|
657
|
-
vm.prank(user);
|
|
658
|
-
_terminal.pay{value: amount}({
|
|
659
|
-
projectId: projectId,
|
|
660
|
-
amount: amount,
|
|
661
|
-
token: JBConstants.NATIVE_TOKEN,
|
|
662
|
-
beneficiary: user,
|
|
663
|
-
minReturnedTokens: 0,
|
|
664
|
-
memo: "",
|
|
665
|
-
metadata: new bytes(0)
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
/// @dev Cash out all tokens for a holder from a project.
|
|
670
|
-
function _cashOutAll(uint256 projectId, address holder) private {
|
|
671
|
-
uint256 tokenBalance = _tokens.totalBalanceOf(holder, projectId);
|
|
672
|
-
if (tokenBalance == 0) return;
|
|
673
|
-
|
|
674
|
-
vm.prank(holder);
|
|
675
|
-
_terminal.cashOutTokensOf({
|
|
676
|
-
holder: holder,
|
|
677
|
-
projectId: projectId,
|
|
678
|
-
cashOutCount: tokenBalance,
|
|
679
|
-
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
680
|
-
minTokensReclaimed: 0,
|
|
681
|
-
beneficiary: payable(holder),
|
|
682
|
-
metadata: new bytes(0)
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
/// @dev Verify that cashing out all tokens returns the exact expected amount (fee-free).
|
|
687
|
-
function _verifyFeeFreeCashOut(uint256 projectId, address holder, uint256 expectedAmount) private {
|
|
688
|
-
uint256 tokenBalance = _tokens.totalBalanceOf(holder, projectId);
|
|
689
|
-
assertGt(tokenBalance, 0, "Holder should have tokens");
|
|
690
|
-
|
|
691
|
-
vm.prank(holder);
|
|
692
|
-
uint256 reclaimAmount = _terminal.cashOutTokensOf({
|
|
693
|
-
holder: holder,
|
|
694
|
-
projectId: projectId,
|
|
695
|
-
cashOutCount: tokenBalance,
|
|
696
|
-
tokenToReclaim: JBConstants.NATIVE_TOKEN,
|
|
697
|
-
minTokensReclaimed: 0,
|
|
698
|
-
beneficiary: payable(holder),
|
|
699
|
-
metadata: new bytes(0)
|
|
700
|
-
});
|
|
701
|
-
|
|
702
|
-
assertEq(reclaimAmount, expectedAmount, "Direct payment cashout should be fee-free");
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
/// @notice Read `_feeFreeSurplusOf[projectId][token]` from JBMultiTerminal storage via vm.load.
|
|
706
|
-
function _readFeeFreeSurplus(uint256 projectId, address token) private view returns (uint256) {
|
|
707
|
-
bytes32 innerSlot = keccak256(abi.encode(projectId, FEE_FREE_SURPLUS_SLOT));
|
|
708
|
-
bytes32 finalSlot = keccak256(abi.encode(token, innerSlot));
|
|
709
|
-
return uint256(vm.load(address(_terminal), finalSlot));
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
/// @notice Launch the fee project (project #1) required by the protocol for fee collection.
|
|
713
|
-
function _launchFeeProject() private returns (uint256) {
|
|
714
|
-
JBRulesetConfig[] memory rc = new JBRulesetConfig[](1);
|
|
715
|
-
rc[0] = _makeRulesetConfig({
|
|
716
|
-
duration: 0,
|
|
717
|
-
metadata: _defaultMetadata(),
|
|
718
|
-
splitGroups: new JBSplitGroup[](0),
|
|
719
|
-
fundAccessLimitGroups: new JBFundAccessLimitGroup[](0)
|
|
720
|
-
});
|
|
721
|
-
|
|
722
|
-
return _controller.launchProjectFor({
|
|
723
|
-
owner: makeAddr("fee-owner"),
|
|
724
|
-
projectUri: "fee-project",
|
|
725
|
-
rulesetConfigurations: rc,
|
|
726
|
-
terminalConfigurations: _makeTerminalConfig(),
|
|
727
|
-
memo: ""
|
|
728
|
-
});
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
/// @notice Build default ruleset metadata with zero tax rate and no data hook.
|
|
732
|
-
function _defaultMetadata() private pure returns (JBRulesetMetadata memory) {
|
|
733
|
-
return JBRulesetMetadata({
|
|
734
|
-
reservedPercent: 0,
|
|
735
|
-
cashOutTaxRate: 0,
|
|
736
|
-
baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
737
|
-
pausePay: false,
|
|
738
|
-
pauseCreditTransfers: false,
|
|
739
|
-
allowOwnerMinting: false,
|
|
740
|
-
allowSetCustomToken: false,
|
|
741
|
-
allowTerminalMigration: false,
|
|
742
|
-
allowSetTerminals: false,
|
|
743
|
-
ownerMustSendPayouts: false,
|
|
744
|
-
allowSetController: false,
|
|
745
|
-
allowAddAccountingContext: true,
|
|
746
|
-
allowAddPriceFeed: false,
|
|
747
|
-
holdFees: false,
|
|
748
|
-
useTotalSurplusForCashOuts: false,
|
|
749
|
-
useDataHookForPay: false,
|
|
750
|
-
useDataHookForCashOut: false,
|
|
751
|
-
dataHook: address(0),
|
|
752
|
-
metadata: 0
|
|
753
|
-
});
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
/// @notice Build a standard terminal configuration accepting native ETH.
|
|
757
|
-
function _makeTerminalConfig() private view returns (JBTerminalConfig[] memory termConfigs) {
|
|
758
|
-
JBAccountingContext[] memory ctxs = new JBAccountingContext[](1);
|
|
759
|
-
ctxs[0] = JBAccountingContext({
|
|
760
|
-
token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
761
|
-
});
|
|
762
|
-
|
|
763
|
-
termConfigs = new JBTerminalConfig[](1);
|
|
764
|
-
termConfigs[0] = JBTerminalConfig({terminal: _terminal, accountingContextsToAccept: ctxs});
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
/// @notice Build a fund access limit group with a single payout limit in native token.
|
|
768
|
-
function _makeFundAccessLimitGroup(uint224 payoutLimitAmount)
|
|
769
|
-
private
|
|
770
|
-
view
|
|
771
|
-
returns (JBFundAccessLimitGroup[] memory)
|
|
772
|
-
{
|
|
773
|
-
JBCurrencyAmount[] memory payoutLimits = new JBCurrencyAmount[](1);
|
|
774
|
-
payoutLimits[0] =
|
|
775
|
-
JBCurrencyAmount({amount: payoutLimitAmount, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))});
|
|
776
|
-
|
|
777
|
-
JBFundAccessLimitGroup[] memory groups = new JBFundAccessLimitGroup[](1);
|
|
778
|
-
groups[0] = JBFundAccessLimitGroup({
|
|
779
|
-
terminal: address(_terminal),
|
|
780
|
-
token: JBConstants.NATIVE_TOKEN,
|
|
781
|
-
payoutLimits: payoutLimits,
|
|
782
|
-
surplusAllowances: new JBCurrencyAmount[](0)
|
|
783
|
-
});
|
|
784
|
-
|
|
785
|
-
return groups;
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
/// @notice Build a ruleset config with the given parameters.
|
|
789
|
-
function _makeRulesetConfig(
|
|
790
|
-
uint32 duration,
|
|
791
|
-
JBRulesetMetadata memory metadata,
|
|
792
|
-
JBSplitGroup[] memory splitGroups,
|
|
793
|
-
JBFundAccessLimitGroup[] memory fundAccessLimitGroups
|
|
794
|
-
)
|
|
795
|
-
private
|
|
796
|
-
pure
|
|
797
|
-
returns (JBRulesetConfig memory config)
|
|
798
|
-
{
|
|
799
|
-
config.mustStartAtOrAfter = 0;
|
|
800
|
-
config.duration = duration;
|
|
801
|
-
config.weight = WEIGHT;
|
|
802
|
-
config.weightCutPercent = 0;
|
|
803
|
-
config.approvalHook = IJBRulesetApprovalHook(address(0));
|
|
804
|
-
config.metadata = metadata;
|
|
805
|
-
config.splitGroups = splitGroups;
|
|
806
|
-
config.fundAccessLimitGroups = fundAccessLimitGroups;
|
|
807
|
-
}
|
|
808
|
-
}
|