@bananapus/core-v6 0.0.20 → 0.0.22
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 +0 -1
- package/AUDIT_INSTRUCTIONS.md +1 -1
- package/CHANGE_LOG.md +3 -3
- package/RISKS.md +3 -3
- package/SKILLS.md +8 -8
- package/USER_JOURNEYS.md +1 -1
- package/foundry.toml +0 -1
- package/package.json +1 -1
- package/src/JBMultiTerminal.sol +92 -192
- package/src/JBTerminalStore.sol +405 -235
- package/src/interfaces/IJBMultiTerminal.sol +0 -4
- package/src/interfaces/IJBTerminal.sol +4 -4
- package/src/interfaces/IJBTerminalStore.sol +65 -33
- package/src/libraries/JBPayoutSplitGroupLib.sol +3 -4
- package/src/libraries/JBSurplus.sol +3 -4
- package/test/ComprehensiveInvariant.t.sol +5 -7
- package/test/CoreExploitTests.t.sol +18 -23
- package/test/TestCashOut.sol +6 -6
- package/test/TestMultiTerminalSurplus.sol +4 -4
- package/test/TestMultiTokenSurplus.sol +6 -23
- package/test/TestTerminalMigration.sol +2 -7
- package/test/fork/TestSequencerPriceFeedFork.sol +1 -1
- package/test/fork/TestTerminalPreviewParityFork.sol +0 -1
- package/test/invariants/TerminalStoreInvariant.t.sol +5 -7
- package/test/units/static/JBMultiTerminal/JBMultiTerminalSetup.sol +1 -2
- package/test/units/static/JBMultiTerminal/TestAccountingContextsOf.sol +23 -24
- package/test/units/static/JBMultiTerminal/TestAddAccountingContextsFor.sol +79 -119
- package/test/units/static/JBMultiTerminal/TestAddToBalanceOf.sol +33 -26
- package/test/units/static/JBMultiTerminal/TestCashOutTokensOf.sol +32 -27
- package/test/units/static/JBMultiTerminal/TestExecutePayout.sol +22 -4
- package/test/units/static/JBMultiTerminal/TestExecuteProcessFee.sol +8 -5
- package/test/units/static/JBMultiTerminal/TestPay.sol +41 -33
- package/test/units/static/JBMultiTerminal/TestPreviewCashOutFrom.sol +19 -18
- package/test/units/static/JBMultiTerminal/TestPreviewPayFor.sol +38 -22
- package/test/units/static/JBMultiTerminal/TestProcessHeldFeesOf.sol +9 -6
- package/test/units/static/JBMultiTerminal/TestSendPayoutsOf.sol +4 -4
- package/test/units/static/JBMultiTerminal/TestUseAllowanceOf.sol +37 -32
- package/test/units/static/JBSurplus/TestSurplusFuzz.sol +5 -20
- package/test/units/static/JBTerminalStore/JBTerminalStoreSetup.sol +17 -0
- package/test/units/static/JBTerminalStore/TestCurrentReclaimableSurplusOf.sol +120 -246
- package/test/units/static/JBTerminalStore/TestCurrentSurplusOf.sol +29 -7
- package/test/units/static/JBTerminalStore/TestCurrentTotalSurplusOf.sol +88 -20
- package/test/units/static/JBTerminalStore/TestPreviewCashOutFrom.sol +30 -29
- package/test/units/static/JBTerminalStore/TestPreviewPayFrom.sol +46 -16
- package/test/units/static/JBTerminalStore/TestRecordCashOutsFor.sol +24 -53
- package/test/units/static/JBTerminalStore/TestRecordPayoutFor.sol +24 -4
- package/test/units/static/JBTerminalStore/TestRecordUsedAllowanceOf.sol +14 -4
- package/test/units/static/JBTerminalStore/TestUint224Overflow.sol +21 -3
|
@@ -8,7 +8,6 @@ import {IJBFeeTerminal} from "../../../../src/interfaces/IJBFeeTerminal.sol";
|
|
|
8
8
|
import {IJBFeelessAddresses} from "../../../../src/interfaces/IJBFeelessAddresses.sol";
|
|
9
9
|
import {IJBPayoutTerminal} from "../../../../src/interfaces/IJBPayoutTerminal.sol";
|
|
10
10
|
import {IJBRulesetApprovalHook} from "../../../../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
11
|
-
import {IJBRulesets} from "../../../../src/interfaces/IJBRulesets.sol";
|
|
12
11
|
import {IJBTerminalStore} from "../../../../src/interfaces/IJBTerminalStore.sol";
|
|
13
12
|
import {JBAccountingContext} from "../../../../src/structs/JBAccountingContext.sol";
|
|
14
13
|
import {JBPayHookSpecification} from "../../../../src/structs/JBPayHookSpecification.sol";
|
|
@@ -18,7 +17,6 @@ import {JBRulesetMetadataResolver} from "../../../../src/libraries/JBRulesetMeta
|
|
|
18
17
|
import {JBConstants} from "../../../../src/libraries/JBConstants.sol";
|
|
19
18
|
import {JBTokenAmount} from "../../../../src/structs/JBTokenAmount.sol";
|
|
20
19
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
21
|
-
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
22
20
|
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|
23
21
|
import {JBMultiTerminalSetup} from "./JBMultiTerminalSetup.sol";
|
|
24
22
|
|
|
@@ -55,7 +53,7 @@ contract TestUseAllowanceOf_Local is JBMultiTerminalSetup {
|
|
|
55
53
|
// recordUsedAllowance
|
|
56
54
|
mockExpect(
|
|
57
55
|
address(store),
|
|
58
|
-
abi.encodeCall(IJBTerminalStore.recordUsedAllowanceOf, (_projectId, mockTokenContext, 0, 0)),
|
|
56
|
+
abi.encodeCall(IJBTerminalStore.recordUsedAllowanceOf, (_projectId, mockTokenContext.token, 0, 0)),
|
|
59
57
|
abi.encode(returnedRuleset, 0)
|
|
60
58
|
);
|
|
61
59
|
|
|
@@ -88,12 +86,10 @@ contract TestUseAllowanceOf_Local is JBMultiTerminalSetup {
|
|
|
88
86
|
metadata: 0
|
|
89
87
|
});
|
|
90
88
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// recordUsedAllowance
|
|
89
|
+
// recordUsedAllowance — terminal now passes token address directly.
|
|
94
90
|
mockExpect(
|
|
95
91
|
address(store),
|
|
96
|
-
abi.encodeCall(IJBTerminalStore.recordUsedAllowanceOf, (_projectId,
|
|
92
|
+
abi.encodeCall(IJBTerminalStore.recordUsedAllowanceOf, (_projectId, mockToken, 100, 0)),
|
|
97
93
|
abi.encode(returnedRuleset, 100)
|
|
98
94
|
);
|
|
99
95
|
|
|
@@ -140,12 +136,10 @@ contract TestUseAllowanceOf_Local is JBMultiTerminalSetup {
|
|
|
140
136
|
metadata: 0
|
|
141
137
|
});
|
|
142
138
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
// recordUsedAllowance
|
|
139
|
+
// recordUsedAllowance — terminal now passes token address directly
|
|
146
140
|
mockExpect(
|
|
147
141
|
address(store),
|
|
148
|
-
abi.encodeCall(IJBTerminalStore.recordUsedAllowanceOf, (_projectId,
|
|
142
|
+
abi.encodeCall(IJBTerminalStore.recordUsedAllowanceOf, (_projectId, mockToken, 100, 0)),
|
|
149
143
|
abi.encode(returnedRuleset, 100)
|
|
150
144
|
);
|
|
151
145
|
|
|
@@ -222,24 +216,30 @@ contract TestUseAllowanceOf_Local is JBMultiTerminalSetup {
|
|
|
222
216
|
metadata: 0
|
|
223
217
|
});
|
|
224
218
|
|
|
225
|
-
// mock call to tokens decimals()
|
|
226
|
-
mockExpect(mockToken, abi.encodeCall(IERC20Metadata.decimals, ()), abi.encode(18));
|
|
227
|
-
|
|
228
|
-
// mock call to rulesets currentOf returning 0 to bypass ruleset checking
|
|
229
|
-
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(returnedRuleset));
|
|
230
|
-
|
|
231
219
|
// call params
|
|
232
220
|
JBAccountingContext[] memory _tokens = new JBAccountingContext[](1);
|
|
233
221
|
_tokens[0] = JBAccountingContext({token: mockToken, decimals: 18, currency: currencyId});
|
|
234
222
|
|
|
223
|
+
// Mock recordAccountingContextOf in the store (validation now happens there)
|
|
224
|
+
mockExpect(
|
|
225
|
+
address(store), abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)), ""
|
|
226
|
+
);
|
|
227
|
+
|
|
235
228
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
236
229
|
|
|
230
|
+
// Mock accountingContextOf for subsequent reads (used by _tokenAmountOf during fee processing)
|
|
231
|
+
mockExpect(
|
|
232
|
+
address(store),
|
|
233
|
+
abi.encodeCall(IJBTerminalStore.accountingContextOf, (address(_terminal), _projectId, mockToken)),
|
|
234
|
+
abi.encode(_tokens[0])
|
|
235
|
+
);
|
|
236
|
+
|
|
237
237
|
_terminal.accountingContextForTokenOf(_projectId, mockToken);
|
|
238
238
|
|
|
239
239
|
// recordUsedAllowance
|
|
240
240
|
mockExpect(
|
|
241
241
|
address(store),
|
|
242
|
-
abi.encodeCall(IJBTerminalStore.recordUsedAllowanceOf, (_projectId, _tokens[0], 100, 0)),
|
|
242
|
+
abi.encodeCall(IJBTerminalStore.recordUsedAllowanceOf, (_projectId, _tokens[0].token, 100, 0)),
|
|
243
243
|
abi.encode(returnedRuleset, 100)
|
|
244
244
|
);
|
|
245
245
|
|
|
@@ -370,22 +370,21 @@ contract TestUseAllowanceOf_Local is JBMultiTerminalSetup {
|
|
|
370
370
|
metadata: packedMetadata
|
|
371
371
|
});
|
|
372
372
|
|
|
373
|
-
// mock call to tokens decimals()
|
|
374
|
-
mockExpect(mockToken, abi.encodeCall(IERC20Metadata.decimals, ()), abi.encode(18));
|
|
375
|
-
|
|
376
|
-
// mock call to rulesets currentOf
|
|
377
|
-
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(returnedRuleset));
|
|
378
|
-
|
|
379
373
|
// Set up accounting context so the token is recognized
|
|
380
374
|
JBAccountingContext[] memory _tokens = new JBAccountingContext[](1);
|
|
381
375
|
_tokens[0] = JBAccountingContext({token: mockToken, decimals: 18, currency: currencyId});
|
|
382
376
|
|
|
377
|
+
// Mock recordAccountingContextOf in the store (validation now happens there)
|
|
378
|
+
mockExpect(
|
|
379
|
+
address(store), abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)), ""
|
|
380
|
+
);
|
|
381
|
+
|
|
383
382
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
384
383
|
|
|
385
384
|
// recordUsedAllowance
|
|
386
385
|
mockExpect(
|
|
387
386
|
address(store),
|
|
388
|
-
abi.encodeCall(IJBTerminalStore.recordUsedAllowanceOf, (_projectId, _tokens[0], 100, 0)),
|
|
387
|
+
abi.encodeCall(IJBTerminalStore.recordUsedAllowanceOf, (_projectId, _tokens[0].token, 100, 0)),
|
|
389
388
|
abi.encode(returnedRuleset, 100)
|
|
390
389
|
);
|
|
391
390
|
|
|
@@ -499,22 +498,28 @@ contract TestUseAllowanceOf_Local is JBMultiTerminalSetup {
|
|
|
499
498
|
metadata: packedMetadata
|
|
500
499
|
});
|
|
501
500
|
|
|
502
|
-
// mock call to tokens decimals()
|
|
503
|
-
mockExpect(mockToken, abi.encodeCall(IERC20Metadata.decimals, ()), abi.encode(18));
|
|
504
|
-
|
|
505
|
-
// mock call to rulesets currentOf
|
|
506
|
-
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(returnedRuleset));
|
|
507
|
-
|
|
508
501
|
// Set up accounting context
|
|
509
502
|
JBAccountingContext[] memory _tokens = new JBAccountingContext[](1);
|
|
510
503
|
_tokens[0] = JBAccountingContext({token: mockToken, decimals: 18, currency: currencyId});
|
|
511
504
|
|
|
505
|
+
// Mock recordAccountingContextOf in the store (validation now happens there)
|
|
506
|
+
mockExpect(
|
|
507
|
+
address(store), abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)), ""
|
|
508
|
+
);
|
|
509
|
+
|
|
512
510
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
513
511
|
|
|
512
|
+
// Mock accountingContextOf for subsequent reads (used by _tokenAmountOf during fee processing)
|
|
513
|
+
mockExpect(
|
|
514
|
+
address(store),
|
|
515
|
+
abi.encodeCall(IJBTerminalStore.accountingContextOf, (address(_terminal), _projectId, mockToken)),
|
|
516
|
+
abi.encode(_tokens[0])
|
|
517
|
+
);
|
|
518
|
+
|
|
514
519
|
// recordUsedAllowance
|
|
515
520
|
mockExpect(
|
|
516
521
|
address(store),
|
|
517
|
-
abi.encodeCall(IJBTerminalStore.recordUsedAllowanceOf, (_projectId, _tokens[0], 100, 0)),
|
|
522
|
+
abi.encodeCall(IJBTerminalStore.recordUsedAllowanceOf, (_projectId, _tokens[0].token, 100, 0)),
|
|
518
523
|
abi.encode(returnedRuleset, 100)
|
|
519
524
|
);
|
|
520
525
|
|
|
@@ -19,17 +19,7 @@ contract MockSurplusTerminal is ERC165, IJBCashOutTerminal {
|
|
|
19
19
|
surplusAmount = _surplus;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
function currentSurplusOf(
|
|
23
|
-
uint256,
|
|
24
|
-
JBAccountingContext[] memory,
|
|
25
|
-
uint256,
|
|
26
|
-
uint256
|
|
27
|
-
)
|
|
28
|
-
external
|
|
29
|
-
view
|
|
30
|
-
override
|
|
31
|
-
returns (uint256)
|
|
32
|
-
{
|
|
22
|
+
function currentSurplusOf(uint256, address[] calldata, uint256, uint256) external view override returns (uint256) {
|
|
33
23
|
return surplusAmount;
|
|
34
24
|
}
|
|
35
25
|
|
|
@@ -131,9 +121,8 @@ contract TestSurplusFuzz_Local is JBTest {
|
|
|
131
121
|
/// @notice Surplus with no terminals is 0.
|
|
132
122
|
function testFuzz_noTerminals_returnsZero(uint256 projectId) external view {
|
|
133
123
|
IJBTerminal[] memory terminals = new IJBTerminal[](0);
|
|
134
|
-
JBAccountingContext[] memory contexts = new JBAccountingContext[](0);
|
|
135
124
|
|
|
136
|
-
uint256 surplus = JBSurplus.currentSurplusOf(projectId, terminals,
|
|
125
|
+
uint256 surplus = JBSurplus.currentSurplusOf(projectId, terminals, new address[](0), 18, 1);
|
|
137
126
|
assertEq(surplus, 0, "surplus with no terminals should be 0");
|
|
138
127
|
}
|
|
139
128
|
|
|
@@ -146,9 +135,7 @@ contract TestSurplusFuzz_Local is JBTest {
|
|
|
146
135
|
terminals[0] = terminal1;
|
|
147
136
|
terminals[1] = terminal2;
|
|
148
137
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
uint256 total = JBSurplus.currentSurplusOf(1, terminals, contexts, 18, 1);
|
|
138
|
+
uint256 total = JBSurplus.currentSurplusOf(1, terminals, new address[](0), 18, 1);
|
|
152
139
|
assertEq(total, uint256(surplus1) + uint256(surplus2), "surplus should be sum of all terminals");
|
|
153
140
|
}
|
|
154
141
|
|
|
@@ -165,10 +152,8 @@ contract TestSurplusFuzz_Local is JBTest {
|
|
|
165
152
|
IJBTerminal[] memory terminals2 = new IJBTerminal[](1);
|
|
166
153
|
terminals2[0] = terminal2;
|
|
167
154
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
uint256 total1 = JBSurplus.currentSurplusOf(1, terminals1, contexts, 18, 1);
|
|
171
|
-
uint256 total2 = JBSurplus.currentSurplusOf(1, terminals2, contexts, 18, 1);
|
|
155
|
+
uint256 total1 = JBSurplus.currentSurplusOf(1, terminals1, new address[](0), 18, 1);
|
|
156
|
+
uint256 total2 = JBSurplus.currentSurplusOf(1, terminals2, new address[](0), 18, 1);
|
|
172
157
|
|
|
173
158
|
assertLe(total1, total2, "surplus should be monotonically increasing");
|
|
174
159
|
}
|
|
@@ -4,8 +4,10 @@ pragma solidity 0.8.26;
|
|
|
4
4
|
import {JBTerminalStore} from "../../../../src/JBTerminalStore.sol";
|
|
5
5
|
import {IJBDirectory} from "../../../../src/interfaces/IJBDirectory.sol";
|
|
6
6
|
import {IJBPrices} from "../../../../src/interfaces/IJBPrices.sol";
|
|
7
|
+
import {IJBRulesetApprovalHook} from "../../../../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
7
8
|
import {IJBRulesets} from "../../../../src/interfaces/IJBRulesets.sol";
|
|
8
9
|
import {IJBTerminalStore} from "../../../../src/interfaces/IJBTerminalStore.sol";
|
|
10
|
+
import {JBRuleset} from "../../../../src/structs/JBRuleset.sol";
|
|
9
11
|
import {JBTest} from "../../../helpers/JBTest.sol";
|
|
10
12
|
|
|
11
13
|
/*
|
|
@@ -24,5 +26,20 @@ contract JBTerminalStoreSetup is JBTest {
|
|
|
24
26
|
function terminalStoreSetup() public virtual {
|
|
25
27
|
// Instantiate the contract being tested
|
|
26
28
|
_store = new JBTerminalStore(directory, prices, rulesets);
|
|
29
|
+
|
|
30
|
+
// Default mock: allow adding accounting contexts (return zero-id ruleset to bypass the
|
|
31
|
+
// allowAddAccountingContext check in recordAccountingContextOf).
|
|
32
|
+
JBRuleset memory _zeroRuleset = JBRuleset({
|
|
33
|
+
cycleNumber: 0,
|
|
34
|
+
id: 0,
|
|
35
|
+
basedOnId: 0,
|
|
36
|
+
start: 0,
|
|
37
|
+
duration: 0,
|
|
38
|
+
weight: 0,
|
|
39
|
+
weightCutPercent: 0,
|
|
40
|
+
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
41
|
+
metadata: 0
|
|
42
|
+
});
|
|
43
|
+
vm.mockCall(address(rulesets), abi.encodeWithSelector(IJBRulesets.currentOf.selector), abi.encode(_zeroRuleset));
|
|
27
44
|
}
|
|
28
45
|
}
|