@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
|
@@ -2,11 +2,8 @@
|
|
|
2
2
|
pragma solidity 0.8.26;
|
|
3
3
|
|
|
4
4
|
import {IJBDirectory} from "../../../../src/interfaces/IJBDirectory.sol";
|
|
5
|
-
import {
|
|
6
|
-
import {IJBRulesets} from "../../../../src/interfaces/IJBRulesets.sol";
|
|
5
|
+
import {IJBTerminalStore} from "../../../../src/interfaces/IJBTerminalStore.sol";
|
|
7
6
|
import {JBAccountingContext} from "../../../../src/structs/JBAccountingContext.sol";
|
|
8
|
-
import {JBRuleset} from "../../../../src/structs/JBRuleset.sol";
|
|
9
|
-
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
10
7
|
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|
11
8
|
import {JBMultiTerminalSetup} from "./JBMultiTerminalSetup.sol";
|
|
12
9
|
|
|
@@ -33,40 +30,42 @@ contract TestAccountingContextsOf_Local is JBMultiTerminalSetup {
|
|
|
33
30
|
address(directory), abi.encodeCall(IJBDirectory.controllerOf, (_projectId)), abi.encode(address(this))
|
|
34
31
|
);
|
|
35
32
|
|
|
36
|
-
// mock call to tokens decimals()
|
|
37
|
-
mockExpect(_usdc, abi.encodeCall(IERC20Metadata.decimals, ()), abi.encode(6));
|
|
38
|
-
|
|
39
|
-
// setup: return data
|
|
40
|
-
JBRuleset memory ruleset = JBRuleset({
|
|
41
|
-
cycleNumber: 1,
|
|
42
|
-
id: 0,
|
|
43
|
-
basedOnId: 0,
|
|
44
|
-
start: 0,
|
|
45
|
-
duration: 0,
|
|
46
|
-
weight: 0,
|
|
47
|
-
weightCutPercent: 0,
|
|
48
|
-
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
49
|
-
metadata: 0
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// mock call to rulesets currentOf returning 0 to bypass ruleset checking
|
|
53
|
-
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(ruleset));
|
|
54
|
-
|
|
55
33
|
// call params
|
|
56
34
|
JBAccountingContext[] memory _tokens = new JBAccountingContext[](1);
|
|
57
35
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
58
36
|
_tokens[0] = JBAccountingContext({token: _usdc, decimals: 6, currency: uint32(uint160(_usdc))});
|
|
59
37
|
|
|
38
|
+
// Mock recordAccountingContextOf in the store (validation now happens there)
|
|
39
|
+
mockExpect(
|
|
40
|
+
address(store), abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)), ""
|
|
41
|
+
);
|
|
42
|
+
|
|
60
43
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
61
44
|
|
|
45
|
+
// Mock the store to return all contexts when queried
|
|
46
|
+
mockExpect(
|
|
47
|
+
address(store),
|
|
48
|
+
abi.encodeCall(IJBTerminalStore.accountingContextsOf, (address(_terminal), _projectId)),
|
|
49
|
+
abi.encode(_tokens)
|
|
50
|
+
);
|
|
51
|
+
|
|
62
52
|
JBAccountingContext[] memory _storedContexts = _terminal.accountingContextsOf(_projectId);
|
|
63
53
|
assertEq(_storedContexts[0].currency, _usdcCurrency);
|
|
64
54
|
assertEq(_storedContexts[0].token, _usdc);
|
|
65
55
|
assertEq(_storedContexts[0].decimals, 6);
|
|
66
56
|
}
|
|
67
57
|
|
|
68
|
-
function test_WhenAccountingContextsAreNotSet() external
|
|
58
|
+
function test_WhenAccountingContextsAreNotSet() external {
|
|
69
59
|
// it will return an empty array
|
|
60
|
+
|
|
61
|
+
// Mock the store to return empty array
|
|
62
|
+
JBAccountingContext[] memory _empty = new JBAccountingContext[](0);
|
|
63
|
+
mockExpect(
|
|
64
|
+
address(store),
|
|
65
|
+
abi.encodeCall(IJBTerminalStore.accountingContextsOf, (address(_terminal), _projectId)),
|
|
66
|
+
abi.encode(_empty)
|
|
67
|
+
);
|
|
68
|
+
|
|
70
69
|
JBAccountingContext[] memory _storedContexts = _terminal.accountingContextsOf(_projectId);
|
|
71
70
|
assertEq(_storedContexts.length, 0);
|
|
72
71
|
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity 0.8.26;
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {JBTerminalStore} from "../../../../src/JBTerminalStore.sol";
|
|
5
5
|
import {IJBDirectory} from "../../../../src/interfaces/IJBDirectory.sol";
|
|
6
|
-
import {
|
|
7
|
-
import {IJBRulesets} from "../../../../src/interfaces/IJBRulesets.sol";
|
|
6
|
+
import {IJBTerminalStore} from "../../../../src/interfaces/IJBTerminalStore.sol";
|
|
8
7
|
import {JBConstants} from "../../../../src/libraries/JBConstants.sol";
|
|
9
8
|
import {JBAccountingContext} from "../../../../src/structs/JBAccountingContext.sol";
|
|
10
|
-
import {JBRuleset} from "../../../../src/structs/JBRuleset.sol";
|
|
11
|
-
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
12
9
|
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|
13
10
|
import {JBMultiTerminalSetup} from "./JBMultiTerminalSetup.sol";
|
|
14
11
|
|
|
@@ -43,44 +40,20 @@ contract TestAddAccountingContextsFor_Local is JBMultiTerminalSetup {
|
|
|
43
40
|
function test_GivenTheContextIsAlreadySet() external whenCallerIsPermissioned {
|
|
44
41
|
// it will revert ACCOUNTING_CONTEXT_ALREADY_SET
|
|
45
42
|
|
|
46
|
-
// Accounting Context to set
|
|
47
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
48
|
-
JBAccountingContext memory _context =
|
|
49
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
50
|
-
JBAccountingContext({token: _usdc, decimals: 18, currency: uint32(_usdcCurrency)});
|
|
51
|
-
|
|
52
|
-
// Find the storage slot
|
|
53
|
-
bytes32 contextSlot = keccak256(abi.encode(_projectId, uint256(0)));
|
|
54
|
-
bytes32 slot = keccak256(abi.encode(_usdc, contextSlot));
|
|
55
|
-
|
|
56
|
-
// Set storage
|
|
57
|
-
vm.store(address(_terminal), slot, bytes32(abi.encode(_context)));
|
|
58
|
-
|
|
59
|
-
// setup: return data
|
|
60
|
-
JBRuleset memory ruleset = JBRuleset({
|
|
61
|
-
cycleNumber: 1,
|
|
62
|
-
id: 0,
|
|
63
|
-
basedOnId: 0,
|
|
64
|
-
start: 0,
|
|
65
|
-
duration: 0,
|
|
66
|
-
weight: 0,
|
|
67
|
-
weightCutPercent: 0,
|
|
68
|
-
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
69
|
-
metadata: 0
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(ruleset));
|
|
73
|
-
|
|
74
|
-
JBAccountingContext memory _storedContext = _terminal.accountingContextForTokenOf(_projectId, _usdc);
|
|
75
|
-
assertEq(_storedContext.token, _usdc);
|
|
76
|
-
|
|
77
43
|
// call params
|
|
78
44
|
JBAccountingContext[] memory _tokens = new JBAccountingContext[](1);
|
|
79
45
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
80
46
|
_tokens[0] = JBAccountingContext({token: _usdc, decimals: 6, currency: uint32(uint160(_usdc))});
|
|
81
47
|
|
|
48
|
+
// Mock recordAccountingContextOf to revert with AccountingContextAlreadySet
|
|
49
|
+
vm.mockCallRevert(
|
|
50
|
+
address(store),
|
|
51
|
+
abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)),
|
|
52
|
+
abi.encodeWithSelector(JBTerminalStore.JBTerminalStore_AccountingContextAlreadySet.selector, _usdc)
|
|
53
|
+
);
|
|
54
|
+
|
|
82
55
|
vm.expectRevert(
|
|
83
|
-
abi.encodeWithSelector(
|
|
56
|
+
abi.encodeWithSelector(JBTerminalStore.JBTerminalStore_AccountingContextAlreadySet.selector, _usdc)
|
|
84
57
|
);
|
|
85
58
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
86
59
|
}
|
|
@@ -88,32 +61,25 @@ contract TestAddAccountingContextsFor_Local is JBMultiTerminalSetup {
|
|
|
88
61
|
function test_GivenHappyPathERC20() external whenCallerIsPermissioned {
|
|
89
62
|
// it will set the context and emit SetAccountingContext
|
|
90
63
|
|
|
91
|
-
// mock call to tokens decimals()
|
|
92
|
-
mockExpect(_usdc, abi.encodeCall(IERC20Metadata.decimals, ()), abi.encode(6));
|
|
93
|
-
|
|
94
|
-
// setup: return data
|
|
95
|
-
JBRuleset memory ruleset = JBRuleset({
|
|
96
|
-
cycleNumber: 1,
|
|
97
|
-
id: 0,
|
|
98
|
-
basedOnId: 0,
|
|
99
|
-
start: 0,
|
|
100
|
-
duration: 0,
|
|
101
|
-
weight: 0,
|
|
102
|
-
weightCutPercent: 0,
|
|
103
|
-
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
104
|
-
metadata: 0
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// mock call to rulesets currentOf returning 0 to bypass ruleset checking
|
|
108
|
-
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(ruleset));
|
|
109
|
-
|
|
110
64
|
// call params
|
|
111
65
|
JBAccountingContext[] memory _tokens = new JBAccountingContext[](1);
|
|
112
66
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
113
67
|
_tokens[0] = JBAccountingContext({token: _usdc, decimals: 6, currency: uint32(uint160(_usdc))});
|
|
114
68
|
|
|
69
|
+
// Mock recordAccountingContextOf in the store (validation now happens there)
|
|
70
|
+
mockExpect(
|
|
71
|
+
address(store), abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)), ""
|
|
72
|
+
);
|
|
73
|
+
|
|
115
74
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
116
75
|
|
|
76
|
+
// Mock the store to return the context when queried
|
|
77
|
+
mockExpect(
|
|
78
|
+
address(store),
|
|
79
|
+
abi.encodeCall(IJBTerminalStore.accountingContextOf, (address(_terminal), _projectId, _usdc)),
|
|
80
|
+
abi.encode(_tokens[0])
|
|
81
|
+
);
|
|
82
|
+
|
|
117
83
|
JBAccountingContext memory _storedContext = _terminal.accountingContextForTokenOf(_projectId, _usdc);
|
|
118
84
|
assertEq(_storedContext.token, _usdc);
|
|
119
85
|
assertEq(_storedContext.decimals, 6);
|
|
@@ -128,25 +94,22 @@ contract TestAddAccountingContextsFor_Local is JBMultiTerminalSetup {
|
|
|
128
94
|
token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
129
95
|
});
|
|
130
96
|
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
cycleNumber: 1,
|
|
136
|
-
id: 0,
|
|
137
|
-
basedOnId: 0,
|
|
138
|
-
start: 0,
|
|
139
|
-
duration: 0,
|
|
140
|
-
weight: 0,
|
|
141
|
-
weightCutPercent: 0,
|
|
142
|
-
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
143
|
-
metadata: 0
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(ruleset));
|
|
97
|
+
// Mock recordAccountingContextOf in the store (validation now happens there)
|
|
98
|
+
mockExpect(
|
|
99
|
+
address(store), abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)), ""
|
|
100
|
+
);
|
|
147
101
|
|
|
148
102
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
149
103
|
|
|
104
|
+
// Mock the store to return the context when queried
|
|
105
|
+
mockExpect(
|
|
106
|
+
address(store),
|
|
107
|
+
abi.encodeCall(
|
|
108
|
+
IJBTerminalStore.accountingContextOf, (address(_terminal), _projectId, JBConstants.NATIVE_TOKEN)
|
|
109
|
+
),
|
|
110
|
+
abi.encode(_tokens[0])
|
|
111
|
+
);
|
|
112
|
+
|
|
150
113
|
JBAccountingContext memory _storedContext =
|
|
151
114
|
_terminal.accountingContextForTokenOf(_projectId, JBConstants.NATIVE_TOKEN);
|
|
152
115
|
assertEq(_storedContext.token, JBConstants.NATIVE_TOKEN);
|
|
@@ -173,23 +136,22 @@ contract TestAddAccountingContextsFor_Local is JBMultiTerminalSetup {
|
|
|
173
136
|
token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
174
137
|
});
|
|
175
138
|
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
basedOnId: 0,
|
|
181
|
-
start: 0,
|
|
182
|
-
duration: 0,
|
|
183
|
-
weight: 0,
|
|
184
|
-
weightCutPercent: 0,
|
|
185
|
-
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
186
|
-
metadata: 0
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(ruleset));
|
|
139
|
+
// Mock recordAccountingContextOf in the store (validation now happens there)
|
|
140
|
+
mockExpect(
|
|
141
|
+
address(store), abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)), ""
|
|
142
|
+
);
|
|
190
143
|
|
|
191
144
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
192
145
|
|
|
146
|
+
// Mock the store to return the context when queried
|
|
147
|
+
mockExpect(
|
|
148
|
+
address(store),
|
|
149
|
+
abi.encodeCall(
|
|
150
|
+
IJBTerminalStore.accountingContextOf, (address(_terminal), _projectId, JBConstants.NATIVE_TOKEN)
|
|
151
|
+
),
|
|
152
|
+
abi.encode(_tokens[0])
|
|
153
|
+
);
|
|
154
|
+
|
|
193
155
|
JBAccountingContext memory _storedContext =
|
|
194
156
|
_terminal.accountingContextForTokenOf(_projectId, JBConstants.NATIVE_TOKEN);
|
|
195
157
|
assertEq(_storedContext.token, JBConstants.NATIVE_TOKEN);
|
|
@@ -216,18 +178,19 @@ contract TestAddAccountingContextsFor_Local is JBMultiTerminalSetup {
|
|
|
216
178
|
token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
217
179
|
});
|
|
218
180
|
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
181
|
+
// Mock recordAccountingContextOf to revert with AddingAccountingContextNotAllowed (validation now in store)
|
|
182
|
+
vm.mockCallRevert(
|
|
183
|
+
address(store),
|
|
184
|
+
abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)),
|
|
185
|
+
abi.encodeWithSelector(JBTerminalStore.JBTerminalStore_AddingAccountingContextNotAllowed.selector)
|
|
186
|
+
);
|
|
224
187
|
|
|
225
|
-
vm.expectRevert(
|
|
188
|
+
vm.expectRevert(JBTerminalStore.JBTerminalStore_AddingAccountingContextNotAllowed.selector);
|
|
226
189
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
227
190
|
}
|
|
228
191
|
|
|
229
192
|
function test_WhenCurrencyIsNativeButDecimalsDNEQ18() external {
|
|
230
|
-
// it will revert
|
|
193
|
+
// it will revert JBTerminalStore_AccountingContextDecimalsMismatch
|
|
231
194
|
|
|
232
195
|
// mock call to JBProjects ownerOf(_projectId)
|
|
233
196
|
bytes memory _projectsCall = abi.encodeCall(IERC721.ownerOf, (_projectId));
|
|
@@ -247,18 +210,19 @@ contract TestAddAccountingContextsFor_Local is JBMultiTerminalSetup {
|
|
|
247
210
|
currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
248
211
|
});
|
|
249
212
|
|
|
250
|
-
//
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
213
|
+
// Mock recordAccountingContextOf to revert with DecimalsMismatch (validation now in store)
|
|
214
|
+
vm.mockCallRevert(
|
|
215
|
+
address(store),
|
|
216
|
+
abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)),
|
|
217
|
+
abi.encodeWithSelector(JBTerminalStore.JBTerminalStore_AccountingContextDecimalsMismatch.selector)
|
|
218
|
+
);
|
|
255
219
|
|
|
256
|
-
vm.expectRevert(
|
|
220
|
+
vm.expectRevert(JBTerminalStore.JBTerminalStore_AccountingContextDecimalsMismatch.selector);
|
|
257
221
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
258
222
|
}
|
|
259
223
|
|
|
260
224
|
function test_WhenTokenDecimalsDoesNotMatchAccountingContext() external {
|
|
261
|
-
// it will revert
|
|
225
|
+
// it will revert JBTerminalStore_AccountingContextDecimalsMismatch
|
|
262
226
|
|
|
263
227
|
// mock call to JBProjects ownerOf(_projectId)
|
|
264
228
|
bytes memory _projectsCall = abi.encodeCall(IERC721.ownerOf, (_projectId));
|
|
@@ -281,21 +245,19 @@ contract TestAddAccountingContextsFor_Local is JBMultiTerminalSetup {
|
|
|
281
245
|
currency: uint32(uint160(someToken))
|
|
282
246
|
});
|
|
283
247
|
|
|
284
|
-
//
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
// mock token call
|
|
291
|
-
mockExpect(address(someToken), abi.encodeCall(IERC20Metadata.decimals, ()), abi.encode(18));
|
|
248
|
+
// Mock recordAccountingContextOf to revert with DecimalsMismatch (validation now in store)
|
|
249
|
+
vm.mockCallRevert(
|
|
250
|
+
address(store),
|
|
251
|
+
abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)),
|
|
252
|
+
abi.encodeWithSelector(JBTerminalStore.JBTerminalStore_AccountingContextDecimalsMismatch.selector)
|
|
253
|
+
);
|
|
292
254
|
|
|
293
|
-
vm.expectRevert(
|
|
255
|
+
vm.expectRevert(JBTerminalStore.JBTerminalStore_AccountingContextDecimalsMismatch.selector);
|
|
294
256
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
295
257
|
}
|
|
296
258
|
|
|
297
259
|
function test_WhenCurrencyEQZero() external {
|
|
298
|
-
// it will revert
|
|
260
|
+
// it will revert JBTerminalStore_ZeroAccountingContextCurrency
|
|
299
261
|
|
|
300
262
|
// mock call to JBProjects ownerOf(_projectId)
|
|
301
263
|
bytes memory _projectsCall = abi.encodeCall(IERC721.ownerOf, (_projectId));
|
|
@@ -314,16 +276,14 @@ contract TestAddAccountingContextsFor_Local is JBMultiTerminalSetup {
|
|
|
314
276
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
315
277
|
_tokens[0] = JBAccountingContext({token: someToken, decimals: 18, currency: uint32(uint160(0))});
|
|
316
278
|
|
|
317
|
-
//
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
// mock token call
|
|
324
|
-
mockExpect(address(someToken), abi.encodeCall(IERC20Metadata.decimals, ()), abi.encode(18));
|
|
279
|
+
// Mock recordAccountingContextOf to revert with ZeroAccountingContextCurrency (validation now in store)
|
|
280
|
+
vm.mockCallRevert(
|
|
281
|
+
address(store),
|
|
282
|
+
abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)),
|
|
283
|
+
abi.encodeWithSelector(JBTerminalStore.JBTerminalStore_ZeroAccountingContextCurrency.selector)
|
|
284
|
+
);
|
|
325
285
|
|
|
326
|
-
vm.expectRevert(
|
|
286
|
+
vm.expectRevert(JBTerminalStore.JBTerminalStore_ZeroAccountingContextCurrency.selector);
|
|
327
287
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
328
288
|
}
|
|
329
289
|
}
|
|
@@ -55,12 +55,12 @@ contract TestAddToBalanceOf_Local is JBMultiTerminalSetup {
|
|
|
55
55
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
56
56
|
JBAccountingContext({token: _native, decimals: 18, currency: uint32(_nativeCurrency)});
|
|
57
57
|
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
// Mock the store to return this accounting context
|
|
59
|
+
mockExpect(
|
|
60
|
+
address(store),
|
|
61
|
+
abi.encodeCall(IJBTerminalStore.accountingContextOf, (address(_terminal), _projectId, _native)),
|
|
62
|
+
abi.encode(_context)
|
|
63
|
+
);
|
|
64
64
|
|
|
65
65
|
JBAccountingContext memory _storedContext = _terminal.accountingContextForTokenOf(_projectId, _native);
|
|
66
66
|
assertEq(_storedContext.token, _native);
|
|
@@ -75,18 +75,18 @@ contract TestAddToBalanceOf_Local is JBMultiTerminalSetup {
|
|
|
75
75
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
76
76
|
JBAccountingContext({token: _native, decimals: 18, currency: uint32(_nativeCurrency)});
|
|
77
77
|
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
// Mock the store to return this accounting context
|
|
79
|
+
mockExpect(
|
|
80
|
+
address(store),
|
|
81
|
+
abi.encodeCall(IJBTerminalStore.accountingContextOf, (address(_terminal), _projectId, _native)),
|
|
82
|
+
abi.encode(_context)
|
|
83
|
+
);
|
|
84
84
|
|
|
85
85
|
JBAccountingContext memory _storedContext = _terminal.accountingContextForTokenOf(_projectId, _native);
|
|
86
86
|
assertEq(_storedContext.token, _native);
|
|
87
87
|
|
|
88
|
-
// Find the storage slot for fees array (_heldFeesOf is at storage slot
|
|
89
|
-
bytes32 feeSlot = keccak256(abi.encode(_projectId, uint256(
|
|
88
|
+
// Find the storage slot for fees array (_heldFeesOf is at storage slot 1)
|
|
89
|
+
bytes32 feeSlot = keccak256(abi.encode(_projectId, uint256(1)));
|
|
90
90
|
bytes32 slotForArrayLength = keccak256(abi.encode(_native, feeSlot));
|
|
91
91
|
|
|
92
92
|
// Set the length of the fees array in the storage slot
|
|
@@ -223,6 +223,13 @@ contract TestAddToBalanceOf_Local is JBMultiTerminalSetup {
|
|
|
223
223
|
function test_WhenTheProjectDNHAccountingContextForTheToken() external {
|
|
224
224
|
// it will revert TOKEN_NOT_ACCEPTED
|
|
225
225
|
|
|
226
|
+
// Mock accountingContextOf to return empty context (token not accepted)
|
|
227
|
+
mockExpect(
|
|
228
|
+
address(store),
|
|
229
|
+
abi.encodeCall(IJBTerminalStore.accountingContextOf, (address(_terminal), _projectId, _native)),
|
|
230
|
+
abi.encode(JBAccountingContext({token: address(0), decimals: 0, currency: 0}))
|
|
231
|
+
);
|
|
232
|
+
|
|
226
233
|
vm.expectRevert(abi.encodeWithSelector(JBMultiTerminal.JBMultiTerminal_TokenNotAccepted.selector, _native));
|
|
227
234
|
|
|
228
235
|
_terminal.addToBalanceOf{value: payAmount}({
|
|
@@ -244,12 +251,12 @@ contract TestAddToBalanceOf_Local is JBMultiTerminalSetup {
|
|
|
244
251
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
245
252
|
JBAccountingContext({token: _usdc, decimals: 18, currency: uint32(_usdcCurrency)});
|
|
246
253
|
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
254
|
+
// Mock the store to return this accounting context
|
|
255
|
+
mockExpect(
|
|
256
|
+
address(store),
|
|
257
|
+
abi.encodeCall(IJBTerminalStore.accountingContextOf, (address(_terminal), _projectId, _usdc)),
|
|
258
|
+
abi.encode(_context)
|
|
259
|
+
);
|
|
253
260
|
|
|
254
261
|
JBAccountingContext memory _storedContext = _terminal.accountingContextForTokenOf(_projectId, _usdc);
|
|
255
262
|
assertEq(_storedContext.token, _usdc);
|
|
@@ -273,12 +280,12 @@ contract TestAddToBalanceOf_Local is JBMultiTerminalSetup {
|
|
|
273
280
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
274
281
|
JBAccountingContext({token: _usdc, decimals: 18, currency: uint32(_usdcCurrency)});
|
|
275
282
|
|
|
276
|
-
//
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
283
|
+
// Mock the store to return this accounting context
|
|
284
|
+
mockExpect(
|
|
285
|
+
address(store),
|
|
286
|
+
abi.encodeCall(IJBTerminalStore.accountingContextOf, (address(_terminal), _projectId, _usdc)),
|
|
287
|
+
abi.encode(_context)
|
|
288
|
+
);
|
|
282
289
|
|
|
283
290
|
JBAccountingContext memory _storedContext = _terminal.accountingContextForTokenOf(_projectId, _usdc);
|
|
284
291
|
assertEq(_storedContext.token, _usdc);
|
|
@@ -10,7 +10,6 @@ import {IJBController} from "../../../../src/interfaces/IJBController.sol";
|
|
|
10
10
|
import {IJBDirectory} from "../../../../src/interfaces/IJBDirectory.sol";
|
|
11
11
|
import {IJBFeelessAddresses} from "../../../../src/interfaces/IJBFeelessAddresses.sol";
|
|
12
12
|
import {IJBPermissions} from "../../../../src/interfaces/IJBPermissions.sol";
|
|
13
|
-
import {IJBRulesets} from "../../../../src/interfaces/IJBRulesets.sol";
|
|
14
13
|
import {IJBRulesetApprovalHook} from "../../../../src/interfaces/IJBRulesetApprovalHook.sol";
|
|
15
14
|
import {IJBTerminalStore} from "../../../../src/interfaces/IJBTerminalStore.sol";
|
|
16
15
|
import {JBConstants} from "../../../../src/libraries/JBConstants.sol";
|
|
@@ -22,7 +21,6 @@ import {JBRuleset} from "../../../../src/structs/JBRuleset.sol";
|
|
|
22
21
|
import {JBTokenAmount} from "../../../../src/structs/JBTokenAmount.sol";
|
|
23
22
|
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
24
23
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
25
|
-
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
26
24
|
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|
27
25
|
import {JBMultiTerminalSetup} from "./JBMultiTerminalSetup.sol";
|
|
28
26
|
|
|
@@ -54,29 +52,28 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
54
52
|
address(directory), abi.encodeCall(IJBDirectory.controllerOf, (_projectId)), abi.encode(address(this))
|
|
55
53
|
);
|
|
56
54
|
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
// Mock ERC20 transfer for non-contract token addresses (needed for SafeERC20 calls later).
|
|
56
|
+
if (token != JBConstants.NATIVE_TOKEN && token.code.length == 0) {
|
|
57
|
+
vm.mockCall(token, abi.encodeWithSelector(IERC20.transfer.selector), abi.encode(true));
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
JBAccountingContext[] memory _tokens = new JBAccountingContext[](1);
|
|
62
61
|
_tokens[0] = JBAccountingContext({token: token, decimals: decimals, currency: currency});
|
|
63
62
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
start: 0,
|
|
69
|
-
duration: 0,
|
|
70
|
-
weight: 0,
|
|
71
|
-
weightCutPercent: 0,
|
|
72
|
-
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
73
|
-
metadata: 0
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(returnedRuleset));
|
|
63
|
+
// Mock recordAccountingContextOf in the store (validation now happens there)
|
|
64
|
+
mockExpect(
|
|
65
|
+
address(store), abi.encodeCall(IJBTerminalStore.recordAccountingContextOf, (_projectId, _tokens)), ""
|
|
66
|
+
);
|
|
77
67
|
|
|
78
68
|
vm.prank(address(this));
|
|
79
69
|
_terminal.addAccountingContextsFor(_projectId, _tokens);
|
|
70
|
+
|
|
71
|
+
// Mock accountingContextOf for subsequent reads (not all code paths call it, so use mockCall only)
|
|
72
|
+
vm.mockCall(
|
|
73
|
+
address(store),
|
|
74
|
+
abi.encodeCall(IJBTerminalStore.accountingContextOf, (address(_terminal), _projectId, token)),
|
|
75
|
+
abi.encode(_tokens[0])
|
|
76
|
+
);
|
|
80
77
|
}
|
|
81
78
|
|
|
82
79
|
function test_WhenCallerDNHavePermission() external {
|
|
@@ -125,7 +122,8 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
125
122
|
uint256 reclaimAmount = 1e9;
|
|
126
123
|
JBCashOutHookSpecification[] memory hookSpecifications = new JBCashOutHookSpecification[](0);
|
|
127
124
|
JBAccountingContext memory mockTokenContext =
|
|
128
|
-
|
|
125
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
126
|
+
JBAccountingContext({token: _mockToken, decimals: 18, currency: uint32(uint160(_mockToken))});
|
|
129
127
|
JBAccountingContext[] memory mockBalanceContext = new JBAccountingContext[](1);
|
|
130
128
|
mockBalanceContext[0] = mockTokenContext;
|
|
131
129
|
JBRuleset memory returnedRuleset = JBRuleset({
|
|
@@ -148,7 +146,7 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
148
146
|
address(store),
|
|
149
147
|
abi.encodeCall(
|
|
150
148
|
IJBTerminalStore.recordCashOutFor,
|
|
151
|
-
(_holder, _projectId, _defaultAmount, mockTokenContext,
|
|
149
|
+
(_holder, _projectId, _defaultAmount, mockTokenContext.token, true, "")
|
|
152
150
|
),
|
|
153
151
|
abi.encode(returnedRuleset, reclaimAmount, _maxCashOutTaxRate, hookSpecifications)
|
|
154
152
|
);
|
|
@@ -165,6 +163,7 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
165
163
|
|
|
166
164
|
// put code at mockToken address to pass OZ Address check
|
|
167
165
|
vm.etch(_mockToken, abi.encode(1));
|
|
166
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
168
167
|
_acceptToken(_mockToken, 18, uint32(uint160(_mockToken)));
|
|
169
168
|
|
|
170
169
|
vm.prank(_bene);
|
|
@@ -177,7 +176,8 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
177
176
|
uint256 reclaimAmount = 1e9;
|
|
178
177
|
JBCashOutHookSpecification[] memory hookSpecifications = new JBCashOutHookSpecification[](0);
|
|
179
178
|
JBAccountingContext memory mockTokenContext =
|
|
180
|
-
|
|
179
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
180
|
+
JBAccountingContext({token: _mockToken, decimals: 18, currency: uint32(uint160(_mockToken))});
|
|
181
181
|
JBAccountingContext[] memory mockBalanceContext = new JBAccountingContext[](1);
|
|
182
182
|
mockBalanceContext[0] = mockTokenContext;
|
|
183
183
|
JBRuleset memory returnedRuleset = JBRuleset({
|
|
@@ -200,7 +200,7 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
200
200
|
address(store),
|
|
201
201
|
abi.encodeCall(
|
|
202
202
|
IJBTerminalStore.recordCashOutFor,
|
|
203
|
-
(_holder, _projectId, _defaultAmount, mockTokenContext,
|
|
203
|
+
(_holder, _projectId, _defaultAmount, mockTokenContext.token, true, "")
|
|
204
204
|
),
|
|
205
205
|
abi.encode(returnedRuleset, reclaimAmount, _maxCashOutTaxRate, hookSpecifications)
|
|
206
206
|
);
|
|
@@ -217,6 +217,7 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
217
217
|
|
|
218
218
|
// put code at mockToken address to pass OZ Address check
|
|
219
219
|
vm.etch(_mockToken, abi.encode(1));
|
|
220
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
220
221
|
_acceptToken(_mockToken, 18, uint32(uint160(_mockToken)));
|
|
221
222
|
|
|
222
223
|
vm.expectRevert(
|
|
@@ -238,7 +239,8 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
238
239
|
uint256 reclaimAmount = 1e9;
|
|
239
240
|
JBCashOutHookSpecification[] memory hookSpecifications = new JBCashOutHookSpecification[](0);
|
|
240
241
|
JBAccountingContext memory mockTokenContext =
|
|
241
|
-
|
|
242
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
243
|
+
JBAccountingContext({token: _mockToken, decimals: 18, currency: uint32(uint160(_mockToken))});
|
|
242
244
|
JBAccountingContext[] memory mockBalanceContext = new JBAccountingContext[](1);
|
|
243
245
|
mockBalanceContext[0] = mockTokenContext;
|
|
244
246
|
JBRuleset memory returnedRuleset = JBRuleset({
|
|
@@ -261,7 +263,7 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
261
263
|
address(store),
|
|
262
264
|
abi.encodeCall(
|
|
263
265
|
IJBTerminalStore.recordCashOutFor,
|
|
264
|
-
(_holder, _projectId, _defaultAmount, mockTokenContext,
|
|
266
|
+
(_holder, _projectId, _defaultAmount, mockTokenContext.token, false, "")
|
|
265
267
|
),
|
|
266
268
|
abi.encode(returnedRuleset, reclaimAmount, _halfCashOutTaxRate, hookSpecifications)
|
|
267
269
|
);
|
|
@@ -278,6 +280,7 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
278
280
|
|
|
279
281
|
// put code at mockToken address to pass OZ Address check
|
|
280
282
|
vm.etch(_mockToken, abi.encode(1));
|
|
283
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
281
284
|
_acceptToken(_mockToken, 18, uint32(uint160(_mockToken)));
|
|
282
285
|
|
|
283
286
|
// get fee amount
|
|
@@ -378,7 +381,7 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
378
381
|
address(store),
|
|
379
382
|
abi.encodeCall(
|
|
380
383
|
IJBTerminalStore.recordCashOutFor,
|
|
381
|
-
(_holder, _projectId, _defaultAmount, mockTokenContext,
|
|
384
|
+
(_holder, _projectId, _defaultAmount, mockTokenContext.token, true, "")
|
|
382
385
|
),
|
|
383
386
|
abi.encode(returnedRuleset, reclaimAmount, _maxCashOutTaxRate, hookSpecifications)
|
|
384
387
|
);
|
|
@@ -495,7 +498,7 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
495
498
|
address(store),
|
|
496
499
|
abi.encodeCall(
|
|
497
500
|
IJBTerminalStore.recordCashOutFor,
|
|
498
|
-
(_holder, _projectId, _defaultAmount, mockTokenContext,
|
|
501
|
+
(_holder, _projectId, _defaultAmount, mockTokenContext.token, true, "")
|
|
499
502
|
),
|
|
500
503
|
abi.encode(returnedRuleset, reclaimAmount, _maxCashOutTaxRate, hookSpecifications)
|
|
501
504
|
);
|
|
@@ -583,7 +586,8 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
583
586
|
hookSpecifications[0] =
|
|
584
587
|
JBCashOutHookSpecification({hook: IJBCashOutHook(address(this)), noop: true, amount: 0, metadata: "info"});
|
|
585
588
|
JBAccountingContext memory mockTokenContext =
|
|
586
|
-
|
|
589
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
590
|
+
JBAccountingContext({token: _mockToken, decimals: 18, currency: uint32(uint160(_mockToken))});
|
|
587
591
|
JBAccountingContext[] memory mockBalanceContext = new JBAccountingContext[](1);
|
|
588
592
|
mockBalanceContext[0] = mockTokenContext;
|
|
589
593
|
JBRuleset memory returnedRuleset = JBRuleset({
|
|
@@ -603,7 +607,7 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
603
607
|
address(store),
|
|
604
608
|
abi.encodeCall(
|
|
605
609
|
IJBTerminalStore.recordCashOutFor,
|
|
606
|
-
(_holder, _projectId, _defaultAmount, mockTokenContext,
|
|
610
|
+
(_holder, _projectId, _defaultAmount, mockTokenContext.token, true, "")
|
|
607
611
|
),
|
|
608
612
|
abi.encode(returnedRuleset, reclaimAmount, _maxCashOutTaxRate, hookSpecifications)
|
|
609
613
|
);
|
|
@@ -614,6 +618,7 @@ contract TestCashOutTokensOf_Local is JBMultiTerminalSetup {
|
|
|
614
618
|
address(this), abi.encodeCall(IJBController.burnTokensOf, (_holder, _projectId, _defaultAmount, "")), ""
|
|
615
619
|
);
|
|
616
620
|
|
|
621
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
617
622
|
_acceptToken(_mockToken, 18, uint32(uint160(_mockToken)));
|
|
618
623
|
|
|
619
624
|
vm.prank(_bene);
|