@bananapus/core-v6 0.0.21 → 0.0.23
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 +414 -256
- 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 +0 -1
- 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
|
@@ -37,6 +37,21 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
37
37
|
super.terminalStoreSetup();
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/// @notice Helper to register an accounting context with the store (pranks as the terminal).
|
|
41
|
+
function _registerContext(JBAccountingContext memory ctx) internal {
|
|
42
|
+
JBAccountingContext[] memory ctxs = new JBAccountingContext[](1);
|
|
43
|
+
ctxs[0] = ctx;
|
|
44
|
+
vm.prank(address(_terminal));
|
|
45
|
+
_store.recordAccountingContextOf(_projectId, ctxs);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// @notice Helper to call currentSurplusOf with the new multi-terminal signature.
|
|
49
|
+
function _currentSurplusOf(uint256 decimals, uint256 currency) internal view returns (uint256) {
|
|
50
|
+
IJBTerminal[] memory terminals = new IJBTerminal[](1);
|
|
51
|
+
terminals[0] = _terminal;
|
|
52
|
+
return _store.currentSurplusOf(_projectId, terminals, new address[](0), decimals, currency);
|
|
53
|
+
}
|
|
54
|
+
|
|
40
55
|
modifier whenProjectHasBalance() {
|
|
41
56
|
// Find the storage slot
|
|
42
57
|
bytes32 balanceOfSlot = keccak256(abi.encode(address(_terminal), uint256(0)));
|
|
@@ -62,6 +77,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
62
77
|
JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
|
|
63
78
|
|
|
64
79
|
_contexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
|
|
80
|
+
_registerContext(_contexts[0]);
|
|
65
81
|
|
|
66
82
|
// JBRulesets calldata
|
|
67
83
|
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
@@ -101,7 +117,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
101
117
|
bytes memory _payoutLimitsReturn = abi.encode(_payoutLimits);
|
|
102
118
|
mockExpect(address(_accessLimits), _payoutLimitsCall, _payoutLimitsReturn);
|
|
103
119
|
|
|
104
|
-
uint256 currentSurplus =
|
|
120
|
+
uint256 currentSurplus = _currentSurplusOf(6, _currency);
|
|
105
121
|
|
|
106
122
|
// assert correct calcs
|
|
107
123
|
uint256 expectedSurplus = (1e18 - 1e17) / 10 ** (18 - 6);
|
|
@@ -116,6 +132,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
116
132
|
JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
|
|
117
133
|
|
|
118
134
|
_contexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
|
|
135
|
+
_registerContext(_contexts[0]);
|
|
119
136
|
|
|
120
137
|
// JBRulesets calldata
|
|
121
138
|
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
@@ -161,7 +178,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
161
178
|
bytes memory _pricePerReturn = abi.encode(uint256(1));
|
|
162
179
|
mockExpect(address(prices), _pricePerCall, _pricePerReturn);
|
|
163
180
|
|
|
164
|
-
uint256 currentSurplus =
|
|
181
|
+
uint256 currentSurplus = _currentSurplusOf(6, _nativeCurrency);
|
|
165
182
|
|
|
166
183
|
// assert correct calcs
|
|
167
184
|
uint256 expectedSurplus = ((1e18 - 1e17) * 1e18) / 10 ** (18 - 6);
|
|
@@ -174,6 +191,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
174
191
|
JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
|
|
175
192
|
|
|
176
193
|
_contexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
|
|
194
|
+
_registerContext(_contexts[0]);
|
|
177
195
|
|
|
178
196
|
// JBRulesets calldata
|
|
179
197
|
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
@@ -213,7 +231,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
213
231
|
bytes memory _payoutLimitsReturn = abi.encode(_payoutLimits);
|
|
214
232
|
mockExpect(address(_accessLimits), _payoutLimitsCall, _payoutLimitsReturn);
|
|
215
233
|
|
|
216
|
-
uint256 currentSurplus =
|
|
234
|
+
uint256 currentSurplus = _currentSurplusOf(18, _currency);
|
|
217
235
|
|
|
218
236
|
// assert correct calcs
|
|
219
237
|
uint256 expectedSurplus = 1e18 - 1e17;
|
|
@@ -225,6 +243,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
225
243
|
JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
|
|
226
244
|
|
|
227
245
|
_contexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
|
|
246
|
+
_registerContext(_contexts[0]);
|
|
228
247
|
|
|
229
248
|
// JBRulesets calldata
|
|
230
249
|
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
@@ -270,7 +289,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
270
289
|
bytes memory _pricePerReturn = abi.encode(uint256(1));
|
|
271
290
|
mockExpect(address(prices), _pricePerCall, _pricePerReturn);
|
|
272
291
|
|
|
273
|
-
uint256 currentSurplus =
|
|
292
|
+
uint256 currentSurplus = _currentSurplusOf(18, _nativeCurrency);
|
|
274
293
|
|
|
275
294
|
// assert correct calcs
|
|
276
295
|
uint256 expectedSurplus = (1e18 - 1e17) * 1e18;
|
|
@@ -283,6 +302,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
283
302
|
JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
|
|
284
303
|
|
|
285
304
|
_contexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
|
|
305
|
+
_registerContext(_contexts[0]);
|
|
286
306
|
|
|
287
307
|
// JBRulesets calldata
|
|
288
308
|
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
@@ -322,7 +342,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
322
342
|
bytes memory _payoutLimitsReturn = abi.encode(_payoutLimits);
|
|
323
343
|
mockExpect(address(_accessLimits), _payoutLimitsCall, _payoutLimitsReturn);
|
|
324
344
|
|
|
325
|
-
uint256 currentSurplus =
|
|
345
|
+
uint256 currentSurplus = _currentSurplusOf(18, _currency);
|
|
326
346
|
|
|
327
347
|
// assert correct calcs
|
|
328
348
|
uint256 expectedSurplus = (1e18 - 1e17);
|
|
@@ -335,6 +355,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
335
355
|
JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
|
|
336
356
|
|
|
337
357
|
_contexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _nativeCurrency});
|
|
358
|
+
_registerContext(_contexts[0]);
|
|
338
359
|
|
|
339
360
|
// JBRulesets calldata
|
|
340
361
|
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
@@ -380,7 +401,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
380
401
|
bytes memory _pricePerReturn = abi.encode(uint256(1e18));
|
|
381
402
|
mockExpect(address(prices), _pricePerCall, _pricePerReturn);
|
|
382
403
|
|
|
383
|
-
uint256 currentSurplus =
|
|
404
|
+
uint256 currentSurplus = _currentSurplusOf(18, _nativeCurrency);
|
|
384
405
|
|
|
385
406
|
// assert correct calcs
|
|
386
407
|
uint256 expectedSurplus = 1e18 - 1e17;
|
|
@@ -393,6 +414,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
393
414
|
JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
|
|
394
415
|
|
|
395
416
|
_contexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
|
|
417
|
+
_registerContext(_contexts[0]);
|
|
396
418
|
|
|
397
419
|
// JBRulesets calldata
|
|
398
420
|
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
@@ -432,7 +454,7 @@ contract TestCurrentSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
432
454
|
bytes memory _payoutLimitsReturn = abi.encode(_payoutLimits);
|
|
433
455
|
mockExpect(address(_accessLimits), _payoutLimitsCall, _payoutLimitsReturn);
|
|
434
456
|
|
|
435
|
-
uint256 currentSurplus =
|
|
457
|
+
uint256 currentSurplus = _currentSurplusOf(18, _currency);
|
|
436
458
|
|
|
437
459
|
// assert correct calcs
|
|
438
460
|
uint256 expectedSurplus = 0;
|
|
@@ -1,50 +1,107 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity 0.8.26;
|
|
3
3
|
|
|
4
|
+
import {IJBController} from "../../../../src/interfaces/IJBController.sol";
|
|
4
5
|
import {IJBDirectory} from "../../../../src/interfaces/IJBDirectory.sol";
|
|
6
|
+
import {IJBFundAccessLimits} from "../../../../src/interfaces/IJBFundAccessLimits.sol";
|
|
7
|
+
import {IJBRulesetApprovalHook} from "../../../../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
8
|
+
import {IJBRulesets} from "../../../../src/interfaces/IJBRulesets.sol";
|
|
5
9
|
import {IJBTerminal} from "../../../../src/interfaces/IJBTerminal.sol";
|
|
6
10
|
import {JBAccountingContext} from "../../../../src/structs/JBAccountingContext.sol";
|
|
11
|
+
import {JBCurrencyAmount} from "../../../../src/structs/JBCurrencyAmount.sol";
|
|
12
|
+
import {JBRuleset} from "../../../../src/structs/JBRuleset.sol";
|
|
7
13
|
import {JBTerminalStoreSetup} from "./JBTerminalStoreSetup.sol";
|
|
8
14
|
|
|
9
15
|
contract TestCurrentTotalSurplusOf_Local is JBTerminalStoreSetup {
|
|
10
16
|
uint256 _projectId = 1;
|
|
11
17
|
uint256 _decimals = 18;
|
|
12
|
-
uint256 _currency = uint32(uint160(makeAddr("token")));
|
|
13
18
|
|
|
14
19
|
// Mocks
|
|
15
20
|
IJBTerminal _terminal1 = IJBTerminal(makeAddr("terminal1"));
|
|
16
21
|
IJBTerminal _terminal2 = IJBTerminal(makeAddr("terminal2"));
|
|
22
|
+
address _token = makeAddr("token");
|
|
23
|
+
IJBController _controller = IJBController(makeAddr("controller"));
|
|
24
|
+
IJBFundAccessLimits _accessLimits = IJBFundAccessLimits(makeAddr("funds"));
|
|
25
|
+
|
|
26
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
27
|
+
uint32 _currency = uint32(uint160(_token));
|
|
17
28
|
|
|
18
29
|
function setUp() public {
|
|
19
30
|
super.terminalStoreSetup();
|
|
20
31
|
}
|
|
21
32
|
|
|
33
|
+
/// @notice Helper to set balance for a terminal/project/token via vm.store.
|
|
34
|
+
function _setBalance(address terminal, uint256 projectId, address token, uint256 balance) internal {
|
|
35
|
+
bytes32 balanceOfSlot = keccak256(abi.encode(terminal, uint256(0)));
|
|
36
|
+
bytes32 projectSlot = keccak256(abi.encode(projectId, uint256(balanceOfSlot)));
|
|
37
|
+
bytes32 slot = keccak256(abi.encode(token, uint256(projectSlot)));
|
|
38
|
+
vm.store(address(_store), slot, bytes32(balance));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// @notice Helper to register an accounting context with the store (pranks as the terminal).
|
|
42
|
+
function _registerContext(address terminal, JBAccountingContext memory ctx) internal {
|
|
43
|
+
JBAccountingContext[] memory ctxs = new JBAccountingContext[](1);
|
|
44
|
+
ctxs[0] = ctx;
|
|
45
|
+
vm.prank(terminal);
|
|
46
|
+
_store.recordAccountingContextOf(_projectId, ctxs);
|
|
47
|
+
}
|
|
48
|
+
|
|
22
49
|
function test_WhenTerminalsAreConfiguredInJBDirectory() external {
|
|
23
50
|
// it will return the cumulative surplus
|
|
24
51
|
|
|
25
|
-
//
|
|
52
|
+
// Set up terminals in directory
|
|
26
53
|
IJBTerminal[] memory _terminals = new IJBTerminal[](2);
|
|
27
54
|
_terminals[0] = _terminal1;
|
|
28
55
|
_terminals[1] = _terminal2;
|
|
29
56
|
|
|
30
|
-
|
|
31
|
-
bytes memory _directoryCall = abi.encodeCall(IJBDirectory.terminalsOf, (_projectId));
|
|
32
|
-
bytes memory _returned = abi.encode(_terminals);
|
|
33
|
-
mockExpect(address(directory), _directoryCall, _returned);
|
|
57
|
+
mockExpect(address(directory), abi.encodeCall(IJBDirectory.terminalsOf, (_projectId)), abi.encode(_terminals));
|
|
34
58
|
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
59
|
+
// Set up accounting contexts for each terminal
|
|
60
|
+
JBAccountingContext memory ctx = JBAccountingContext({token: _token, decimals: 18, currency: _currency});
|
|
61
|
+
_registerContext(address(_terminal1), ctx);
|
|
62
|
+
_registerContext(address(_terminal2), ctx);
|
|
63
|
+
|
|
64
|
+
// Set balances: terminal1 = 1e18, terminal2 = 2e18
|
|
65
|
+
_setBalance(address(_terminal1), _projectId, _token, 1e18);
|
|
66
|
+
_setBalance(address(_terminal2), _projectId, _token, 2e18);
|
|
67
|
+
|
|
68
|
+
// Mock ruleset
|
|
69
|
+
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
70
|
+
cycleNumber: uint48(block.timestamp),
|
|
71
|
+
id: uint48(block.timestamp),
|
|
72
|
+
basedOnId: 0,
|
|
73
|
+
start: uint48(block.timestamp),
|
|
74
|
+
duration: uint32(block.timestamp + 1000),
|
|
75
|
+
weight: 1e18,
|
|
76
|
+
weightCutPercent: 0,
|
|
77
|
+
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
78
|
+
metadata: 0
|
|
79
|
+
});
|
|
80
|
+
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
81
|
+
|
|
82
|
+
// Mock controller and fund access limits (zero payout limits = all balance is surplus)
|
|
83
|
+
mockExpect(address(directory), abi.encodeCall(IJBDirectory.controllerOf, (_projectId)), abi.encode(_controller));
|
|
84
|
+
mockExpect(
|
|
85
|
+
address(_controller), abi.encodeCall(IJBController.FUND_ACCESS_LIMITS, ()), abi.encode(_accessLimits)
|
|
38
86
|
);
|
|
39
|
-
bytes memory _terminal1Return = abi.encode(1e18);
|
|
40
|
-
mockExpect(address(_terminal1), _terminal1Call, _terminal1Return);
|
|
41
87
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
88
|
+
JBCurrencyAmount[] memory _emptyLimits = new JBCurrencyAmount[](0);
|
|
89
|
+
// Mock payoutLimitsOf for terminal1
|
|
90
|
+
mockExpect(
|
|
91
|
+
address(_accessLimits),
|
|
92
|
+
abi.encodeCall(
|
|
93
|
+
IJBFundAccessLimits.payoutLimitsOf, (_projectId, block.timestamp, address(_terminal1), _token)
|
|
94
|
+
),
|
|
95
|
+
abi.encode(_emptyLimits)
|
|
96
|
+
);
|
|
97
|
+
// Mock payoutLimitsOf for terminal2
|
|
98
|
+
mockExpect(
|
|
99
|
+
address(_accessLimits),
|
|
100
|
+
abi.encodeCall(
|
|
101
|
+
IJBFundAccessLimits.payoutLimitsOf, (_projectId, block.timestamp, address(_terminal2), _token)
|
|
102
|
+
),
|
|
103
|
+
abi.encode(_emptyLimits)
|
|
45
104
|
);
|
|
46
|
-
bytes memory _terminal2Return = abi.encode(2e18);
|
|
47
|
-
mockExpect(address(_terminal2), _terminal2Call, _terminal2Return);
|
|
48
105
|
|
|
49
106
|
uint256 sum = _store.currentTotalSurplusOf(_projectId, _decimals, _currency);
|
|
50
107
|
assertEq(3e18, sum);
|
|
@@ -53,13 +110,24 @@ contract TestCurrentTotalSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
53
110
|
function test_WhenTerminalsAreNotConfiguredInJBDirectory() external {
|
|
54
111
|
// it will return zero
|
|
55
112
|
|
|
56
|
-
// return data for mock call
|
|
57
113
|
IJBTerminal[] memory _terminals = new IJBTerminal[](0);
|
|
58
114
|
|
|
59
115
|
// mock call to JBDirectory terminalsOf
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
116
|
+
mockExpect(address(directory), abi.encodeCall(IJBDirectory.terminalsOf, (_projectId)), abi.encode(_terminals));
|
|
117
|
+
|
|
118
|
+
// Mock ruleset (needed by currentSurplusOf)
|
|
119
|
+
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
120
|
+
cycleNumber: uint48(block.timestamp),
|
|
121
|
+
id: uint48(block.timestamp),
|
|
122
|
+
basedOnId: 0,
|
|
123
|
+
start: uint48(block.timestamp),
|
|
124
|
+
duration: uint32(block.timestamp + 1000),
|
|
125
|
+
weight: 1e18,
|
|
126
|
+
weightCutPercent: 0,
|
|
127
|
+
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
128
|
+
metadata: 0
|
|
129
|
+
});
|
|
130
|
+
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
63
131
|
|
|
64
132
|
uint256 sum = _store.currentTotalSurplusOf(_projectId, _decimals, _currency);
|
|
65
133
|
assertEq(0, sum);
|
|
@@ -16,7 +16,6 @@ import {JBRulesetMetadataResolver} from "../../../../src/libraries/JBRulesetMeta
|
|
|
16
16
|
import {JBAccountingContext} from "../../../../src/structs/JBAccountingContext.sol";
|
|
17
17
|
import {JBBeforeCashOutRecordedContext} from "../../../../src/structs/JBBeforeCashOutRecordedContext.sol";
|
|
18
18
|
import {JBCashOutHookSpecification} from "../../../../src/structs/JBCashOutHookSpecification.sol";
|
|
19
|
-
import {JBCurrencyAmount} from "../../../../src/structs/JBCurrencyAmount.sol";
|
|
20
19
|
import {JBRuleset} from "../../../../src/structs/JBRuleset.sol";
|
|
21
20
|
import {JBRulesetMetadata} from "../../../../src/structs/JBRulesetMetadata.sol";
|
|
22
21
|
import {JBTokenAmount} from "../../../../src/structs/JBTokenAmount.sol";
|
|
@@ -42,6 +41,12 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
42
41
|
|
|
43
42
|
function setUp() public {
|
|
44
43
|
super.terminalStoreSetup();
|
|
44
|
+
|
|
45
|
+
// Register accounting context so the store can look up decimals/currency for the token.
|
|
46
|
+
// address(this) acts as the terminal for both preview and record calls.
|
|
47
|
+
JBAccountingContext[] memory _ctxs = new JBAccountingContext[](1);
|
|
48
|
+
_ctxs[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
|
|
49
|
+
_store.recordAccountingContextOf(_projectId, _ctxs);
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
function _setBalance(address terminal, uint256 balance) internal {
|
|
@@ -60,16 +65,12 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
60
65
|
|
|
61
66
|
mockExpect(
|
|
62
67
|
address(_terminal1),
|
|
63
|
-
abi.encodeCall(
|
|
64
|
-
IJBTerminal.currentSurplusOf, (_projectId, new JBAccountingContext[](0), _decimals, _currency)
|
|
65
|
-
),
|
|
68
|
+
abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, new address[](0), _decimals, _currency)),
|
|
66
69
|
abi.encode(1e18)
|
|
67
70
|
);
|
|
68
71
|
mockExpect(
|
|
69
72
|
address(_terminal2),
|
|
70
|
-
abi.encodeCall(
|
|
71
|
-
IJBTerminal.currentSurplusOf, (_projectId, new JBAccountingContext[](0), _decimals, _currency)
|
|
72
|
-
),
|
|
73
|
+
abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, new address[](0), _decimals, _currency)),
|
|
73
74
|
abi.encode(2e18)
|
|
74
75
|
);
|
|
75
76
|
}
|
|
@@ -119,9 +120,8 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
119
120
|
uint256 _cashOutCount = 10e18;
|
|
120
121
|
|
|
121
122
|
JBAccountingContext memory _accountingContext =
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
JBAccountingContext[] memory _balanceContexts = new JBAccountingContext[](0);
|
|
123
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
124
|
+
JBAccountingContext({token: address(_token), decimals: uint8(_decimals), currency: _currency});
|
|
125
125
|
|
|
126
126
|
// Mock for preview call
|
|
127
127
|
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
@@ -133,11 +133,11 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
133
133
|
);
|
|
134
134
|
|
|
135
135
|
(, uint256 previewReclaimAmount, uint256 previewTaxRate, JBCashOutHookSpecification[] memory previewSpecs) = _store.previewCashOutFrom({
|
|
136
|
+
terminal: address(this),
|
|
136
137
|
holder: address(this),
|
|
137
138
|
projectId: _projectId,
|
|
138
139
|
cashOutCount: _cashOutCount,
|
|
139
|
-
|
|
140
|
-
balanceAccountingContexts: _balanceContexts,
|
|
140
|
+
tokenToReclaim: _accountingContext.token,
|
|
141
141
|
beneficiaryIsFeeless: false,
|
|
142
142
|
metadata: ""
|
|
143
143
|
});
|
|
@@ -156,8 +156,7 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
156
156
|
holder: address(this),
|
|
157
157
|
projectId: _projectId,
|
|
158
158
|
cashOutCount: _cashOutCount,
|
|
159
|
-
|
|
160
|
-
balanceAccountingContexts: _balanceContexts,
|
|
159
|
+
tokenToReclaim: _accountingContext.token,
|
|
161
160
|
beneficiaryIsFeeless: false,
|
|
162
161
|
metadata: ""
|
|
163
162
|
});
|
|
@@ -208,7 +207,8 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
208
207
|
});
|
|
209
208
|
|
|
210
209
|
JBAccountingContext memory _accountingContext =
|
|
211
|
-
|
|
210
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
211
|
+
JBAccountingContext({token: address(_token), decimals: uint8(_decimals), currency: _currency});
|
|
212
212
|
|
|
213
213
|
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
214
214
|
mockExpect(address(directory), abi.encodeCall(IJBDirectory.controllerOf, (_projectId)), abi.encode(_controller));
|
|
@@ -221,11 +221,11 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
221
221
|
uint256 balanceBefore = _store.balanceOf(address(this), _projectId, address(_token));
|
|
222
222
|
|
|
223
223
|
_store.previewCashOutFrom({
|
|
224
|
+
terminal: address(this),
|
|
224
225
|
holder: address(this),
|
|
225
226
|
projectId: _projectId,
|
|
226
227
|
cashOutCount: 5e18,
|
|
227
|
-
|
|
228
|
-
balanceAccountingContexts: new JBAccountingContext[](0),
|
|
228
|
+
tokenToReclaim: _accountingContext.token,
|
|
229
229
|
beneficiaryIsFeeless: false,
|
|
230
230
|
metadata: ""
|
|
231
231
|
});
|
|
@@ -275,7 +275,8 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
275
275
|
});
|
|
276
276
|
|
|
277
277
|
JBAccountingContext memory _accountingContext =
|
|
278
|
-
|
|
278
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
279
|
+
JBAccountingContext({token: address(_token), decimals: uint8(_decimals), currency: _currency});
|
|
279
280
|
|
|
280
281
|
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
281
282
|
mockExpect(address(directory), abi.encodeCall(IJBDirectory.controllerOf, (_projectId)), abi.encode(_controller));
|
|
@@ -293,11 +294,11 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
293
294
|
)
|
|
294
295
|
);
|
|
295
296
|
_store.previewCashOutFrom({
|
|
297
|
+
terminal: address(this),
|
|
296
298
|
holder: address(this),
|
|
297
299
|
projectId: _projectId,
|
|
298
300
|
cashOutCount: _excessiveCashOutCount,
|
|
299
|
-
|
|
300
|
-
balanceAccountingContexts: new JBAccountingContext[](0),
|
|
301
|
+
tokenToReclaim: _accountingContext.token,
|
|
301
302
|
beneficiaryIsFeeless: false,
|
|
302
303
|
metadata: ""
|
|
303
304
|
});
|
|
@@ -343,7 +344,8 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
343
344
|
});
|
|
344
345
|
|
|
345
346
|
JBAccountingContext memory _accountingContext =
|
|
346
|
-
|
|
347
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
348
|
+
JBAccountingContext({token: address(_token), decimals: uint8(_decimals), currency: _currency});
|
|
347
349
|
|
|
348
350
|
IJBTerminal[] memory _terminals = new IJBTerminal[](1);
|
|
349
351
|
_terminals[0] = _terminal1;
|
|
@@ -352,9 +354,7 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
352
354
|
mockExpect(address(directory), abi.encodeCall(IJBDirectory.terminalsOf, (_projectId)), abi.encode(_terminals));
|
|
353
355
|
mockExpect(
|
|
354
356
|
address(_terminal1),
|
|
355
|
-
abi.encodeCall(
|
|
356
|
-
IJBTerminal.currentSurplusOf, (_projectId, new JBAccountingContext[](0), _decimals, _currency)
|
|
357
|
-
),
|
|
357
|
+
abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, new address[](0), _decimals, _currency)),
|
|
358
358
|
abi.encode(0)
|
|
359
359
|
);
|
|
360
360
|
mockExpect(address(directory), abi.encodeCall(IJBDirectory.controllerOf, (_projectId)), abi.encode(_controller));
|
|
@@ -365,11 +365,11 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
365
365
|
);
|
|
366
366
|
|
|
367
367
|
(, uint256 reclaimAmount,,) = _store.previewCashOutFrom({
|
|
368
|
+
terminal: address(this),
|
|
368
369
|
holder: address(this),
|
|
369
370
|
projectId: _projectId,
|
|
370
371
|
cashOutCount: 5e18,
|
|
371
|
-
|
|
372
|
-
balanceAccountingContexts: new JBAccountingContext[](0),
|
|
372
|
+
tokenToReclaim: _accountingContext.token,
|
|
373
373
|
beneficiaryIsFeeless: false,
|
|
374
374
|
metadata: ""
|
|
375
375
|
});
|
|
@@ -418,7 +418,8 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
418
418
|
});
|
|
419
419
|
|
|
420
420
|
JBAccountingContext memory _accountingContext =
|
|
421
|
-
|
|
421
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
422
|
+
JBAccountingContext({token: address(_token), decimals: uint8(_decimals), currency: _currency});
|
|
422
423
|
|
|
423
424
|
JBBeforeCashOutRecordedContext memory _context = JBBeforeCashOutRecordedContext({
|
|
424
425
|
terminal: address(this),
|
|
@@ -456,11 +457,11 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
456
457
|
);
|
|
457
458
|
|
|
458
459
|
(, uint256 reclaimAmount, uint256 cashOutTaxRate, JBCashOutHookSpecification[] memory hookSpecifications) = _store.previewCashOutFrom({
|
|
460
|
+
terminal: address(this),
|
|
459
461
|
holder: address(this),
|
|
460
462
|
projectId: _projectId,
|
|
461
463
|
cashOutCount: 10e18,
|
|
462
|
-
|
|
463
|
-
balanceAccountingContexts: new JBAccountingContext[](0),
|
|
464
|
+
tokenToReclaim: _accountingContext.token,
|
|
464
465
|
beneficiaryIsFeeless: false,
|
|
465
466
|
metadata: ""
|
|
466
467
|
});
|
|
@@ -60,9 +60,13 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
60
60
|
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
61
61
|
|
|
62
62
|
vm.expectRevert(abi.encodeWithSelector(JBTerminalStore.JBTerminalStore_RulesetNotFound.selector, _projectId));
|
|
63
|
-
vm.prank(_terminal);
|
|
64
63
|
_store.previewPayFrom({
|
|
65
|
-
|
|
64
|
+
terminal: _terminal,
|
|
65
|
+
payer: address(this),
|
|
66
|
+
amount: _tokenAmount,
|
|
67
|
+
projectId: _projectId,
|
|
68
|
+
beneficiary: address(this),
|
|
69
|
+
metadata: ""
|
|
66
70
|
});
|
|
67
71
|
}
|
|
68
72
|
|
|
@@ -112,9 +116,13 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
112
116
|
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
113
117
|
|
|
114
118
|
vm.expectRevert(JBTerminalStore.JBTerminalStore_RulesetPaymentPaused.selector);
|
|
115
|
-
vm.prank(_terminal);
|
|
116
119
|
_store.previewPayFrom({
|
|
117
|
-
|
|
120
|
+
terminal: _terminal,
|
|
121
|
+
payer: address(this),
|
|
122
|
+
amount: _tokenAmount,
|
|
123
|
+
projectId: _projectId,
|
|
124
|
+
beneficiary: address(this),
|
|
125
|
+
metadata: ""
|
|
118
126
|
});
|
|
119
127
|
}
|
|
120
128
|
|
|
@@ -165,7 +173,12 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
165
173
|
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
166
174
|
|
|
167
175
|
(, uint256 previewTokenCount, JBPayHookSpecification[] memory previewSpecs) = _store.previewPayFrom({
|
|
168
|
-
|
|
176
|
+
terminal: _terminal,
|
|
177
|
+
payer: address(this),
|
|
178
|
+
amount: _tokenAmount,
|
|
179
|
+
projectId: _projectId,
|
|
180
|
+
beneficiary: address(this),
|
|
181
|
+
metadata: ""
|
|
169
182
|
});
|
|
170
183
|
|
|
171
184
|
// Mock for record call
|
|
@@ -225,10 +238,9 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
225
238
|
JBPayHookSpecification[] memory _spec = new JBPayHookSpecification[](1);
|
|
226
239
|
_spec[0] = JBPayHookSpecification({hook: _payHook, noop: false, amount: _defaultValue / 2, metadata: ""});
|
|
227
240
|
|
|
228
|
-
// The data hook context
|
|
229
|
-
// Since we call both from address(this), they match.
|
|
241
|
+
// The data hook context uses the explicit terminal parameter for preview / msg.sender for record.
|
|
230
242
|
JBBeforePayRecordedContext memory _context = JBBeforePayRecordedContext({
|
|
231
|
-
terminal:
|
|
243
|
+
terminal: _terminal,
|
|
232
244
|
payer: address(this),
|
|
233
245
|
amount: _tokenAmount,
|
|
234
246
|
projectId: _projectId,
|
|
@@ -248,10 +260,15 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
248
260
|
);
|
|
249
261
|
|
|
250
262
|
(, uint256 previewTokenCount, JBPayHookSpecification[] memory previewSpecs) = _store.previewPayFrom({
|
|
251
|
-
|
|
263
|
+
terminal: _terminal,
|
|
264
|
+
payer: address(this),
|
|
265
|
+
amount: _tokenAmount,
|
|
266
|
+
projectId: _projectId,
|
|
267
|
+
beneficiary: address(this),
|
|
268
|
+
metadata: ""
|
|
252
269
|
});
|
|
253
270
|
|
|
254
|
-
// Mock for record call
|
|
271
|
+
// Mock for record call — recordPaymentFrom uses msg.sender as terminal, so prank _terminal.
|
|
255
272
|
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
256
273
|
mockExpect(
|
|
257
274
|
address(_dataHook),
|
|
@@ -259,6 +276,7 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
259
276
|
abi.encode(1e18 / 2, _spec)
|
|
260
277
|
);
|
|
261
278
|
|
|
279
|
+
vm.prank(_terminal);
|
|
262
280
|
(, uint256 recordTokenCount, JBPayHookSpecification[] memory recordSpecs) = _store.recordPaymentFrom({
|
|
263
281
|
payer: address(this), amount: _tokenAmount, projectId: _projectId, beneficiary: address(this), metadata: ""
|
|
264
282
|
});
|
|
@@ -315,9 +333,13 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
315
333
|
|
|
316
334
|
uint256 balanceBefore = _store.balanceOf(_terminal, _projectId, address(_token));
|
|
317
335
|
|
|
318
|
-
vm.prank(_terminal);
|
|
319
336
|
_store.previewPayFrom({
|
|
320
|
-
|
|
337
|
+
terminal: _terminal,
|
|
338
|
+
payer: address(this),
|
|
339
|
+
amount: _tokenAmount,
|
|
340
|
+
projectId: _projectId,
|
|
341
|
+
beneficiary: address(this),
|
|
342
|
+
metadata: ""
|
|
321
343
|
});
|
|
322
344
|
|
|
323
345
|
uint256 balanceAfter = _store.balanceOf(_terminal, _projectId, address(_token));
|
|
@@ -379,9 +401,13 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
379
401
|
|
|
380
402
|
uint256 expectedCount = mulDiv(_defaultValue, 1e18, 2e18);
|
|
381
403
|
|
|
382
|
-
vm.prank(_terminal);
|
|
383
404
|
(, uint256 tokenCount,) = _store.previewPayFrom({
|
|
384
|
-
|
|
405
|
+
terminal: _terminal,
|
|
406
|
+
payer: address(this),
|
|
407
|
+
amount: _tokenAmount,
|
|
408
|
+
projectId: _projectId,
|
|
409
|
+
beneficiary: address(this),
|
|
410
|
+
metadata: ""
|
|
385
411
|
});
|
|
386
412
|
|
|
387
413
|
assertEq(tokenCount, expectedCount);
|
|
@@ -450,9 +476,13 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
450
476
|
abi.encode(1e18 / 2, _spec)
|
|
451
477
|
);
|
|
452
478
|
|
|
453
|
-
vm.prank(_terminal);
|
|
454
479
|
(, uint256 tokenCount, JBPayHookSpecification[] memory hookSpecifications) = _store.previewPayFrom({
|
|
455
|
-
|
|
480
|
+
terminal: _terminal,
|
|
481
|
+
payer: address(this),
|
|
482
|
+
amount: _tokenAmount,
|
|
483
|
+
projectId: _projectId,
|
|
484
|
+
beneficiary: address(this),
|
|
485
|
+
metadata: ""
|
|
456
486
|
});
|
|
457
487
|
|
|
458
488
|
assertEq(tokenCount, 1e18 / 2);
|