@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
|
@@ -145,6 +145,8 @@ interface IJBTerminalStore {
|
|
|
145
145
|
/// @param cashOutCount The number of project tokens being cashed out.
|
|
146
146
|
/// @param accountingContext The accounting context of the token being reclaimed.
|
|
147
147
|
/// @param balanceAccountingContexts The accounting contexts to include in the balance calculation.
|
|
148
|
+
/// @param beneficiaryIsFeeless Whether the cash out's beneficiary is a feeless address. Passed through to data
|
|
149
|
+
/// hooks so they can skip their own fees when value stays in the protocol (e.g. project-to-project routing).
|
|
148
150
|
/// @param metadata Extra data to pass along to the data hook.
|
|
149
151
|
/// @return ruleset The project's current ruleset.
|
|
150
152
|
/// @return reclaimAmount The amount reclaimed.
|
|
@@ -156,6 +158,7 @@ interface IJBTerminalStore {
|
|
|
156
158
|
uint256 cashOutCount,
|
|
157
159
|
JBAccountingContext calldata accountingContext,
|
|
158
160
|
JBAccountingContext[] calldata balanceAccountingContexts,
|
|
161
|
+
bool beneficiaryIsFeeless,
|
|
159
162
|
bytes calldata metadata
|
|
160
163
|
)
|
|
161
164
|
external
|
|
@@ -36,4 +36,9 @@ interface IJBToken {
|
|
|
36
36
|
/// @param account The address to mint tokens to.
|
|
37
37
|
/// @param amount The amount of tokens to mint.
|
|
38
38
|
function mint(address account, uint256 amount) external;
|
|
39
|
+
|
|
40
|
+
/// @notice Sets the token's name and symbol.
|
|
41
|
+
/// @param name The new name.
|
|
42
|
+
/// @param symbol The new symbol.
|
|
43
|
+
function setMetadata(string memory name, string memory symbol) external;
|
|
39
44
|
}
|
|
@@ -64,6 +64,13 @@ interface IJBTokens {
|
|
|
64
64
|
/// @param caller The address that set the token.
|
|
65
65
|
event SetToken(uint256 indexed projectId, IJBToken indexed token, address caller);
|
|
66
66
|
|
|
67
|
+
/// @notice A project token's name and symbol were updated.
|
|
68
|
+
/// @param projectId The ID of the project whose token was updated.
|
|
69
|
+
/// @param name The new token name.
|
|
70
|
+
/// @param symbol The new token symbol.
|
|
71
|
+
/// @param caller The address that called the function.
|
|
72
|
+
event SetTokenMetadata(uint256 indexed projectId, string name, string symbol, address caller);
|
|
73
|
+
|
|
67
74
|
/// @notice Credits were transferred from one holder to another.
|
|
68
75
|
/// @param holder The address that transferred the credits.
|
|
69
76
|
/// @param projectId The ID of the project whose credits were transferred.
|
|
@@ -146,6 +153,12 @@ interface IJBTokens {
|
|
|
146
153
|
/// @param token The token to set.
|
|
147
154
|
function setTokenFor(uint256 projectId, IJBToken token) external;
|
|
148
155
|
|
|
156
|
+
/// @notice Sets the name and symbol of a project's token.
|
|
157
|
+
/// @param projectId The ID of the project whose token is being updated.
|
|
158
|
+
/// @param name The new name.
|
|
159
|
+
/// @param symbol The new symbol.
|
|
160
|
+
function setTokenMetadataFor(uint256 projectId, string calldata name, string calldata symbol) external;
|
|
161
|
+
|
|
149
162
|
/// @notice Transfers credits from one holder to another.
|
|
150
163
|
/// @param holder The address to transfer credits from.
|
|
151
164
|
/// @param projectId The ID of the project whose credits are being transferred.
|
package/src/libraries/JBFees.sol
CHANGED
|
@@ -19,6 +19,8 @@ library JBFees {
|
|
|
19
19
|
|
|
20
20
|
/// @notice Returns the fee that would be taken from `amountBeforeFee`.
|
|
21
21
|
/// @dev Use this to forward-calculate the fee from a known pre-fee amount.
|
|
22
|
+
/// @dev Fee rounding error is bounded by N-1 wei (N = number of splits). Economically
|
|
23
|
+
/// insignificant. Rounds down (mulDiv floors), so the fee beneficiary may receive up to 1 wei less per split.
|
|
22
24
|
/// @param amountBeforeFee The amount before the fee is applied, as a fixed point number.
|
|
23
25
|
/// @param feePercent The fee percent, out of `JBConstants.MAX_FEE`.
|
|
24
26
|
/// @return The fee amount, as a fixed point number with the same number of decimals as the provided `amount`.
|
|
@@ -60,17 +60,18 @@ library JBMetadataResolver {
|
|
|
60
60
|
pure
|
|
61
61
|
returns (bytes memory newMetadata)
|
|
62
62
|
{
|
|
63
|
+
// Validate data padding upfront so that the fast path below cannot bypass the check.
|
|
64
|
+
if (dataToAdd.length < 32) revert JBMetadataResolver_DataNotPadded();
|
|
65
|
+
|
|
63
66
|
// Empty original metadata and maybe something in the first 32 bytes: create new metadata
|
|
64
67
|
if (originalMetadata.length <= RESERVED_SIZE) {
|
|
68
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
65
69
|
return abi.encodePacked(bytes32(originalMetadata), bytes32(abi.encodePacked(idToAdd, uint8(2))), dataToAdd);
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
// There is something in the table offset, but not a valid entry - avoid overwriting
|
|
69
73
|
if (originalMetadata.length < RESERVED_SIZE + ID_SIZE + 1) revert JBMetadataResolver_MetadataTooShort();
|
|
70
74
|
|
|
71
|
-
// Make sure the data is padded to 32 bytes.
|
|
72
|
-
if (dataToAdd.length < 32) revert JBMetadataResolver_DataNotPadded();
|
|
73
|
-
|
|
74
75
|
// Get the first data offset - upcast to avoid overflow (same for other offset)...
|
|
75
76
|
uint256 firstOffset = uint8(originalMetadata[RESERVED_SIZE + ID_SIZE]);
|
|
76
77
|
|
|
@@ -96,13 +97,16 @@ library JBMetadataResolver {
|
|
|
96
97
|
numberOfWordslastData = (originalMetadata.length - lastOffset * WORD_SIZE) / WORD_SIZE;
|
|
97
98
|
|
|
98
99
|
// Copy the reserved word and the table and remove the previous padding
|
|
99
|
-
newMetadata = _sliceBytes(originalMetadata, 0, lastOffsetIndex + 1);
|
|
100
|
+
newMetadata = _sliceBytes({data: originalMetadata, start: 0, end: lastOffsetIndex + 1});
|
|
100
101
|
|
|
101
102
|
// Check if the new entry is still fitting in this word
|
|
102
103
|
if (i + TOTAL_ID_SIZE >= firstOffset * WORD_SIZE) {
|
|
103
104
|
// Increment every offset by 1 (as the table now takes one more word)
|
|
104
105
|
for (uint256 j = RESERVED_SIZE + ID_SIZE; j < lastOffsetIndex + 1; j += TOTAL_ID_SIZE) {
|
|
105
|
-
|
|
106
|
+
uint256 incremented = uint256(uint8(originalMetadata[j])) + 1;
|
|
107
|
+
if (incremented > 255) revert JBMetadataResolver_MetadataTooLong();
|
|
108
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
109
|
+
newMetadata[j] = bytes1(uint8(incremented));
|
|
106
110
|
}
|
|
107
111
|
|
|
108
112
|
// Increment the last offset so the new offset will be properly set too
|
|
@@ -118,9 +122,14 @@ library JBMetadataResolver {
|
|
|
118
122
|
// Compute in uint256 first — casting directly to uint8 silently wraps offsets > 255.
|
|
119
123
|
uint256 newOffset = lastOffset + numberOfWordslastData;
|
|
120
124
|
if (newOffset > 255) revert JBMetadataResolver_MetadataTooLong();
|
|
125
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
121
126
|
newMetadata = abi.encodePacked(newMetadata, idToAdd, bytes1(uint8(newOffset)));
|
|
122
127
|
|
|
123
128
|
// Pad as needed - inlined for gas saving
|
|
129
|
+
// The length inflation to the next 32-byte boundary does NOT read uninitialized memory.
|
|
130
|
+
// abi.encodePacked always advances the free memory pointer to a 32-byte-aligned position, so the
|
|
131
|
+
// padding bytes (up to 31) are within the already-allocated region and guaranteed to be zero by
|
|
132
|
+
// Solidity's virgin-memory invariant. The zeros are the intended table padding per the metadata format.
|
|
124
133
|
uint256 paddedLength =
|
|
125
134
|
newMetadata.length % WORD_SIZE == 0 ? newMetadata.length : (newMetadata.length / WORD_SIZE + 1) * WORD_SIZE;
|
|
126
135
|
assembly ("memory-safe") {
|
|
@@ -129,7 +138,8 @@ library JBMetadataResolver {
|
|
|
129
138
|
|
|
130
139
|
// Add existing data at the end
|
|
131
140
|
newMetadata = abi.encodePacked(
|
|
132
|
-
newMetadata,
|
|
141
|
+
newMetadata,
|
|
142
|
+
_sliceBytes({data: originalMetadata, start: firstOffset * WORD_SIZE, end: originalMetadata.length})
|
|
133
143
|
);
|
|
134
144
|
|
|
135
145
|
// Pad as needed
|
|
@@ -159,6 +169,9 @@ library JBMetadataResolver {
|
|
|
159
169
|
function createMetadata(bytes4[] memory ids, bytes[] memory datas) internal pure returns (bytes memory metadata) {
|
|
160
170
|
if (ids.length != datas.length) revert JBMetadataResolver_LengthMismatch();
|
|
161
171
|
|
|
172
|
+
// Return empty bytes for empty input arrays to avoid underflow in offset calculation below.
|
|
173
|
+
if (ids.length == 0) return bytes("");
|
|
174
|
+
|
|
162
175
|
// Add a first empty 32B for the protocol reserved word
|
|
163
176
|
metadata = abi.encodePacked(bytes32(0));
|
|
164
177
|
|
|
@@ -181,6 +194,7 @@ library JBMetadataResolver {
|
|
|
181
194
|
revert JBMetadataResolver_DataNotPadded();
|
|
182
195
|
}
|
|
183
196
|
|
|
197
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
184
198
|
metadata = abi.encodePacked(metadata, ids[i], bytes1(uint8(offset)));
|
|
185
199
|
offset += data.length / JBMetadataResolver.WORD_SIZE;
|
|
186
200
|
|
|
@@ -214,6 +228,9 @@ library JBMetadataResolver {
|
|
|
214
228
|
|
|
215
229
|
/// @notice Parse the metadata to find the data for a specific ID
|
|
216
230
|
/// @dev Returns false and an empty bytes if no data is found
|
|
231
|
+
/// @dev Padding to 32-byte boundaries is required for ABI compatibility. The apparent
|
|
232
|
+
/// inconsistency between creation and parsing is intentional: creation pads for storage alignment,
|
|
233
|
+
/// parsing uses actual data length boundaries from the lookup table.
|
|
217
234
|
/// @param id The ID to find.
|
|
218
235
|
/// @param metadata The metadata to parse.
|
|
219
236
|
/// @return found Whether the {id:data} was found
|
|
@@ -244,7 +261,7 @@ library JBMetadataResolver {
|
|
|
244
261
|
? metadata.length
|
|
245
262
|
: uint256(uint8(metadata[i + NEXT_ID_OFFSET])) * WORD_SIZE;
|
|
246
263
|
|
|
247
|
-
return (true, _sliceBytes(metadata, currentOffset * WORD_SIZE, end));
|
|
264
|
+
return (true, _sliceBytes({data: metadata, start: currentOffset * WORD_SIZE, end: end}));
|
|
248
265
|
}
|
|
249
266
|
unchecked {
|
|
250
267
|
i += TOTAL_ID_SIZE;
|
|
@@ -135,26 +135,26 @@ library JBRulesetMetadataResolver {
|
|
|
135
135
|
/// @param ruleset The funding cycle having its metadata expanded.
|
|
136
136
|
/// @return rulesetMetadata The ruleset's metadata object.
|
|
137
137
|
function expandMetadata(JBRuleset memory ruleset) internal pure returns (JBRulesetMetadata memory) {
|
|
138
|
-
return JBRulesetMetadata(
|
|
139
|
-
reservedPercent(ruleset),
|
|
140
|
-
cashOutTaxRate(ruleset),
|
|
141
|
-
baseCurrency(ruleset),
|
|
142
|
-
pausePay(ruleset),
|
|
143
|
-
pauseCreditTransfers(ruleset),
|
|
144
|
-
allowOwnerMinting(ruleset),
|
|
145
|
-
allowSetCustomToken(ruleset),
|
|
146
|
-
allowTerminalMigration(ruleset),
|
|
147
|
-
allowSetTerminals(ruleset),
|
|
148
|
-
allowSetController(ruleset),
|
|
149
|
-
allowAddAccountingContext(ruleset),
|
|
150
|
-
allowAddPriceFeed(ruleset),
|
|
151
|
-
ownerMustSendPayouts(ruleset),
|
|
152
|
-
holdFees(ruleset),
|
|
153
|
-
useTotalSurplusForCashOuts(ruleset),
|
|
154
|
-
useDataHookForPay(ruleset),
|
|
155
|
-
useDataHookForCashOut(ruleset),
|
|
156
|
-
dataHook(ruleset),
|
|
157
|
-
metadata(ruleset)
|
|
158
|
-
);
|
|
138
|
+
return JBRulesetMetadata({
|
|
139
|
+
reservedPercent: reservedPercent(ruleset),
|
|
140
|
+
cashOutTaxRate: cashOutTaxRate(ruleset),
|
|
141
|
+
baseCurrency: baseCurrency(ruleset),
|
|
142
|
+
pausePay: pausePay(ruleset),
|
|
143
|
+
pauseCreditTransfers: pauseCreditTransfers(ruleset),
|
|
144
|
+
allowOwnerMinting: allowOwnerMinting(ruleset),
|
|
145
|
+
allowSetCustomToken: allowSetCustomToken(ruleset),
|
|
146
|
+
allowTerminalMigration: allowTerminalMigration(ruleset),
|
|
147
|
+
allowSetTerminals: allowSetTerminals(ruleset),
|
|
148
|
+
allowSetController: allowSetController(ruleset),
|
|
149
|
+
allowAddAccountingContext: allowAddAccountingContext(ruleset),
|
|
150
|
+
allowAddPriceFeed: allowAddPriceFeed(ruleset),
|
|
151
|
+
ownerMustSendPayouts: ownerMustSendPayouts(ruleset),
|
|
152
|
+
holdFees: holdFees(ruleset),
|
|
153
|
+
useTotalSurplusForCashOuts: useTotalSurplusForCashOuts(ruleset),
|
|
154
|
+
useDataHookForPay: useDataHookForPay(ruleset),
|
|
155
|
+
useDataHookForCashOut: useDataHookForCashOut(ruleset),
|
|
156
|
+
dataHook: dataHook(ruleset),
|
|
157
|
+
metadata: metadata(ruleset)
|
|
158
|
+
});
|
|
159
159
|
}
|
|
160
160
|
}
|
|
@@ -5,6 +5,7 @@ pragma solidity ^0.8.0;
|
|
|
5
5
|
/// @custom:member decimals The number of decimals expected in that token's fixed point accounting.
|
|
6
6
|
/// @custom:member currency The currency that the token is priced in terms of. By convention, this is
|
|
7
7
|
/// `uint32(uint160(tokenAddress))` for tokens, or a constant ID from e.g. `JBCurrencyIds` for other currencies.
|
|
8
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
8
9
|
struct JBAccountingContext {
|
|
9
10
|
address token;
|
|
10
11
|
uint8 decimals;
|
|
@@ -16,6 +16,7 @@ import {JBTokenAmount} from "./JBTokenAmount.sol";
|
|
|
16
16
|
/// @custom:member beneficiary The address the reclaimed amount will be sent to.
|
|
17
17
|
/// @custom:member hookMetadata Extra data specified by the data hook, which is sent to the cash out hook.
|
|
18
18
|
/// @custom:member cashOutMetadata Extra data specified by the account cashing out, which is sent to the cash out hook.
|
|
19
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
19
20
|
struct JBAfterCashOutRecordedContext {
|
|
20
21
|
address holder;
|
|
21
22
|
uint256 projectId;
|
|
@@ -15,6 +15,7 @@ import {JBTokenAmount} from "./JBTokenAmount.sol";
|
|
|
15
15
|
/// @custom:member beneficiary The address which receives any tokens this payment yields.
|
|
16
16
|
/// @custom:member hookMetadata Extra data specified by the data hook, which is sent to the pay hook.
|
|
17
17
|
/// @custom:member payerMetadata Extra data specified by the payer, which is sent to the pay hook.
|
|
18
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
18
19
|
struct JBAfterPayRecordedContext {
|
|
19
20
|
address payer;
|
|
20
21
|
uint256 projectId;
|
|
@@ -16,7 +16,11 @@ import {JBTokenAmount} from "./JBTokenAmount.sol";
|
|
|
16
16
|
/// included, and the currency of the surplus.
|
|
17
17
|
/// @custom:member useTotalSurplus If surplus across all of a project's terminals is being used when making cash outs.
|
|
18
18
|
/// @custom:member cashOutTaxRate The cash out tax rate of the ruleset the cash out is being made during.
|
|
19
|
+
/// @custom:member beneficiaryIsFeeless Whether the cash out's beneficiary is a feeless address. Useful for data hooks
|
|
20
|
+
/// that charge their own fees — they can skip fees when value stays in the protocol (e.g. project-to-project
|
|
21
|
+
/// routing).
|
|
19
22
|
/// @custom:member metadata Extra data provided by the casher.
|
|
23
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
20
24
|
struct JBBeforeCashOutRecordedContext {
|
|
21
25
|
address terminal;
|
|
22
26
|
address holder;
|
|
@@ -27,5 +31,6 @@ struct JBBeforeCashOutRecordedContext {
|
|
|
27
31
|
JBTokenAmount surplus;
|
|
28
32
|
bool useTotalSurplus;
|
|
29
33
|
uint256 cashOutTaxRate;
|
|
34
|
+
bool beneficiaryIsFeeless;
|
|
30
35
|
bytes metadata;
|
|
31
36
|
}
|
|
@@ -15,6 +15,7 @@ import {JBTokenAmount} from "./JBTokenAmount.sol";
|
|
|
15
15
|
/// @custom:member weight The weight of the ruleset during which the payment is being made.
|
|
16
16
|
/// @custom:member reservedPercent The reserved percent of the ruleset the payment is being made during.
|
|
17
17
|
/// @custom:member metadata Extra data specified by the payer.
|
|
18
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
18
19
|
struct JBBeforePayRecordedContext {
|
|
19
20
|
address terminal;
|
|
20
21
|
address payer;
|
|
@@ -8,6 +8,7 @@ import {IJBCashOutHook} from "../interfaces/IJBCashOutHook.sol";
|
|
|
8
8
|
/// @custom:member hook The cash out hook to use when fulfilling this specification.
|
|
9
9
|
/// @custom:member amount The amount to send to the hook.
|
|
10
10
|
/// @custom:member metadata Metadata to pass to the hook.
|
|
11
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
11
12
|
struct JBCashOutHookSpecification {
|
|
12
13
|
IJBCashOutHook hook;
|
|
13
14
|
uint256 amount;
|
|
@@ -4,6 +4,7 @@ pragma solidity ^0.8.0;
|
|
|
4
4
|
/// @custom:member amount The amount of the currency.
|
|
5
5
|
/// @custom:member currency The currency. By convention, this is `uint32(uint160(tokenAddress))` for tokens, or a
|
|
6
6
|
/// constant ID from e.g. `JBCurrencyIds` for other currencies.
|
|
7
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
7
8
|
struct JBCurrencyAmount {
|
|
8
9
|
uint224 amount;
|
|
9
10
|
uint32 currency;
|
package/src/structs/JBFee.sol
CHANGED
|
@@ -5,6 +5,7 @@ pragma solidity ^0.8.0;
|
|
|
5
5
|
/// decimals as the terminal in which this struct was created.
|
|
6
6
|
/// @custom:member beneficiary The address that will receive the tokens that are minted as a result of the fee payment.
|
|
7
7
|
/// @custom:member unlockTimestamp The timestamp at which the fee is unlocked and can be processed.
|
|
8
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
8
9
|
struct JBFee {
|
|
9
10
|
uint256 amount;
|
|
10
11
|
address beneficiary;
|
|
@@ -20,6 +20,7 @@ import {JBCurrencyAmount} from "./JBCurrencyAmount.sol";
|
|
|
20
20
|
/// @custom:member surplusAllowances An array of surplus allowances. The surplus allowances cumulatively dictates the
|
|
21
21
|
/// maximum value of `token`s a project can pay out from its surplus (balance less payouts) in a terminal during a
|
|
22
22
|
/// ruleset. Each surplus allowance can have a unique currency and amount.
|
|
23
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
23
24
|
struct JBFundAccessLimitGroup {
|
|
24
25
|
address terminal;
|
|
25
26
|
address token;
|
|
@@ -8,6 +8,7 @@ import {IJBPayHook} from "../interfaces/IJBPayHook.sol";
|
|
|
8
8
|
/// @custom:member hook The pay hook to use when fulfilling this specification.
|
|
9
9
|
/// @custom:member amount The amount to send to the hook.
|
|
10
10
|
/// @custom:member metadata Metadata to pass the hook.
|
|
11
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
11
12
|
struct JBPayHookSpecification {
|
|
12
13
|
IJBPayHook hook;
|
|
13
14
|
uint256 amount;
|
|
@@ -6,6 +6,7 @@ pragma solidity ^0.8.0;
|
|
|
6
6
|
/// permissions under this project's scope. An ID of 0 is a wildcard, which gives an operator permissions across all
|
|
7
7
|
/// projects.
|
|
8
8
|
/// @custom:member permissionIds The IDs of the permissions being given. See the `JBPermissionIds` library.
|
|
9
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
9
10
|
struct JBPermissionsData {
|
|
10
11
|
address operator;
|
|
11
12
|
uint64 projectId;
|
|
@@ -29,6 +29,7 @@ import {IJBRulesetApprovalHook} from "./../interfaces/IJBRulesetApprovalHook.sol
|
|
|
29
29
|
/// ruleset is rejected, it won't go into effect. An approval hook can be used to create rules which dictate how a
|
|
30
30
|
/// project owner can change their ruleset over time.
|
|
31
31
|
/// @custom:member metadata Extra data associated with a ruleset which can be used by other contracts.
|
|
32
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
32
33
|
struct JBRuleset {
|
|
33
34
|
uint48 cycleNumber;
|
|
34
35
|
uint48 id;
|
|
@@ -31,6 +31,7 @@ import {JBSplitGroup} from "./JBSplitGroup.sol";
|
|
|
31
31
|
/// its balance in each payment terminal while the ruleset is active. Amounts are fixed point numbers using the same
|
|
32
32
|
/// number of decimals as the corresponding terminal. The `_payoutLimit` and `_surplusAllowance` parameters must fit in
|
|
33
33
|
/// a `uint232`.
|
|
34
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
34
35
|
struct JBRulesetConfig {
|
|
35
36
|
uint48 mustStartAtOrAfter;
|
|
36
37
|
uint32 duration;
|
|
@@ -33,6 +33,7 @@ pragma solidity ^0.8.0;
|
|
|
33
33
|
/// @custom:member dataHook The data hook to use during this ruleset.
|
|
34
34
|
/// @custom:member metadata Metadata of the metadata, only the 14 least significant bits can be used, the 2 most
|
|
35
35
|
/// significant bits are disregarded.
|
|
36
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
36
37
|
struct JBRulesetMetadata {
|
|
37
38
|
uint16 reservedPercent;
|
|
38
39
|
uint16 cashOutTaxRate;
|
|
@@ -3,6 +3,7 @@ pragma solidity ^0.8.0;
|
|
|
3
3
|
|
|
4
4
|
/// @custom:member weight The cached weight value.
|
|
5
5
|
/// @custom:member weightCutMultiple The weight cut multiple that produces the given weight.
|
|
6
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
6
7
|
struct JBRulesetWeightCache {
|
|
7
8
|
uint112 weight;
|
|
8
9
|
uint168 weightCutMultiple;
|
|
@@ -6,6 +6,7 @@ import {JBRulesetMetadata} from "./JBRulesetMetadata.sol";
|
|
|
6
6
|
|
|
7
7
|
/// @custom:member ruleset The ruleset.
|
|
8
8
|
/// @custom:member metadata The ruleset's metadata.
|
|
9
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
9
10
|
struct JBRulesetWithMetadata {
|
|
10
11
|
JBRuleset ruleset;
|
|
11
12
|
JBRulesetMetadata metadata;
|
|
@@ -7,6 +7,7 @@ pragma solidity ^0.8.0;
|
|
|
7
7
|
/// @custom:member nonce An incrementing value indexed per owner,token,and spender for each signature.
|
|
8
8
|
/// @custom:member signature The signature over the permit data. Supports EOA signatures, compact signatures defined by
|
|
9
9
|
/// EIP-2098, and contract signatures defined by EIP-1271.
|
|
10
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
10
11
|
struct JBSingleAllowance {
|
|
11
12
|
uint256 sigDeadline;
|
|
12
13
|
uint160 amount;
|
package/src/structs/JBSplit.sol
CHANGED
|
@@ -27,6 +27,7 @@ import {IJBSplitHook} from "./../interfaces/IJBSplitHook.sol";
|
|
|
27
27
|
/// increased while a split is locked. If `lockedUntil` is zero, this split can be changed at any time.
|
|
28
28
|
/// @custom:member hook A contract which will receive this split's tokens and properties, and can define custom
|
|
29
29
|
/// behavior.
|
|
30
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
30
31
|
struct JBSplit {
|
|
31
32
|
uint32 percent;
|
|
32
33
|
uint64 projectId;
|
|
@@ -6,6 +6,7 @@ import {JBSplit} from "./JBSplit.sol";
|
|
|
6
6
|
/// @custom:member groupId An identifier for the group. By convention, this ID is `uint256(uint160(tokenAddress))` for
|
|
7
7
|
/// payouts and `1` for reserved tokens.
|
|
8
8
|
/// @custom:member splits The splits in the group.
|
|
9
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
9
10
|
struct JBSplitGroup {
|
|
10
11
|
uint256 groupId;
|
|
11
12
|
JBSplit[] splits;
|
|
@@ -10,6 +10,7 @@ import {JBSplit} from "./JBSplit.sol";
|
|
|
10
10
|
/// @custom:member groupId The group the split belongs to. By convention, this ID is `uint256(uint160(tokenAddress))`
|
|
11
11
|
/// for payouts and `1` for reserved tokens.
|
|
12
12
|
/// @custom:member split The split which specified the hook.
|
|
13
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
13
14
|
struct JBSplitHookContext {
|
|
14
15
|
address token;
|
|
15
16
|
uint256 amount;
|
|
@@ -6,6 +6,7 @@ import {IJBTerminal} from "./../interfaces/IJBTerminal.sol";
|
|
|
6
6
|
|
|
7
7
|
/// @custom:member terminal The terminal to configure.
|
|
8
8
|
/// @custom:member accountingContextsToAccept The accounting contexts to accept from the terminal.
|
|
9
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
9
10
|
struct JBTerminalConfig {
|
|
10
11
|
IJBTerminal terminal;
|
|
11
12
|
JBAccountingContext[] accountingContextsToAccept;
|
|
@@ -6,6 +6,7 @@ pragma solidity ^0.8.0;
|
|
|
6
6
|
/// @custom:member currency The currency. By convention, this is `uint32(uint160(tokenAddress))` for tokens, or a
|
|
7
7
|
/// constant ID from e.g. `JBCurrencyIds` for other currencies.
|
|
8
8
|
/// @custom:member value The amount of tokens that was paid, as a fixed point number.
|
|
9
|
+
// forge-lint: disable-next-line(pascal-case-struct)
|
|
9
10
|
struct JBTokenAmount {
|
|
10
11
|
address token;
|
|
11
12
|
uint8 decimals;
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.6;
|
|
3
3
|
|
|
4
|
-
import "forge-std/StdInvariant.sol";
|
|
5
|
-
import
|
|
4
|
+
import {StdInvariant} from "forge-std/StdInvariant.sol";
|
|
5
|
+
import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
|
|
6
|
+
import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
7
|
+
import {IJBSplitHook} from "../src/interfaces/IJBSplitHook.sol";
|
|
8
|
+
import {IJBToken} from "../src/interfaces/IJBToken.sol";
|
|
9
|
+
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
10
|
+
import {JBRulesetMetadataResolver} from "../src/libraries/JBRulesetMetadataResolver.sol";
|
|
11
|
+
import {JBCurrencyAmount} from "../src/structs/JBCurrencyAmount.sol";
|
|
12
|
+
import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
|
|
13
|
+
import {JBRuleset} from "../src/structs/JBRuleset.sol";
|
|
14
|
+
import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
|
|
15
|
+
import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
|
|
16
|
+
import {JBSplit} from "../src/structs/JBSplit.sol";
|
|
17
|
+
import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
|
|
18
|
+
import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
|
|
6
19
|
import {ComprehensiveHandler} from "./invariants/handlers/ComprehensiveHandler.sol";
|
|
7
20
|
import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
|
|
8
21
|
|
|
@@ -1,7 +1,32 @@
|
|
|
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 {MetadataResolverHelper} from "./helpers/MetadataResolverHelper.sol";
|
|
6
|
+
import {MockERC20} from "./mock/MockERC20.sol";
|
|
7
|
+
import {JBMultiTerminal} from "../src/JBMultiTerminal.sol";
|
|
8
|
+
import {JBTokens} from "../src/JBTokens.sol";
|
|
9
|
+
import {JBApprovalStatus} from "../src/enums/JBApprovalStatus.sol";
|
|
10
|
+
import {IJBController} from "../src/interfaces/IJBController.sol";
|
|
11
|
+
import {IJBMultiTerminal} from "../src/interfaces/IJBMultiTerminal.sol";
|
|
12
|
+
import {IJBPayHook} from "../src/interfaces/IJBPayHook.sol";
|
|
13
|
+
import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
14
|
+
import {IJBRulesetDataHook} from "../src/interfaces/IJBRulesetDataHook.sol";
|
|
15
|
+
import {IJBTerminal} from "../src/interfaces/IJBTerminal.sol";
|
|
16
|
+
import {IJBToken} from "../src/interfaces/IJBToken.sol";
|
|
17
|
+
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
18
|
+
import {JBFees} from "../src/libraries/JBFees.sol";
|
|
19
|
+
import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
|
|
20
|
+
import {JBCurrencyAmount} from "../src/structs/JBCurrencyAmount.sol";
|
|
21
|
+
import {JBFee} from "../src/structs/JBFee.sol";
|
|
22
|
+
import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
|
|
23
|
+
import {JBPayHookSpecification} from "../src/structs/JBPayHookSpecification.sol";
|
|
24
|
+
import {JBRuleset} from "../src/structs/JBRuleset.sol";
|
|
25
|
+
import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
|
|
26
|
+
import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
|
|
27
|
+
import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
|
|
28
|
+
import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
|
|
29
|
+
import {ERC165, IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
|
|
5
30
|
import {JBCashOuts} from "../src/libraries/JBCashOuts.sol";
|
|
6
31
|
|
|
7
32
|
/// @notice Tests for edge case scenarios in Juicebox V5.
|
|
@@ -1227,7 +1252,9 @@ contract EdgeCases_Local is TestBaseWorkflow {
|
|
|
1227
1252
|
uint256 hugeBorrow = uint256(type(uint112).max) + 500 ether;
|
|
1228
1253
|
|
|
1229
1254
|
// Silent truncation — Solidity 0.8.x does NOT revert on explicit downcasts!
|
|
1255
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
1230
1256
|
uint112 truncatedCollateral = uint112(hugeCollateral);
|
|
1257
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
1231
1258
|
uint112 truncatedBorrow = uint112(hugeBorrow);
|
|
1232
1259
|
|
|
1233
1260
|
// The truncated values are dramatically smaller.
|
|
@@ -2050,6 +2077,7 @@ contract EdgeCases_Local is TestBaseWorkflow {
|
|
|
2050
2077
|
|
|
2051
2078
|
/// @notice Helper: launches a project with only MockERC20 (6 decimals, simulating USDC on Tempo).
|
|
2052
2079
|
/// No NATIVE_TOKEN accounting context is registered.
|
|
2080
|
+
// forge-lint: disable-next-line(mixed-case-function)
|
|
2053
2081
|
function _launchProjectERC20(uint16 cashOutTaxRate, uint16 reservedPercent) internal returns (uint256 projectId) {
|
|
2054
2082
|
MockERC20 token = usdcToken();
|
|
2055
2083
|
|
|
@@ -2119,6 +2147,7 @@ contract EdgeCases_Local is TestBaseWorkflow {
|
|
|
2119
2147
|
}
|
|
2120
2148
|
|
|
2121
2149
|
/// @notice Helper: launches an ERC-20-only project with payout limits.
|
|
2150
|
+
// forge-lint: disable-next-line(mixed-case-function)
|
|
2122
2151
|
function _launchProjectERC20WithPayoutLimit(
|
|
2123
2152
|
uint16 cashOutTaxRate,
|
|
2124
2153
|
uint224 payoutLimit
|
|
@@ -2632,8 +2661,11 @@ contract ReentrancyAttacker {
|
|
|
2632
2661
|
|
|
2633
2662
|
/// @notice Malicious fee terminal that reenters processHeldFeesOf during pay().
|
|
2634
2663
|
contract ReentrantFeeTerminal is ERC165 {
|
|
2664
|
+
// forge-lint: disable-next-line(screaming-snake-case-immutable)
|
|
2635
2665
|
IJBMultiTerminal public immutable victim;
|
|
2666
|
+
// forge-lint: disable-next-line(screaming-snake-case-immutable)
|
|
2636
2667
|
uint256 public immutable targetProjectId;
|
|
2668
|
+
// forge-lint: disable-next-line(screaming-snake-case-immutable)
|
|
2637
2669
|
address public immutable targetToken;
|
|
2638
2670
|
uint256 public payCallCount;
|
|
2639
2671
|
|
|
@@ -2688,6 +2720,7 @@ contract ReentrantFeeTerminal is ERC165 {
|
|
|
2688
2720
|
|
|
2689
2721
|
/// @notice Malicious approval hook that always reverts.
|
|
2690
2722
|
contract MaliciousApprovalHook is ERC165, IJBRulesetApprovalHook {
|
|
2723
|
+
// forge-lint: disable-next-line(mixed-case-function)
|
|
2691
2724
|
function DURATION() external pure override returns (uint256) {
|
|
2692
2725
|
return 1 days;
|
|
2693
2726
|
}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.6;
|
|
3
3
|
|
|
4
|
-
import "forge-std/StdInvariant.sol";
|
|
5
|
-
import
|
|
4
|
+
import {StdInvariant} from "forge-std/StdInvariant.sol";
|
|
5
|
+
import {TestBaseWorkflow} from "./helpers/TestBaseWorkflow.sol";
|
|
6
|
+
import {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
7
|
+
import {JBRulesetMetadataResolver} from "../src/libraries/JBRulesetMetadataResolver.sol";
|
|
8
|
+
import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
|
|
9
|
+
import {JBRuleset} from "../src/structs/JBRuleset.sol";
|
|
10
|
+
import {JBRulesetConfig} from "../src/structs/JBRulesetConfig.sol";
|
|
11
|
+
import {JBRulesetMetadata} from "../src/structs/JBRulesetMetadata.sol";
|
|
12
|
+
import {JBSplitGroup} from "../src/structs/JBSplitGroup.sol";
|
|
13
|
+
import {JBTerminalConfig} from "../src/structs/JBTerminalConfig.sol";
|
|
6
14
|
import {EconomicHandler} from "./invariants/handlers/EconomicHandler.sol";
|
|
7
15
|
import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
|
|
8
16
|
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
@@ -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 {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
6
|
+
import {JBRulesetMetadataResolver} from "../src/libraries/JBRulesetMetadataResolver.sol";
|
|
7
|
+
import {JBCurrencyAmount} from "../src/structs/JBCurrencyAmount.sol";
|
|
8
|
+
import {JBFee} from "../src/structs/JBFee.sol";
|
|
9
|
+
import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
|
|
10
|
+
import {JBRuleset} from "../src/structs/JBRuleset.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
|
import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
|
|
6
16
|
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
7
17
|
|
|
@@ -592,7 +602,9 @@ contract EntryPointPermutations_Local is TestBaseWorkflow {
|
|
|
592
602
|
if (payoutLimit > 0) {
|
|
593
603
|
payoutLimits = new JBCurrencyAmount[](1);
|
|
594
604
|
payoutLimits[0] = JBCurrencyAmount({
|
|
595
|
-
|
|
605
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
606
|
+
amount: uint224(payoutLimit),
|
|
607
|
+
currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
596
608
|
});
|
|
597
609
|
} else {
|
|
598
610
|
payoutLimits = new JBCurrencyAmount[](0);
|
|
@@ -601,7 +613,9 @@ contract EntryPointPermutations_Local is TestBaseWorkflow {
|
|
|
601
613
|
if (surplusAllowance > 0) {
|
|
602
614
|
surplusAllowances = new JBCurrencyAmount[](1);
|
|
603
615
|
surplusAllowances[0] = JBCurrencyAmount({
|
|
604
|
-
|
|
616
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
617
|
+
amount: uint224(surplusAllowance),
|
|
618
|
+
currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
605
619
|
});
|
|
606
620
|
} else {
|
|
607
621
|
surplusAllowances = new JBCurrencyAmount[](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 {IJBRulesetApprovalHook} from "../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
6
|
+
import {JBConstants} from "../src/libraries/JBConstants.sol";
|
|
7
|
+
import {JBRulesetMetadataResolver} from "../src/libraries/JBRulesetMetadataResolver.sol";
|
|
8
|
+
import {JBCurrencyAmount} from "../src/structs/JBCurrencyAmount.sol";
|
|
9
|
+
import {JBFundAccessLimitGroup} from "../src/structs/JBFundAccessLimitGroup.sol";
|
|
10
|
+
import {JBRuleset} from "../src/structs/JBRuleset.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
|
import {JBAccountingContext} from "../src/structs/JBAccountingContext.sol";
|
|
6
16
|
|
|
7
17
|
/// @notice Tests that flash-loan style atomic pay+cashOut attacks cannot extract profit.
|
|
@@ -548,6 +558,7 @@ contract FlashLoanAttacks_Local is TestBaseWorkflow {
|
|
|
548
558
|
|
|
549
559
|
// Attacker front-runs: pays right before payout
|
|
550
560
|
address attacker = address(0xA77AC0);
|
|
561
|
+
// forge-lint: disable-next-line(mixed-case-variable)
|
|
551
562
|
uint256 attackerInitialETH = 10 ether;
|
|
552
563
|
vm.deal(attacker, attackerInitialETH);
|
|
553
564
|
vm.prank(attacker);
|