@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.
Files changed (48) hide show
  1. package/ADMINISTRATION.md +0 -1
  2. package/AUDIT_INSTRUCTIONS.md +1 -1
  3. package/CHANGE_LOG.md +3 -3
  4. package/RISKS.md +3 -3
  5. package/SKILLS.md +8 -8
  6. package/USER_JOURNEYS.md +1 -1
  7. package/foundry.toml +0 -1
  8. package/package.json +1 -1
  9. package/src/JBMultiTerminal.sol +92 -192
  10. package/src/JBTerminalStore.sol +405 -235
  11. package/src/interfaces/IJBMultiTerminal.sol +0 -4
  12. package/src/interfaces/IJBTerminal.sol +4 -4
  13. package/src/interfaces/IJBTerminalStore.sol +65 -33
  14. package/src/libraries/JBPayoutSplitGroupLib.sol +3 -4
  15. package/src/libraries/JBSurplus.sol +3 -4
  16. package/test/ComprehensiveInvariant.t.sol +5 -7
  17. package/test/CoreExploitTests.t.sol +18 -23
  18. package/test/TestCashOut.sol +6 -6
  19. package/test/TestMultiTerminalSurplus.sol +4 -4
  20. package/test/TestMultiTokenSurplus.sol +6 -23
  21. package/test/TestTerminalMigration.sol +2 -7
  22. package/test/fork/TestSequencerPriceFeedFork.sol +1 -1
  23. package/test/fork/TestTerminalPreviewParityFork.sol +0 -1
  24. package/test/invariants/TerminalStoreInvariant.t.sol +5 -7
  25. package/test/units/static/JBMultiTerminal/JBMultiTerminalSetup.sol +1 -2
  26. package/test/units/static/JBMultiTerminal/TestAccountingContextsOf.sol +23 -24
  27. package/test/units/static/JBMultiTerminal/TestAddAccountingContextsFor.sol +79 -119
  28. package/test/units/static/JBMultiTerminal/TestAddToBalanceOf.sol +33 -26
  29. package/test/units/static/JBMultiTerminal/TestCashOutTokensOf.sol +32 -27
  30. package/test/units/static/JBMultiTerminal/TestExecutePayout.sol +22 -4
  31. package/test/units/static/JBMultiTerminal/TestExecuteProcessFee.sol +8 -5
  32. package/test/units/static/JBMultiTerminal/TestPay.sol +41 -33
  33. package/test/units/static/JBMultiTerminal/TestPreviewCashOutFrom.sol +19 -18
  34. package/test/units/static/JBMultiTerminal/TestPreviewPayFor.sol +38 -22
  35. package/test/units/static/JBMultiTerminal/TestProcessHeldFeesOf.sol +9 -6
  36. package/test/units/static/JBMultiTerminal/TestSendPayoutsOf.sol +4 -4
  37. package/test/units/static/JBMultiTerminal/TestUseAllowanceOf.sol +37 -32
  38. package/test/units/static/JBSurplus/TestSurplusFuzz.sol +5 -20
  39. package/test/units/static/JBTerminalStore/JBTerminalStoreSetup.sol +17 -0
  40. package/test/units/static/JBTerminalStore/TestCurrentReclaimableSurplusOf.sol +120 -246
  41. package/test/units/static/JBTerminalStore/TestCurrentSurplusOf.sol +29 -7
  42. package/test/units/static/JBTerminalStore/TestCurrentTotalSurplusOf.sol +88 -20
  43. package/test/units/static/JBTerminalStore/TestPreviewCashOutFrom.sol +30 -29
  44. package/test/units/static/JBTerminalStore/TestPreviewPayFrom.sol +46 -16
  45. package/test/units/static/JBTerminalStore/TestRecordCashOutsFor.sol +24 -53
  46. package/test/units/static/JBTerminalStore/TestRecordPayoutFor.sol +24 -4
  47. package/test/units/static/JBTerminalStore/TestRecordUsedAllowanceOf.sol +14 -4
  48. package/test/units/static/JBTerminalStore/TestUint224Overflow.sol +21 -3
