@bananapus/core-v6 0.0.15 → 0.0.17
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/ADMINISTRATION.md +5 -1
- package/ARCHITECTURE.md +2 -1
- package/AUDIT_INSTRUCTIONS.md +342 -0
- package/CHANGE_LOG.md +375 -0
- package/README.md +6 -6
- package/RISKS.md +171 -50
- package/SKILLS.md +11 -6
- package/STYLE_GUIDE.md +16 -2
- package/USER_JOURNEYS.md +622 -0
- package/package.json +2 -2
- package/script/Deploy.s.sol +22 -13
- package/script/DeployPeriphery.s.sol +76 -52
- package/script/helpers/CoreDeploymentLib.sol +83 -35
- package/src/JBChainlinkV3PriceFeed.sol +1 -0
- package/src/JBController.sol +23 -3
- package/src/JBDeadline.sol +3 -0
- package/src/JBDirectory.sol +2 -1
- package/src/JBERC20.sol +12 -3
- package/src/JBFundAccessLimits.sol +12 -2
- package/src/JBMultiTerminal.sol +53 -10
- package/src/JBPermissions.sol +3 -0
- package/src/JBPrices.sol +8 -2
- package/src/JBProjects.sol +1 -1
- package/src/JBRulesets.sol +14 -0
- package/src/JBSplits.sol +14 -5
- package/src/JBTerminalStore.sol +57 -47
- package/src/JBTokens.sol +43 -4
- package/src/interfaces/IJBController.sol +6 -0
- package/src/interfaces/IJBPermitTerminal.sol +1 -0
- package/src/interfaces/IJBTerminalStore.sol +3 -0
- package/src/interfaces/IJBToken.sol +5 -0
- package/src/interfaces/IJBTokens.sol +13 -0
- package/src/libraries/JBFees.sol +2 -0
- package/src/libraries/JBMetadataResolver.sol +24 -7
- package/src/libraries/JBRulesetMetadataResolver.sol +21 -21
- package/src/structs/JBAccountingContext.sol +1 -0
- package/src/structs/JBAfterCashOutRecordedContext.sol +1 -0
- package/src/structs/JBAfterPayRecordedContext.sol +1 -0
- package/src/structs/JBBeforeCashOutRecordedContext.sol +5 -0
- package/src/structs/JBBeforePayRecordedContext.sol +1 -0
- package/src/structs/JBCashOutHookSpecification.sol +1 -0
- package/src/structs/JBCurrencyAmount.sol +1 -0
- package/src/structs/JBFee.sol +1 -0
- package/src/structs/JBFundAccessLimitGroup.sol +1 -0
- package/src/structs/JBPayHookSpecification.sol +1 -0
- package/src/structs/JBPermissionsData.sol +1 -0
- package/src/structs/JBRuleset.sol +1 -0
- package/src/structs/JBRulesetConfig.sol +1 -0
- package/src/structs/JBRulesetMetadata.sol +1 -0
- package/src/structs/JBRulesetWeightCache.sol +1 -0
- package/src/structs/JBRulesetWithMetadata.sol +1 -0
- package/src/structs/JBSingleAllowance.sol +1 -0
- package/src/structs/JBSplit.sol +1 -0
- package/src/structs/JBSplitGroup.sol +1 -0
- package/src/structs/JBSplitHookContext.sol +1 -0
- package/src/structs/JBTerminalConfig.sol +1 -0
- package/src/structs/JBTokenAmount.sol +1 -0
- package/test/ComprehensiveInvariant.t.sol +15 -2
- package/test/CoreExploitTests.t.sol +34 -1
- package/test/EconomicSimulation.t.sol +10 -2
- package/test/EntryPointPermutations.t.sol +17 -3
- package/test/FlashLoanAttacks.t.sol +12 -1
- package/test/PermissionEscalation.t.sol +53 -10
- package/test/RulesetTransitions.t.sol +15 -1
- package/test/SplitLoopTests.t.sol +25 -2
- package/test/TestAccessToFunds.sol +17 -2
- package/test/TestAuditResponseDesignProofs.sol +434 -0
- package/test/TestCashOut.sol +15 -1
- package/test/TestCashOutCountFor.sol +1 -1
- package/test/TestCashOutHooks.sol +47 -25
- package/test/TestCashOutTimingEdge.sol +13 -1
- package/test/TestDataHookFuzzing.sol +520 -0
- package/test/TestDurationUnderflow.sol +13 -1
- package/test/TestFeeFreeCashOutBypass.sol +617 -0
- package/test/TestFeeProcessingFailure.sol +16 -1
- package/test/TestFees.sol +14 -1
- package/test/TestInterfaceSupport.sol +20 -1
- package/test/TestJBERC20Inheritance.sol +11 -1
- package/test/TestL2SequencerPriceFeed.sol +292 -0
- package/test/TestLaunchProject.sol +13 -1
- package/test/TestMetaTx.sol +15 -1
- package/test/TestMetadataOffsetOverflow.sol +179 -0
- package/test/TestMetadataParserLib.sol +37 -4
- package/test/TestMigrationHeldFees.sol +16 -1
- package/test/TestMintTokensOf.sol +14 -1
- package/test/TestMultiTerminalSurplus.sol +348 -0
- package/test/TestMultiTokenSurplus.sol +14 -1
- package/test/TestMultipleAccessLimits.sol +23 -1
- package/test/TestPayBurnRedeemFlow.sol +16 -1
- package/test/TestPayHooks.sol +33 -14
- package/test/TestPermissions.sol +20 -1
- package/test/TestPermissionsEdge.sol +5 -1
- package/test/TestPermit2DataHook.t.sol +360 -0
- package/test/TestPermit2Terminal.sol +36 -3
- package/test/TestRulesetQueueing.sol +23 -1
- package/test/TestRulesetQueuingStress.sol +20 -1
- package/test/TestRulesetWeightCaching.sol +127 -125
- package/test/TestSplits.sol +23 -1
- package/test/TestTerminalMigration.sol +11 -1
- package/test/TestTokenFlow.sol +18 -1
- package/test/TestWeightCacheStaleAfterRejection.sol +15 -1
- package/test/WeirdTokenTests.t.sol +54 -1
- package/test/fork/TestChainlinkPriceFeedFork.sol +6 -1
- package/test/formal/BondingCurveProperties.t.sol +8 -1
- package/test/formal/FeeProperties.t.sol +7 -1
- package/test/helpers/JBTest.sol +1 -1
- package/test/helpers/TestBaseWorkflow.sol +84 -1
- package/test/invariants/Phase3DeepInvariant.t.sol +13 -2
- package/test/invariants/RulesetsInvariant.t.sol +12 -2
- package/test/invariants/TerminalStoreInvariant.t.sol +11 -2
- package/test/invariants/TokensInvariant.t.sol +13 -2
- package/test/invariants/handlers/ComprehensiveHandler.sol +19 -1
- package/test/invariants/handlers/EconomicHandler.sol +31 -1
- package/test/invariants/handlers/Phase3Handler.sol +31 -1
- package/test/invariants/handlers/RulesetsHandler.sol +5 -1
- package/test/invariants/handlers/TerminalStoreHandler.sol +6 -1
- package/test/invariants/handlers/TokensHandler.sol +1 -1
- package/test/mock/MockERC20.sol +0 -2
- package/test/mock/MockMaliciousBeneficiary.sol +2 -1
- package/test/mock/MockMaliciousSplitHook.sol +2 -1
- package/test/mock/MockPriceFeed.sol +1 -1
- package/test/regression/HoldFeesCashOutReserved.t.sol +415 -0
- package/test/regression/WeightCacheBoundary.t.sol +291 -0
- package/test/units/static/JBChainlinkV3PriceFeed/TestPriceFeed.sol +0 -1
- package/test/units/static/JBController/JBControllerSetup.sol +10 -1
- package/test/units/static/JBController/TestBurnTokensOf.sol +8 -1
- package/test/units/static/JBController/TestClaimTokensFor.sol +4 -1
- package/test/units/static/JBController/TestDeployErc20For.sol +7 -1
- package/test/units/static/JBController/TestLaunchProjectFor.sol +21 -1
- package/test/units/static/JBController/TestLaunchRulesetsFor.sol +21 -1
- package/test/units/static/JBController/TestMigrateController.sol +10 -1
- package/test/units/static/JBController/TestMintTokensOfUnits.sol +10 -1
- package/test/units/static/JBController/TestPayReservedTokenToTerminal.sol +4 -1
- package/test/units/static/JBController/TestReceiveMigrationFrom.sol +5 -1
- package/test/units/static/JBController/TestRulesetViews.sol +7 -1
- package/test/units/static/JBController/TestSendReservedTokensToSplitsOf.sol +21 -1
- package/test/units/static/JBController/TestSetSplitGroupsOf.sol +6 -1
- package/test/units/static/JBController/TestSetTokenFor.sol +13 -1
- package/test/units/static/JBController/TestSetUriOf.sol +5 -1
- package/test/units/static/JBController/TestTransferCreditsFrom.sol +11 -1
- package/test/units/static/JBDeadline/TestDeadlineFuzz.sol +12 -1
- package/test/units/static/JBDirectory/JBDirectorySetup.sol +4 -1
- package/test/units/static/JBDirectory/TestPrimaryTerminalOf.sol +5 -1
- package/test/units/static/JBDirectory/TestSetControllerOf.sol +11 -1
- package/test/units/static/JBDirectory/TestSetControllerOfMigrationOrder.sol +7 -1
- package/test/units/static/JBDirectory/TestSetPrimaryTerminalOf.sol +11 -1
- package/test/units/static/JBDirectory/TestSetTerminalsOf.sol +10 -1
- package/test/units/static/JBERC20/JBERC20Setup.sol +2 -1
- package/test/units/static/JBERC20/SigUtils.sol +2 -0
- package/test/units/static/JBERC20/TestInitialize.sol +1 -1
- package/test/units/static/JBERC20/TestName.sol +1 -1
- package/test/units/static/JBERC20/TestNonces.sol +3 -1
- package/test/units/static/JBERC20/TestSymbol.sol +1 -1
- package/test/units/static/JBFeelessAdresses/JBFeelessSetup.sol +2 -1
- package/test/units/static/JBFeelessAdresses/TestInterfaces.sol +2 -1
- package/test/units/static/JBFeelessAdresses/TestSetFeelessAddress.sol +1 -1
- package/test/units/static/JBFees/TestFeesFuzz.sol +1 -1
- package/test/units/static/JBFixedPointNumber/TestAdjustDecimals.sol +0 -1
- package/test/units/static/JBFixedPointNumber/TestAdjustDecimalsFuzz.sol +0 -1
- package/test/units/static/JBFundAccessLimits/JBFundAccessSetup.sol +3 -1
- package/test/units/static/JBFundAccessLimits/TestFundAccessLimitsEdge.sol +4 -1
- package/test/units/static/JBFundAccessLimits/TestPayoutLimitOf.sol +4 -1
- package/test/units/static/JBFundAccessLimits/TestPayoutLimitsOf.sol +8 -1
- package/test/units/static/JBFundAccessLimits/TestSetFundAccessLimitsFor.sol +8 -1
- package/test/units/static/JBFundAccessLimits/TestSurplusAllowanceOf.sol +4 -1
- package/test/units/static/JBFundAccessLimits/TestSurplusAllowancesOf.sol +7 -1
- package/test/units/static/JBMetadataResolver/TestGetDataFor.sol +1 -1
- package/test/units/static/JBMetadataResolver/TestMetadataResolverEdgeCases.sol +2 -1
- package/test/units/static/JBMetadataResolver/TestMetadataResolverFuzz.sol +2 -1
- package/test/units/static/JBMultiTerminal/JBMultiTerminalSetup.sol +12 -1
- package/test/units/static/JBMultiTerminal/TestAccountingContextsOf.sol +9 -1
- package/test/units/static/JBMultiTerminal/TestAddAccountingContextsFor.sol +18 -2
- package/test/units/static/JBMultiTerminal/TestAddToBalanceOf.sol +44 -9
- package/test/units/static/JBMultiTerminal/TestCashOutTokensOf.sol +48 -23
- package/test/units/static/JBMultiTerminal/TestExecutePayout.sol +18 -2
- package/test/units/static/JBMultiTerminal/TestExecuteProcessFee.sol +13 -3
- package/test/units/static/JBMultiTerminal/TestMigrateBalanceOf.sol +21 -4
- package/test/units/static/JBMultiTerminal/TestPay.sol +35 -7
- package/test/units/static/JBMultiTerminal/TestProcessHeldFeesOf.sol +206 -19
- package/test/units/static/JBMultiTerminal/TestSendPayoutsOf.sol +15 -1
- package/test/units/static/JBMultiTerminal/TestUseAllowanceOf.sol +297 -1
- package/test/units/static/JBPermissions/JBPermissionsSetup.sol +2 -1
- package/test/units/static/JBPermissions/TestHasPermission.sol +1 -1
- package/test/units/static/JBPermissions/TestHasPermissions.sol +1 -1
- package/test/units/static/JBPermissions/TestSetPermissionsFor.sol +3 -1
- package/test/units/static/JBPrices/JBPricesSetup.sol +6 -1
- package/test/units/static/JBPrices/TestAddPriceFeedFor.sol +6 -1
- package/test/units/static/JBPrices/TestPricePerUnitOf.sol +4 -1
- package/test/units/static/JBPrices/TestPrices.sol +4 -1
- package/test/units/static/JBProjects/JBProjectsSetup.sol +2 -1
- package/test/units/static/JBProjects/TestCreateFor.sol +3 -1
- package/test/units/static/JBProjects/TestInitialProject.sol +2 -1
- package/test/units/static/JBProjects/TestInterfaces.sol +0 -1
- package/test/units/static/JBProjects/TestSetResolver.sol +2 -1
- package/test/units/static/JBProjects/TestTokenUri.sol +3 -1
- package/test/units/static/JBRulesetMetadataResolver/TestSetCashOutTaxRateTo.sol +9 -1
- package/test/units/static/JBRulesets/JBRulesetsSetup.sol +3 -1
- package/test/units/static/JBRulesets/TestCurrentApprovalStatusForLatestRulesetOf.sol +9 -1
- package/test/units/static/JBRulesets/TestCurrentOf.sol +10 -1
- package/test/units/static/JBRulesets/TestGetRulesetOf.sol +7 -1
- package/test/units/static/JBRulesets/TestLatestQueuedRulesetOf.sol +9 -1
- package/test/units/static/JBRulesets/TestRulesets.sol +12 -1
- package/test/units/static/JBRulesets/TestRulesetsOf.sol +1 -1
- package/test/units/static/JBRulesets/TestUpcomingRulesetOf.sol +10 -1
- package/test/units/static/JBRulesets/TestUpdateRulesetWeightCache.sol +6 -1
- package/test/units/static/JBSplits/JBSplitsSetup.sol +3 -1
- package/test/units/static/JBSplits/TestSelfManagedSplitGroups.sol +63 -13
- package/test/units/static/JBSplits/TestSetSplitGroupsOf.sol +8 -1
- package/test/units/static/JBSplits/TestSplitsLockedEdge.sol +6 -1
- package/test/units/static/JBSplits/TestSplitsOf.sol +1 -1
- package/test/units/static/JBSplits/TestSplitsPacking.sol +5 -2
- package/test/units/static/JBSurplus/TestSurplusFuzz.sol +3 -1
- package/test/units/static/JBTerminalStore/JBTerminalStoreSetup.sol +5 -1
- package/test/units/static/JBTerminalStore/TestCurrentReclaimableSurplusOf.sol +14 -1
- package/test/units/static/JBTerminalStore/TestCurrentSurplusOf.sol +14 -1
- package/test/units/static/JBTerminalStore/TestCurrentTotalSurplusOf.sol +3 -1
- package/test/units/static/JBTerminalStore/TestRecordCashOutsFor.sol +92 -1
- package/test/units/static/JBTerminalStore/TestRecordPaymentFrom.sol +15 -1
- package/test/units/static/JBTerminalStore/TestRecordPayoutFor.sol +13 -1
- package/test/units/static/JBTerminalStore/TestRecordTerminalMigration.sol +8 -1
- package/test/units/static/JBTerminalStore/TestRecordUsedAllowanceOf.sol +16 -1
- package/test/units/static/JBTerminalStore/TestUint224Overflow.sol +15 -1
- package/test/units/static/JBTokens/JBTokensSetup.sol +5 -1
- package/test/units/static/JBTokens/TestBurnFrom.sol +4 -1
- package/test/units/static/JBTokens/TestClaimTokensFor.sol +4 -1
- package/test/units/static/JBTokens/TestDeployERC20ForUnits.sol +4 -1
- package/test/units/static/JBTokens/TestMintFor.sol +4 -1
- package/test/units/static/JBTokens/TestSetTokenFor.sol +4 -1
- package/test/units/static/JBTokens/TestTotalBalanceOf.sol +1 -1
- package/test/units/static/JBTokens/TestTotalSupplyOf.sol +1 -1
- package/test/units/static/JBTokens/TestTransferCreditsFrom.sol +3 -1
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.6;
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
|
|
5
|
+
import {JBDeadline} from "../src/JBDeadline.sol";
|
|
6
|
+
import {JBApprovalStatus} from "../src/enums/JBApprovalStatus.sol";
|
|
7
|
+
import {IJBController} from "../src/interfaces/IJBController.sol";
|
|
8
|
+
import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
9
|
+
import {IJBRulesets} from "../src/interfaces/IJBRulesets.sol";
|
|
10
|
+
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
11
|
+
import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
|
|
12
|
+
import {JBRuleset} from "../src/structs/JBRuleset.sol";
|
|
13
|
+
import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
|
|
14
|
+
import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
|
|
15
|
+
import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
|
|
16
|
+
import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
|
|
17
|
+
import {IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
|
|
5
18
|
|
|
6
19
|
/// @notice Mock approval hook that always returns a configurable status.
|
|
7
20
|
contract MockApprovalHookConfigurable is IJBRulesetApprovalHook {
|
|
@@ -350,6 +363,7 @@ contract MockApprovalHookConfigurable is IJBRulesetApprovalHook {
|
|
|
350
363
|
pid,
|
|
351
364
|
0,
|
|
352
365
|
FOURTEEN_DAYS,
|
|
366
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
353
367
|
uint112(INITIAL_WEIGHT + uint112(i) * 100e18),
|
|
354
368
|
0,
|
|
355
369
|
IJBRulesetApprovalHook(address(0))
|
|
@@ -544,6 +558,7 @@ contract MockApprovalHookConfigurable is IJBRulesetApprovalHook {
|
|
|
544
558
|
|
|
545
559
|
_queueRuleset(
|
|
546
560
|
pid,
|
|
561
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
547
562
|
uint48(originalStart + SEVEN_DAYS),
|
|
548
563
|
SEVEN_DAYS,
|
|
549
564
|
INITIAL_WEIGHT * 2,
|
|
@@ -563,6 +578,7 @@ contract MockApprovalHookConfigurable is IJBRulesetApprovalHook {
|
|
|
563
578
|
// 1 second after first boundary -> should snap to second boundary.
|
|
564
579
|
_queueRuleset(
|
|
565
580
|
pid,
|
|
581
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
566
582
|
uint48(originalStart + SEVEN_DAYS + 1),
|
|
567
583
|
SEVEN_DAYS,
|
|
568
584
|
INITIAL_WEIGHT * 2,
|
|
@@ -599,6 +615,7 @@ contract MockApprovalHookConfigurable is IJBRulesetApprovalHook {
|
|
|
599
615
|
pid,
|
|
600
616
|
0,
|
|
601
617
|
SEVEN_DAYS,
|
|
618
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
602
619
|
uint112(INITIAL_WEIGHT + uint112(i) * 100e18),
|
|
603
620
|
0,
|
|
604
621
|
IJBRulesetApprovalHook(address(0))
|
|
@@ -608,6 +625,7 @@ contract MockApprovalHookConfigurable is IJBRulesetApprovalHook {
|
|
|
608
625
|
JBRuleset memory current = _rulesets.currentOf(pid);
|
|
609
626
|
assertEq(
|
|
610
627
|
current.weight,
|
|
628
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
611
629
|
INITIAL_WEIGHT + uint112(i) * 100e18,
|
|
612
630
|
string.concat("Cycle ", vm.toString(i + 1), " weight mismatch")
|
|
613
631
|
);
|
|
@@ -765,6 +783,7 @@ contract MockApprovalHookConfigurable is IJBRulesetApprovalHook {
|
|
|
765
783
|
pid,
|
|
766
784
|
0,
|
|
767
785
|
SEVEN_DAYS,
|
|
786
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
768
787
|
uint112(INITIAL_WEIGHT + uint112(i) * 100e18),
|
|
769
788
|
0,
|
|
770
789
|
IJBRulesetApprovalHook(address(0))
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity >=0.8.6;
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
|
|
5
|
+
import {IJBController} from "../src/interfaces/IJBController.sol";
|
|
6
|
+
import {IJBRulesets} from "../src/interfaces/IJBRulesets.sol";
|
|
7
|
+
import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
8
|
+
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
9
|
+
import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
|
|
10
|
+
import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
|
|
11
|
+
import {JBRuleset} from "../src/structs/JBRuleset.sol";
|
|
12
|
+
import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
|
|
13
|
+
import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
|
|
14
|
+
import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
|
|
5
15
|
|
|
6
16
|
// A ruleset's weight can be cached to make larger intervals calculable while staying within the gas limit.
|
|
7
17
|
contract TestRulesetWeightCaching_Local is TestBaseWorkflow {
|
|
@@ -47,130 +57,122 @@ contract TestRulesetWeightCaching_Local is TestBaseWorkflow {
|
|
|
47
57
|
}
|
|
48
58
|
|
|
49
59
|
/// Test that caching a ruleset's weight yields the same result as computing it.
|
|
60
|
+
/// @dev Bounded to 1,000 rulesets for CI speed. For full coverage (80,000), run:
|
|
61
|
+
/// forge test --match-test testWeightCaching -vvv --fuzz-runs 8
|
|
50
62
|
function testWeightCaching(uint256 _rulesetDiff) public {
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
// // Go many rolled over rulesets into the future.
|
|
166
|
-
// vm.warp(block.timestamp + (_DURATION * _rulesetDiff));
|
|
167
|
-
|
|
168
|
-
// // Queue the ruleset.
|
|
169
|
-
// vm.prank(_projectOwner);
|
|
170
|
-
// _controller.queueRulesetsOf({
|
|
171
|
-
// projectId: _projectId2,
|
|
172
|
-
// rulesetConfigurations: _rulesetConfigurations,
|
|
173
|
-
// memo: ""
|
|
174
|
-
// });
|
|
63
|
+
// Bound to a CI-friendly range. The cache threshold is 20,000 iterations;
|
|
64
|
+
// 1,000 is enough to exercise the caching path without extreme gas usage.
|
|
65
|
+
_rulesetDiff = bound(_rulesetDiff, 0, 1000);
|
|
66
|
+
|
|
67
|
+
// Keep references to the projects.
|
|
68
|
+
uint256 _projectId1;
|
|
69
|
+
uint256 _projectId2;
|
|
70
|
+
|
|
71
|
+
// Package up the ruleset configuration.
|
|
72
|
+
JBRulesetConfig[] memory _rulesetConfigurations = new JBRulesetConfig[](1);
|
|
73
|
+
|
|
74
|
+
{
|
|
75
|
+
_rulesetConfigurations[0].mustStartAtOrAfter = 0;
|
|
76
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
77
|
+
_rulesetConfigurations[0].duration = uint32(_DURATION); // safe: _DURATION = 1
|
|
78
|
+
_rulesetConfigurations[0].weight = uint112(1000 * 10 ** _WEIGHT_DECIMALS);
|
|
79
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
80
|
+
_rulesetConfigurations[0].weightCutPercent = uint32(_WEIGHT_CUT_PERCENT); // safe: _WEIGHT_CUT_PERCENT = 1
|
|
81
|
+
_rulesetConfigurations[0].approvalHook = IJBRulesetApprovalHook(address(0));
|
|
82
|
+
_rulesetConfigurations[0].metadata = _metadata;
|
|
83
|
+
_rulesetConfigurations[0].splitGroups = new JBSplitGroup[](0);
|
|
84
|
+
_rulesetConfigurations[0].fundAccessLimitGroups = new JBFundAccessLimitGroup[](0);
|
|
85
|
+
|
|
86
|
+
// Create the project to test.
|
|
87
|
+
_projectId1 = _controller.launchProjectFor({
|
|
88
|
+
owner: _projectOwner,
|
|
89
|
+
projectUri: "myIPFSHash",
|
|
90
|
+
rulesetConfigurations: _rulesetConfigurations,
|
|
91
|
+
terminalConfigurations: new JBTerminalConfig[](0),
|
|
92
|
+
memo: ""
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Create the project to test.
|
|
96
|
+
_projectId2 = _controller.launchProjectFor({
|
|
97
|
+
owner: _projectOwner,
|
|
98
|
+
projectUri: "myIPFSHash",
|
|
99
|
+
rulesetConfigurations: _rulesetConfigurations,
|
|
100
|
+
terminalConfigurations: new JBTerminalConfig[](0),
|
|
101
|
+
memo: ""
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Keep a reference to the current rulesets.
|
|
106
|
+
JBRuleset memory _ruleset1 = jbRulesets().currentOf(_projectId1);
|
|
107
|
+
JBRuleset memory _ruleset2 = jbRulesets().currentOf(_projectId2);
|
|
108
|
+
|
|
109
|
+
// Go a few rolled over rulesets into the future.
|
|
110
|
+
vm.warp(block.timestamp + (_DURATION * 10));
|
|
111
|
+
|
|
112
|
+
// Keep a reference to the amount of gas before the caching call.
|
|
113
|
+
uint256 _gasBeforeCache = gasleft();
|
|
114
|
+
|
|
115
|
+
// Cache the weight in the second project using the latest ruleset ID.
|
|
116
|
+
_rulesets.updateRulesetWeightCache(_projectId2, _rulesets.latestRulesetIdOf(_projectId2));
|
|
117
|
+
|
|
118
|
+
// Keep a reference to the amount of gas spent on the call.
|
|
119
|
+
uint256 _gasDiffCache = _gasBeforeCache - gasleft();
|
|
120
|
+
|
|
121
|
+
// Make sure the difference is within the gas limit.
|
|
122
|
+
assertLe(_gasDiffCache, _GAS_LIMIT);
|
|
123
|
+
|
|
124
|
+
// Go many rolled over rulesets into the future.
|
|
125
|
+
vm.warp(block.timestamp + (_DURATION * _rulesetDiff));
|
|
126
|
+
|
|
127
|
+
// Cache the weight in the second project again.
|
|
128
|
+
_rulesets.updateRulesetWeightCache(_projectId2, _rulesets.latestRulesetIdOf(_projectId2));
|
|
129
|
+
|
|
130
|
+
// Inherit the weight (weight=1 is the inherit sentinel in the current API).
|
|
131
|
+
_rulesetConfigurations[0].weight = 1;
|
|
132
|
+
|
|
133
|
+
// Keep a reference to the amount of gas before the call.
|
|
134
|
+
uint256 _gasBefore1 = gasleft();
|
|
135
|
+
|
|
136
|
+
// Queue the ruleset.
|
|
137
|
+
vm.startPrank(_projectOwner);
|
|
138
|
+
_controller.queueRulesetsOf({projectId: _projectId1, rulesetConfigurations: _rulesetConfigurations, memo: ""});
|
|
139
|
+
|
|
140
|
+
// Keep a reference to the amount of gas spent on the call.
|
|
141
|
+
uint256 _gasDiff1 = _gasBefore1 - gasleft();
|
|
142
|
+
|
|
143
|
+
// Make sure the difference is within the gas limit.
|
|
144
|
+
assertLe(_gasDiff1, _GAS_LIMIT);
|
|
145
|
+
|
|
146
|
+
// Keep a reference to the amount of gas before the call.
|
|
147
|
+
uint256 _gasBefore2 = gasleft();
|
|
148
|
+
|
|
149
|
+
_controller.queueRulesetsOf({projectId: _projectId2, rulesetConfigurations: _rulesetConfigurations, memo: ""});
|
|
150
|
+
vm.stopPrank();
|
|
151
|
+
|
|
152
|
+
// Keep a reference to the amount of gas spent on the call.
|
|
153
|
+
uint256 _gasDiff2 = _gasBefore2 - gasleft();
|
|
154
|
+
|
|
155
|
+
// Make sure the difference is within the gas limit.
|
|
156
|
+
assertLe(_gasDiff2, _GAS_LIMIT);
|
|
157
|
+
|
|
158
|
+
// Renew the reference to the current ruleset.
|
|
159
|
+
_ruleset1 = jbRulesets().currentOf(_projectId1);
|
|
160
|
+
_ruleset2 = jbRulesets().currentOf(_projectId2);
|
|
161
|
+
|
|
162
|
+
// The cached call should have been cheaper.
|
|
163
|
+
assertLe(_gasDiff2, _gasDiff1);
|
|
164
|
+
|
|
165
|
+
// Make sure the rulesets have the same weight.
|
|
166
|
+
assertEq(_ruleset1.weight, _ruleset2.weight);
|
|
167
|
+
|
|
168
|
+
// Cache the weight in the second project again.
|
|
169
|
+
_rulesets.updateRulesetWeightCache(_projectId2, _rulesets.latestRulesetIdOf(_projectId2));
|
|
170
|
+
|
|
171
|
+
// Go many rolled over rulesets into the future.
|
|
172
|
+
vm.warp(block.timestamp + (_DURATION * _rulesetDiff));
|
|
173
|
+
|
|
174
|
+
// Queue the ruleset.
|
|
175
|
+
vm.prank(_projectOwner);
|
|
176
|
+
_controller.queueRulesetsOf({projectId: _projectId2, rulesetConfigurations: _rulesetConfigurations, memo: ""});
|
|
175
177
|
}
|
|
176
178
|
}
|
package/test/TestSplits.sol
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.6;
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
|
|
5
|
+
import {JBTerminalStore} from "../src/JBTerminalStore.sol";
|
|
6
|
+
import {IJBController} from "../src/interfaces/IJBController.sol";
|
|
7
|
+
import {IJBDirectory} from "../src/interfaces/IJBDirectory.sol";
|
|
8
|
+
import {IJBMultiTerminal} from "../src/interfaces/IJBMultiTerminal.sol";
|
|
9
|
+
import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
10
|
+
import {IJBSplitHook} from "../src/interfaces/IJBSplitHook.sol";
|
|
11
|
+
import {IJBTerminal} from "../src/interfaces/IJBTerminal.sol";
|
|
12
|
+
import {IJBTokens} from "../src/interfaces/IJBTokens.sol";
|
|
13
|
+
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
14
|
+
import {JBSplitGroupIds} from "../src/libraries/JBSplitGroupIds.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 {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
|
|
19
|
+
import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
|
|
20
|
+
import {JBSplit} from "../src/structs/JBSplit.sol";
|
|
21
|
+
import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
|
|
22
|
+
import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
|
|
23
|
+
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
24
|
+
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
5
25
|
|
|
6
26
|
contract TestSplits_Local is TestBaseWorkflow {
|
|
7
27
|
IJBController private _controller;
|
|
@@ -304,6 +324,7 @@ contract TestSplits_Local is TestBaseWorkflow {
|
|
|
304
324
|
// Set up a payout split recipient.
|
|
305
325
|
_splits[0] = JBSplit({
|
|
306
326
|
preferAddToBalance: false,
|
|
327
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
307
328
|
percent: uint32(JBConstants.SPLITS_TOTAL_PERCENT / _multiplier),
|
|
308
329
|
projectId: 0,
|
|
309
330
|
beneficiary: _splitsGuy,
|
|
@@ -314,6 +335,7 @@ contract TestSplits_Local is TestBaseWorkflow {
|
|
|
314
335
|
// A dummy used to check that splits groups of "0" don't bypass payout limits.
|
|
315
336
|
_splits[1] = JBSplit({
|
|
316
337
|
preferAddToBalance: false,
|
|
338
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
317
339
|
percent: uint32(JBConstants.SPLITS_TOTAL_PERCENT / _multiplier),
|
|
318
340
|
projectId: 0,
|
|
319
341
|
beneficiary: _splitsGuy,
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.6;
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
|
|
5
|
+
import {JBMultiTerminal} from "../src/JBMultiTerminal.sol";
|
|
6
|
+
import {IJBController} from "../src/interfaces/IJBController.sol";
|
|
7
|
+
import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
8
|
+
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
9
|
+
import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
|
|
10
|
+
import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
|
|
11
|
+
import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
|
|
12
|
+
import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
|
|
13
|
+
import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
|
|
14
|
+
import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
|
|
5
15
|
|
|
6
16
|
/// @notice E2E test: Pay into terminal A -> migrate to terminal B -> verify balances, surplus, cash outs.
|
|
7
17
|
contract TestTerminalMigration_Local is TestBaseWorkflow {
|
package/test/TestTokenFlow.sol
CHANGED
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.6;
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
|
|
5
|
+
import {JBController} from "../src/JBController.sol";
|
|
6
|
+
import {JBERC20} from "../src/JBERC20.sol";
|
|
7
|
+
import {JBTokens} from "../src/JBTokens.sol";
|
|
8
|
+
import {IJBController} from "../src/interfaces/IJBController.sol";
|
|
9
|
+
import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
10
|
+
import {IJBTerminal} from "../src/interfaces/IJBTerminal.sol";
|
|
11
|
+
import {IJBToken} from "../src/interfaces/IJBToken.sol";
|
|
12
|
+
import {IJBTokens} from "../src/interfaces/IJBTokens.sol";
|
|
13
|
+
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
14
|
+
import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
|
|
15
|
+
import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
|
|
16
|
+
import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
|
|
17
|
+
import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
|
|
18
|
+
import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
|
|
19
|
+
import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
|
|
20
|
+
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
|
|
21
|
+
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
5
22
|
|
|
6
23
|
// Launch project, issue token or set the token, mint token, burn token.
|
|
7
24
|
contract TestTokenFlow_Local is TestBaseWorkflow {
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity >=0.8.6;
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
|
|
5
|
+
import {JBApprovalStatus} from "../src/enums/JBApprovalStatus.sol";
|
|
6
|
+
import {IJBController} from "../src/interfaces/IJBController.sol";
|
|
7
|
+
import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
8
|
+
import {IJBRulesets} from "../src/interfaces/IJBRulesets.sol";
|
|
9
|
+
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
10
|
+
import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
|
|
11
|
+
import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
|
|
12
|
+
import {JBRuleset} from "../src/structs/JBRuleset.sol";
|
|
13
|
+
import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
|
|
14
|
+
import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
|
|
15
|
+
import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
|
|
16
|
+
import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
|
|
17
|
+
import {IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
|
|
5
18
|
|
|
6
19
|
/// @notice Mock approval hook that ALWAYS rejects queued rulesets.
|
|
7
20
|
contract AlwaysRejectApprovalHook is IJBRulesetApprovalHook {
|
|
21
|
+
// forge-lint: disable-next-line(mixed-case-function)
|
|
8
22
|
function DURATION() external pure override returns (uint256) {
|
|
9
23
|
return 0;
|
|
10
24
|
}
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.6;
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
|
|
5
|
+
import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
6
|
+
import {IJBSplitHook} from "../src/interfaces/IJBSplitHook.sol";
|
|
7
|
+
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
8
|
+
import {JBRulesetMetadataResolver} from "../src/libraries/JBRulesetMetadataResolver.sol";
|
|
9
|
+
import {JBCurrencyAmount} from "../src/structs/JBCurrencyAmount.sol";
|
|
10
|
+
import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
|
|
11
|
+
import {JBRuleset} from "../src/structs/JBRuleset.sol";
|
|
12
|
+
import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
|
|
13
|
+
import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
|
|
14
|
+
import {JBSplit} from "../src/structs/JBSplit.sol";
|
|
15
|
+
import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
|
|
16
|
+
import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
|
|
5
17
|
import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
|
|
6
18
|
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
|
7
19
|
|
|
@@ -92,6 +104,7 @@ contract WeirdTokenTests_Local is TestBaseWorkflow {
|
|
|
92
104
|
rulesetConfig[0].metadata = JBRulesetMetadata({
|
|
93
105
|
reservedPercent: 0,
|
|
94
106
|
cashOutTaxRate: 0,
|
|
107
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
95
108
|
baseCurrency: uint32(uint160(token)),
|
|
96
109
|
pausePay: false,
|
|
97
110
|
pauseCreditTransfers: false,
|
|
@@ -115,6 +128,7 @@ contract WeirdTokenTests_Local is TestBaseWorkflow {
|
|
|
115
128
|
|
|
116
129
|
JBTerminalConfig[] memory terminalConfigurations = new JBTerminalConfig[](1);
|
|
117
130
|
JBAccountingContext[] memory tokensToAccept = new JBAccountingContext[](1);
|
|
131
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
118
132
|
tokensToAccept[0] = JBAccountingContext({token: token, decimals: decimals, currency: uint32(uint160(token))});
|
|
119
133
|
terminalConfigurations[0] =
|
|
120
134
|
JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: tokensToAccept});
|
|
@@ -161,6 +175,14 @@ contract WeirdTokenTests_Local is TestBaseWorkflow {
|
|
|
161
175
|
// 1% fee: 1000e18 * 99/100 = 990e18
|
|
162
176
|
uint256 expectedDelta = 990e18;
|
|
163
177
|
assertEq(recordedBalance, expectedDelta, "Terminal should record delta amount for FOT tokens");
|
|
178
|
+
|
|
179
|
+
// INVARIANT: recorded balance <= actual token balance at all times.
|
|
180
|
+
uint256 actualTerminalBalance = fotToken.balanceOf(address(jbMultiTerminal()));
|
|
181
|
+
assertLe(
|
|
182
|
+
recordedBalance,
|
|
183
|
+
actualTerminalBalance,
|
|
184
|
+
"FOT: recorded balance must not exceed actual terminal token balance after pay"
|
|
185
|
+
);
|
|
164
186
|
}
|
|
165
187
|
|
|
166
188
|
// ═══════════════════════════════════════════════════════════════════
|
|
@@ -209,6 +231,16 @@ contract WeirdTokenTests_Local is TestBaseWorkflow {
|
|
|
209
231
|
|
|
210
232
|
// Beneficiary receives less than reclaimAmount due to outbound fee
|
|
211
233
|
assertLt(actualReceived, reclaimAmount, "FOT: beneficiary receives less than reclaimAmount on outbound");
|
|
234
|
+
|
|
235
|
+
// INVARIANT: recorded balance <= actual token balance after cash-out.
|
|
236
|
+
uint256 recordedBalanceAfterCashOut =
|
|
237
|
+
jbTerminalStore().balanceOf(address(jbMultiTerminal()), pid, address(fotToken));
|
|
238
|
+
uint256 actualTerminalBalanceAfterCashOut = fotToken.balanceOf(address(jbMultiTerminal()));
|
|
239
|
+
assertLe(
|
|
240
|
+
recordedBalanceAfterCashOut,
|
|
241
|
+
actualTerminalBalanceAfterCashOut,
|
|
242
|
+
"FOT: recorded balance must not exceed actual terminal token balance after cash-out"
|
|
243
|
+
);
|
|
212
244
|
}
|
|
213
245
|
|
|
214
246
|
// ═══════════════════════════════════════════════════════════════════
|
|
@@ -322,6 +354,17 @@ contract WeirdTokenTests_Local is TestBaseWorkflow {
|
|
|
322
354
|
assertTrue(actualReceived > 0, "Split beneficiary should receive something");
|
|
323
355
|
// The terminal sends a computed net amount, but the FOT tax reduces what arrives
|
|
324
356
|
// This documents the information finding: FOT tokens cause split recipients to receive less
|
|
357
|
+
|
|
358
|
+
// INVARIANT: Terminal's recorded balance must never exceed actual token balance.
|
|
359
|
+
// With FOT tokens, the terminal may hold fewer tokens than recorded (inbound fee on pay).
|
|
360
|
+
// After a payout, the recorded balance should still be <= actual balance.
|
|
361
|
+
uint256 recordedBalance = jbTerminalStore().balanceOf(address(jbMultiTerminal()), pid, address(fotToken));
|
|
362
|
+
uint256 actualTerminalBalance = fotToken.balanceOf(address(jbMultiTerminal()));
|
|
363
|
+
assertLe(
|
|
364
|
+
recordedBalance,
|
|
365
|
+
actualTerminalBalance,
|
|
366
|
+
"FOT: recorded balance must not exceed actual terminal token balance after payout"
|
|
367
|
+
);
|
|
325
368
|
}
|
|
326
369
|
|
|
327
370
|
// ═══════════════════════════════════════════════════════════════════
|
|
@@ -560,6 +603,14 @@ contract WeirdTokenTests_Local is TestBaseWorkflow {
|
|
|
560
603
|
|
|
561
604
|
// Balance should increase (delta accounting handles the fee)
|
|
562
605
|
assertGt(recordedAfter, recordedBefore, "Balance should increase with addToBalance");
|
|
606
|
+
|
|
607
|
+
// INVARIANT: recorded balance <= actual token balance after addToBalance.
|
|
608
|
+
uint256 actualTerminalBalance = fotToken.balanceOf(address(jbMultiTerminal()));
|
|
609
|
+
assertLe(
|
|
610
|
+
recordedAfter,
|
|
611
|
+
actualTerminalBalance,
|
|
612
|
+
"FOT: recorded balance must not exceed actual terminal token balance after addToBalance"
|
|
613
|
+
);
|
|
563
614
|
}
|
|
564
615
|
|
|
565
616
|
// ═══════════════════════════════════════════════════════════════════
|
|
@@ -676,9 +727,11 @@ contract RebasingToken is ERC20 {
|
|
|
676
727
|
function rebaseHolder(address target, int256 percent) external {
|
|
677
728
|
uint256 balance = balanceOf(target);
|
|
678
729
|
if (percent > 0) {
|
|
730
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
679
731
|
uint256 increase = (balance * uint256(percent)) / 100;
|
|
680
732
|
_mint(target, increase);
|
|
681
733
|
} else if (percent < 0) {
|
|
734
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
682
735
|
uint256 decrease = (balance * uint256(-percent)) / 100;
|
|
683
736
|
if (decrease > 0 && decrease <= balance) {
|
|
684
737
|
_burn(target, decrease);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity 0.8.26;
|
|
3
3
|
|
|
4
|
-
import "forge-std/Test.sol";
|
|
4
|
+
import {Test} from "forge-std/Test.sol";
|
|
5
5
|
|
|
6
6
|
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
|
|
7
7
|
|
|
@@ -68,6 +68,7 @@ contract TestChainlinkPriceFeedFork is Test {
|
|
|
68
68
|
// Cross-check against raw latestRoundData.
|
|
69
69
|
(, int256 rawPrice,,,) = AggregatorV3Interface(ETH_USD_FEED).latestRoundData();
|
|
70
70
|
uint256 feedDecimals = AggregatorV3Interface(ETH_USD_FEED).decimals();
|
|
71
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
71
72
|
uint256 expected18 = uint256(rawPrice) * 10 ** (18 - feedDecimals);
|
|
72
73
|
assertEq(price18, expected18, "Price mismatch vs raw feed");
|
|
73
74
|
}
|
|
@@ -85,15 +86,19 @@ contract TestChainlinkPriceFeedFork is Test {
|
|
|
85
86
|
|
|
86
87
|
// Raw feed is 8 decimals — price8 should match it exactly.
|
|
87
88
|
(, int256 rawPrice,,,) = AggregatorV3Interface(ETH_USD_FEED).latestRoundData();
|
|
89
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
88
90
|
assertEq(price8, uint256(rawPrice), "8-decimal mismatch");
|
|
89
91
|
|
|
90
92
|
// 6 decimals = raw / 100 (truncated).
|
|
93
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
91
94
|
assertEq(price6, uint256(rawPrice) / 1e2, "6-decimal mismatch");
|
|
92
95
|
|
|
93
96
|
// 18 decimals = raw * 1e10.
|
|
97
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
94
98
|
assertEq(price18, uint256(rawPrice) * 1e10, "18-decimal mismatch");
|
|
95
99
|
|
|
96
100
|
// 27 decimals = raw * 1e19.
|
|
101
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
97
102
|
assertEq(price27, uint256(rawPrice) * 1e19, "27-decimal mismatch");
|
|
98
103
|
}
|
|
99
104
|
|