@@ -37,9 +37,8 @@ contract JBMultiTerminalSetup is JBTest {
37
37
  address trustedForwarder = makeAddr("forwarder");
38
38
 
39
39
  function multiTerminalSetup() public virtual {
40
- // Constructor will call to find directory and rulesets from the terminal store
40
+ // Constructor will call to find directory from the terminal store
41
41
  mockExpect(address(store), abi.encodeCall(IJBTerminalStore.DIRECTORY, ()), abi.encode(address(directory)));
42
- mockExpect(address(store), abi.encodeCall(IJBTerminalStore.RULESETS, ()), abi.encode(address(rulesets)));
43
42
 
44
43
  // Instantiate the contract being tested
45
44
  _terminal = new JBMultiTerminal(
@@ -2,11 +2,8 @@
2
2
  pragma solidity 0.8.26;
3
3
 
4
4
  import {IJBDirectory} from "../../../../src/interfaces/IJBDirectory.sol";
5
- import {IJBRulesetApprovalHook} from "../../../../src/interfaces/IJBRulesetApprovalHook.sol";
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 view {
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 {JBMultiTerminal} from "../../../../src/JBMultiTerminal.sol";
4
+ import {JBTerminalStore} from "../../../../src/JBTerminalStore.sol";
5
5
  import {IJBDirectory} from "../../../../src/interfaces/IJBDirectory.sol";
6
- import {IJBRulesetApprovalHook} from "../../../../src/interfaces/IJBRulesetApprovalHook.sol";
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(JBMultiTerminal.JBMultiTerminal_AccountingContextAlreadySet.selector, _usdc)
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
- // mock call to rulesets currentOf returning 0 to bypass ruleset checking
132
-
133
- // setup: return data
134
- JBRuleset memory ruleset = JBRuleset({
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
- // setup: return data
177
- JBRuleset memory ruleset = JBRuleset({
178
- cycleNumber: 1,
179
- id: 0,
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
- // setup: return data
220
- JBRuleset memory ruleset = generateUnfriendlyRuleset();
221
-
222
- // mock rulesets call
223
- mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(ruleset));
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(JBMultiTerminal.JBMultiTerminal_AddingAccountingContextNotAllowed.selector);
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 JBMultiTerminal_AccountingContextDecimalsMismatch
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
- // setup: return data
251
- JBRuleset memory ruleset = generateFriendlyRuleset();
252
-
253
- // mock rulesets call
254
- mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(ruleset));
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(JBMultiTerminal.JBMultiTerminal_AccountingContextDecimalsMismatch.selector);
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 JBMultiTerminal_AccountingContextDecimalsMismatch
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
- // setup: return data
285
- JBRuleset memory ruleset = generateFriendlyRuleset();
286
-
287
- // mock rulesets call
288
- mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(ruleset));
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(JBMultiTerminal.JBMultiTerminal_AccountingContextDecimalsMismatch.selector);
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 JBMultiTerminal_ZeroAccountingContextCurrency
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
- // setup: return data
318
- JBRuleset memory ruleset = generateFriendlyRuleset();
319
-
320
- // mock rulesets call
321
- mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(ruleset));
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(JBMultiTerminal.JBMultiTerminal_ZeroAccountingContextCurrency.selector);
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
- // Find the storage slot
59
- bytes32 contextSlot = keccak256(abi.encode(_projectId, uint256(0)));
60
- bytes32 slot = keccak256(abi.encode(_native, contextSlot));
61
-
62
- // Set storage
63
- vm.store(address(_terminal), slot, bytes32(abi.encode(_context)));
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
- // Find the storage slot
79
- bytes32 contextSlot = keccak256(abi.encode(_projectId, uint256(0)));
80
- bytes32 slot = keccak256(abi.encode(_native, contextSlot));
81
-
82
- // Set storage
83
- vm.store(address(_terminal), slot, bytes32(abi.encode(_context)));
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 3)
89
- bytes32 feeSlot = keccak256(abi.encode(_projectId, uint256(3)));
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
- // Find the storage slot
248
- bytes32 contextSlot = keccak256(abi.encode(_projectId, uint256(0)));
249
- bytes32 slot = keccak256(abi.encode(_usdc, contextSlot));
250
-
251
- // Set storage
252
- vm.store(address(_terminal), slot, bytes32(abi.encode(_context)));
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
- // Find the storage slot
277
- bytes32 contextSlot = keccak256(abi.encode(_projectId, uint256(0)));
278
- bytes32 slot = keccak256(abi.encode(_usdc, contextSlot));
279
-
280
- // Set storage
281
- vm.store(address(_terminal), slot, bytes32(abi.encode(_context)));
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);