@bananapus/core-v6 0.0.21 → 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 +0 -1
  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
@@ -45,6 +45,11 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
45
45
 
46
46
  function setUp() public {
47
47
  super.terminalStoreSetup();
48
+
49
+ // Register accounting context so the store can look up decimals/currency for the token.
50
+ JBAccountingContext[] memory _ctxs = new JBAccountingContext[](1);
51
+ _ctxs[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
52
+ _store.recordAccountingContextOf(_projectId, _ctxs);
48
53
  }
49
54
 
50
55
  modifier whenCurrentRulesetUseTotalSurplusForCashOutsEqTrue() {
@@ -73,16 +78,14 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
73
78
  mockExpect(address(directory), _directoryCall, _returned);
74
79
 
75
80
  // mock call to first terminal currentSurplusOf
76
- bytes memory _terminal1Call = abi.encodeCall(
77
- IJBTerminal.currentSurplusOf, (_projectId, new JBAccountingContext[](0), _decimals, _currency)
78
- );
81
+ bytes memory _terminal1Call =
82
+ abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, new address[](0), _decimals, _currency));
79
83
  bytes memory _terminal1Return = abi.encode(1e18);
80
84
  mockExpect(address(_terminal1), _terminal1Call, _terminal1Return);
81
85
 
82
86
  // mock call to first terminal currentSurplusOf
83
- bytes memory _terminal2Call = abi.encodeCall(
84
- IJBTerminal.currentSurplusOf, (_projectId, new JBAccountingContext[](0), _decimals, _currency)
85
- );
87
+ bytes memory _terminal2Call =
88
+ abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, new address[](0), _decimals, _currency));
86
89
  bytes memory _terminal2Return = abi.encode(2e18);
87
90
  mockExpect(address(_terminal2), _terminal2Call, _terminal2Return);
88
91
 
@@ -158,16 +161,14 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
158
161
  mockExpect(address(directory), _directoryCall, _returned);
159
162
 
160
163
  // mock call to first terminal currentSurplusOf
161
- bytes memory _terminal1Call = abi.encodeCall(
162
- IJBTerminal.currentSurplusOf, (_projectId, new JBAccountingContext[](0), _decimals, _currency)
163
- );
164
+ bytes memory _terminal1Call =
165
+ abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, new address[](0), _decimals, _currency));
164
166
  bytes memory _terminal1Return = abi.encode(1e18);
165
167
  mockExpect(address(_terminal1), _terminal1Call, _terminal1Return);
166
168
 
167
169
  // mock call to first terminal currentSurplusOf
168
- bytes memory _terminal2Call = abi.encodeCall(
169
- IJBTerminal.currentSurplusOf, (_projectId, new JBAccountingContext[](0), _decimals, _currency)
170
- );
170
+ bytes memory _terminal2Call =
171
+ abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, new address[](0), _decimals, _currency));
171
172
  bytes memory _terminal2Return = abi.encode(2e18);
172
173
  mockExpect(address(_terminal2), _terminal2Call, _terminal2Return);
173
174
 
@@ -243,16 +244,14 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
243
244
  mockExpect(address(directory), _directoryCall, _returned);
244
245
 
245
246
  // mock call to first terminal currentSurplusOf
246
- bytes memory _terminal1Call = abi.encodeCall(
247
- IJBTerminal.currentSurplusOf, (_projectId, new JBAccountingContext[](0), _decimals, _currency)
248
- );
247
+ bytes memory _terminal1Call =
248
+ abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, new address[](0), _decimals, _currency));
249
249
  bytes memory _terminal1Return = abi.encode(1e18);
250
250
  mockExpect(address(_terminal1), _terminal1Call, _terminal1Return);
251
251
 
252
252
  // mock call to first terminal currentSurplusOf
253
- bytes memory _terminal2Call = abi.encodeCall(
254
- IJBTerminal.currentSurplusOf, (_projectId, new JBAccountingContext[](0), _decimals, _currency)
255
- );
253
+ bytes memory _terminal2Call =
254
+ abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, new address[](0), _decimals, _currency));
256
255
  bytes memory _terminal2Return = abi.encode(2e18);
257
256
  mockExpect(address(_terminal2), _terminal2Call, _terminal2Return);
258
257
 
@@ -318,13 +317,6 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
318
317
  JBCurrencyAmount[] memory _payoutLimits = new JBCurrencyAmount[](1);
319
318
  _payoutLimits[0] = JBCurrencyAmount({amount: 1e17, currency: _currency});
320
319
 
321
- // call params
322
- JBAccountingContext memory _accountingContexts =
323
- JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
324
- JBAccountingContext[] memory _balanceContexts = new JBAccountingContext[](1);
325
-
326
- _balanceContexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
327
-
328
320
  uint256 _cashOutCount = 4e18; // greater than token total supply
329
321
 
330
322
  vm.expectRevert(
@@ -334,8 +326,7 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
334
326
  holder: address(this),
335
327
  projectId: _projectId,
336
328
  cashOutCount: _cashOutCount,
337
- accountingContext: _accountingContexts,
338
- balanceAccountingContexts: _balanceContexts,
329
+ tokenToReclaim: address(_token),
339
330
  beneficiaryIsFeeless: false,
340
331
  metadata: ""
341
332
  });
@@ -354,13 +345,6 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
354
345
  JBCurrencyAmount[] memory _payoutLimits = new JBCurrencyAmount[](1);
355
346
  _payoutLimits[0] = JBCurrencyAmount({amount: 1e17, currency: _currency});
356
347
 
357
- // call params
358
- JBAccountingContext memory _accountingContexts =
359
- JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
360
- JBAccountingContext[] memory _balanceContexts = new JBAccountingContext[](1);
361
-
362
- _balanceContexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
363
-
364
348
  uint256 _cashOutCount = 6; // within balance bounds
365
349
  uint256 expectedCashOuts = mulDiv(3e18, _cashOutCount, _totalSupply);
366
350
 
@@ -368,8 +352,7 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
368
352
  holder: address(this),
369
353
  projectId: _projectId,
370
354
  cashOutCount: _cashOutCount,
371
- accountingContext: _accountingContexts,
372
- balanceAccountingContexts: _balanceContexts,
355
+ tokenToReclaim: address(_token),
373
356
  beneficiaryIsFeeless: false,
374
357
  metadata: ""
375
358
  });
@@ -443,8 +426,7 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
443
426
  holder: address(this),
444
427
  projectId: _projectId,
445
428
  cashOutCount: _cashOutCount,
446
- accountingContext: _accountingContexts,
447
- balanceAccountingContexts: _balanceContexts,
429
+ tokenToReclaim: address(_token),
448
430
  beneficiaryIsFeeless: false,
449
431
  metadata: ""
450
432
  });
@@ -469,13 +451,6 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
469
451
  abi.encode(_totalTokens)
470
452
  );
471
453
 
472
- // call params
473
- JBAccountingContext memory _accountingContexts =
474
- JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
475
- JBAccountingContext[] memory _balanceContexts = new JBAccountingContext[](1);
476
-
477
- _balanceContexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
478
-
479
454
  uint256 _cashOutCount = 4e18; // greater than caller balance
480
455
 
481
456
  uint256 reclaimAmount = mulDiv(_currentSurplus, _cashOutCount, _totalTokens);
@@ -489,8 +464,7 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
489
464
  holder: address(this),
490
465
  projectId: _projectId,
491
466
  cashOutCount: _cashOutCount,
492
- accountingContext: _accountingContexts,
493
- balanceAccountingContexts: _balanceContexts,
467
+ tokenToReclaim: address(_token),
494
468
  beneficiaryIsFeeless: false,
495
469
  metadata: ""
496
470
  });
@@ -554,8 +528,7 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
554
528
  holder: address(this),
555
529
  projectId: _projectId,
556
530
  cashOutCount: _cashOutCount,
557
- accountingContext: _accountingContexts,
558
- balanceAccountingContexts: _balanceContexts,
531
+ tokenToReclaim: address(_token),
559
532
  beneficiaryIsFeeless: true,
560
533
  metadata: ""
561
534
  });
@@ -611,8 +584,7 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
611
584
  holder: address(this),
612
585
  projectId: _projectId,
613
586
  cashOutCount: 1e18,
614
- accountingContext: _accountingContexts,
615
- balanceAccountingContexts: _balanceContexts,
587
+ tokenToReclaim: address(_token),
616
588
  beneficiaryIsFeeless: false,
617
589
  metadata: ""
618
590
  });
@@ -667,8 +639,7 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
667
639
  holder: address(this),
668
640
  projectId: _projectId,
669
641
  cashOutCount: 1e18,
670
- accountingContext: _accountingContexts,
671
- balanceAccountingContexts: _balanceContexts,
642
+ tokenToReclaim: address(_token),
672
643
  beneficiaryIsFeeless: false,
673
644
  metadata: ""
674
645
  });
@@ -36,6 +36,13 @@ contract TestRecordPayoutFor_Local is JBTerminalStoreSetup {
36
36
  super.terminalStoreSetup();
37
37
  }
38
38
 
39
+ /// @notice Helper to register an accounting context with the store (from address(this) as terminal).
40
+ function _registerContext(address token, uint32 currency) internal {
41
+ JBAccountingContext[] memory ctxs = new JBAccountingContext[](1);
42
+ ctxs[0] = JBAccountingContext({token: token, decimals: 18, currency: currency});
43
+ _store.recordAccountingContextOf(_projectId, ctxs);
44
+ }
45
+
39
46
  modifier whenThereIsAZeroUsedPayoutLimitOfTheSenderForCurrentRuleset() {
40
47
  JBRulesetMetadata memory _metadata = JBRulesetMetadata({
41
48
  reservedPercent: 0,
@@ -147,6 +154,9 @@ contract TestRecordPayoutFor_Local is JBTerminalStoreSetup {
147
154
  {
148
155
  // it will revert JBTerminalStore_InadequateTerminalStoreBalance
149
156
 
157
+ // Register accounting context so the store can look up decimals/currency for the token.
158
+ _registerContext(address(_token), _currency);
159
+
150
160
  // setup calldata
151
161
  JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
152
162
  _contexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
@@ -156,7 +166,7 @@ contract TestRecordPayoutFor_Local is JBTerminalStoreSetup {
156
166
  JBTerminalStore.JBTerminalStore_InadequateTerminalStoreBalance.selector, _defaultValue, 0
157
167
  )
158
168
  );
159
- _store.recordPayoutFor(_projectId, _contexts[0], _defaultValue, _currency);
169
+ _store.recordPayoutFor(_projectId, _contexts[0].token, _defaultValue, _currency);
160
170
  }
161
171
 
162
172
  function test_GivenTheCallingCurrencyEqTheContextCurrency()
@@ -165,6 +175,9 @@ contract TestRecordPayoutFor_Local is JBTerminalStoreSetup {
165
175
  {
166
176
  // it will not convert prices, update balances and return
167
177
 
178
+ // Register accounting context so the store can look up decimals/currency for the token.
179
+ _registerContext(address(_token), _currency);
180
+
168
181
  // Find the storage slot
169
182
  bytes32 balanceOfSlot = keccak256(abi.encode(address(this), uint256(0)));
170
183
  bytes32 projectSlot = keccak256(abi.encode(_projectId, uint256(balanceOfSlot)));
@@ -193,7 +206,7 @@ contract TestRecordPayoutFor_Local is JBTerminalStoreSetup {
193
206
 
194
207
  uint256 balanceBefore = _store.balanceOf(address(this), _projectId, address(_token));
195
208
 
196
- (, uint256 amountPaid) = _store.recordPayoutFor(_projectId, _contexts[0], _defaultValue, _currency);
209
+ (, uint256 amountPaid) = _store.recordPayoutFor(_projectId, _contexts[0].token, _defaultValue, _currency);
197
210
  assertEq(amountPaid, _defaultValue);
198
211
 
199
212
  // check usedPayoutLimit updated correctly
@@ -213,6 +226,10 @@ contract TestRecordPayoutFor_Local is JBTerminalStoreSetup {
213
226
  {
214
227
  // it will convert prices and return
215
228
 
229
+ // Register accounting context with _nativeCurrency so currency != accountingContext.currency triggers
230
+ // conversion.
231
+ _registerContext(address(_token), _nativeCurrency);
232
+
216
233
  // Find the storage slot
217
234
  bytes32 balanceOfSlot = keccak256(abi.encode(address(this), uint256(0)));
218
235
  bytes32 projectSlot = keccak256(abi.encode(_projectId, uint256(balanceOfSlot)));
@@ -245,7 +262,7 @@ contract TestRecordPayoutFor_Local is JBTerminalStoreSetup {
245
262
  bytes memory _pricesReturn = abi.encode(2e18);
246
263
  mockExpect(address(prices), _pricesCall, _pricesReturn);
247
264
 
248
- (, uint256 amountPaid) = _store.recordPayoutFor(_projectId, _contexts[0], _defaultValue, _currency);
265
+ (, uint256 amountPaid) = _store.recordPayoutFor(_projectId, _contexts[0].token, _defaultValue, _currency);
249
266
  assertEq(amountPaid, _defaultValue / 2);
250
267
  }
251
268
 
@@ -255,6 +272,9 @@ contract TestRecordPayoutFor_Local is JBTerminalStoreSetup {
255
272
  {
256
273
  // it will revert INADEQUATE_TERMINAL_STORE_BALANCE
257
274
 
275
+ // Register accounting context so the store can look up decimals/currency for the token.
276
+ _registerContext(address(_token), _currency);
277
+
258
278
  // setup calldata
259
279
  JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
260
280
  _contexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
@@ -264,6 +284,6 @@ contract TestRecordPayoutFor_Local is JBTerminalStoreSetup {
264
284
  JBTerminalStore.JBTerminalStore_InadequateTerminalStoreBalance.selector, _defaultValue, 0
265
285
  )
266
286
  );
267
- _store.recordPayoutFor(_projectId, _contexts[0], _defaultValue, _currency);
287
+ _store.recordPayoutFor(_projectId, _contexts[0].token, _defaultValue, _currency);
268
288
  }
269
289
  }
@@ -35,6 +35,11 @@ contract TestRecordUsedAllowanceOf_Local is JBTerminalStoreSetup {
35
35
 
36
36
  function setUp() public {
37
37
  super.terminalStoreSetup();
38
+
39
+ // Register accounting context so the store can look up decimals/currency for the token.
40
+ JBAccountingContext[] memory _ctxs = new JBAccountingContext[](1);
41
+ _ctxs[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
42
+ _store.recordAccountingContextOf(_projectId, _ctxs);
38
43
  }
39
44
 
40
45
  modifier whenAmountIsWithinRangeToUseSurplusAllowance() {
@@ -134,13 +139,18 @@ contract TestRecordUsedAllowanceOf_Local is JBTerminalStoreSetup {
134
139
  JBAccountingContext memory _context =
135
140
  JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
136
141
 
137
- (, uint256 usedAmount) = _store.recordUsedAllowanceOf(_projectId, _context, _defaultAmount, _currency);
142
+ (, uint256 usedAmount) = _store.recordUsedAllowanceOf(_projectId, _context.token, _defaultAmount, _currency);
138
143
  assertEq(usedAmount, _defaultAmount);
139
144
  }
140
145
 
141
146
  function test_GivenCallingCurrencyDneqAccountingCurrency() external {
142
147
  // it will convert prices
143
148
 
149
+ // Register accounting context for the native token so the store can look up decimals/currency.
150
+ JBAccountingContext[] memory _nativeCtxs = new JBAccountingContext[](1);
151
+ _nativeCtxs[0] = JBAccountingContext({token: address(_nativeAddress), decimals: 18, currency: _nativeCurrency});
152
+ _store.recordAccountingContextOf(_projectId, _nativeCtxs);
153
+
144
154
  // Find the storage slot
145
155
  bytes32 balanceOfSlot = keccak256(abi.encode(address(this), uint256(0)));
146
156
  bytes32 projectSlot = keccak256(abi.encode(_projectId, uint256(balanceOfSlot)));
@@ -238,7 +248,7 @@ contract TestRecordUsedAllowanceOf_Local is JBTerminalStoreSetup {
238
248
  JBAccountingContext({token: address(_nativeAddress), decimals: 18, currency: _nativeCurrency});
239
249
 
240
250
  // price is 1:1
241
- (, uint256 usedAmount) = _store.recordUsedAllowanceOf(_projectId, _context, _defaultAmount, _currency);
251
+ (, uint256 usedAmount) = _store.recordUsedAllowanceOf(_projectId, _context.token, _defaultAmount, _currency);
242
252
  assertEq(usedAmount, _defaultAmount);
243
253
  }
244
254
 
@@ -317,7 +327,7 @@ contract TestRecordUsedAllowanceOf_Local is JBTerminalStoreSetup {
317
327
  JBTerminalStore.JBTerminalStore_InadequateTerminalStoreBalance.selector, _defaultAmount, 0
318
328
  )
319
329
  );
320
- _store.recordUsedAllowanceOf(_projectId, _context, _defaultAmount, _currency);
330
+ _store.recordUsedAllowanceOf(_projectId, _context.token, _defaultAmount, _currency);
321
331
  }
322
332
 
323
333
  function test_WhenAmountIsNotWithinRangeToUseSurplusAllowance() external {
@@ -400,6 +410,6 @@ contract TestRecordUsedAllowanceOf_Local is JBTerminalStoreSetup {
400
410
  0 // no balance
401
411
  )
402
412
  );
403
- _store.recordUsedAllowanceOf(_projectId, _context, _defaultAmount, _currency);
413
+ _store.recordUsedAllowanceOf(_projectId, _context.token, _defaultAmount, _currency);
404
414
  }
405
415
  }
@@ -35,6 +35,21 @@ contract TestUint224Overflow_Local is JBTerminalStoreSetup {
35
35
  super.terminalStoreSetup();
36
36
  }
37
37
 
38
+ /// @notice Helper to call currentSurplusOf with the new multi-terminal signature.
39
+ function _currentSurplusOf(uint256 decimals, uint256 currency) internal view returns (uint256) {
40
+ IJBTerminal[] memory terminals = new IJBTerminal[](1);
41
+ terminals[0] = _terminal;
42
+ return _store.currentSurplusOf(_projectId, terminals, new address[](0), decimals, currency);
43
+ }
44
+
45
+ /// @notice Helper to register an accounting context with the store (pranks as the terminal).
46
+ function _registerContext(JBAccountingContext memory ctx) internal {
47
+ JBAccountingContext[] memory ctxs = new JBAccountingContext[](1);
48
+ ctxs[0] = ctx;
49
+ vm.prank(address(_terminal));
50
+ _store.recordAccountingContextOf(_projectId, ctxs);
51
+ }
52
+
38
53
  /// @notice Helper to set balance for a terminal/project/token via vm.store.
39
54
  function _setBalance(address terminal, uint256 projectId, address token, uint256 balance) internal {
40
55
  bytes32 balanceOfSlot = keccak256(abi.encode(terminal, uint256(0)));
@@ -121,11 +136,12 @@ contract TestUint224Overflow_Local is JBTerminalStoreSetup {
121
136
  // Accounting context: token has 6 decimals.
122
137
  JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
123
138
  _contexts[0] = JBAccountingContext({token: address(_token), decimals: 6, currency: _currency});
139
+ _registerContext(_contexts[0]);
124
140
 
125
141
  // Query surplus with 18 target decimals — triggers decimal adjustment overflow.
126
142
  uint256 adjusted = uint256(amount) * 1e12;
127
143
  vm.expectRevert(abi.encodeWithSelector(JBTerminalStore.JBTerminalStore_Uint224Overflow.selector, adjusted));
128
- _store.currentSurplusOf(address(_terminal), _projectId, _contexts, 18, _currency);
144
+ _currentSurplusOf(18, _currency);
129
145
  }
130
146
 
131
147
  /// @notice Verifies that currency conversion overflow reverts with Uint224Overflow.
@@ -163,10 +179,11 @@ contract TestUint224Overflow_Local is JBTerminalStoreSetup {
163
179
  // Same decimals so no decimal adjustment.
164
180
  JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
165
181
  _contexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
182
+ _registerContext(_contexts[0]);
166
183
 
167
184
  // The conversion: mulDiv(type(uint224).max, 10^18, 1) = type(uint224).max * 10^18 → overflows uint224.
168
185
  vm.expectRevert();
169
- _store.currentSurplusOf(address(_terminal), _projectId, _contexts, 18, _currency);
186
+ _currentSurplusOf(18, _currency);
170
187
  }
171
188
 
172
189
  /// @notice Verifies that normal amounts below uint224.max pass through without reverting.
@@ -194,8 +211,9 @@ contract TestUint224Overflow_Local is JBTerminalStoreSetup {
194
211
  // Balance: 100e6 → 100e18. Payout limit: 50e6 → 50e18. Surplus = 50e18.
195
212
  JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
196
213
  _contexts[0] = JBAccountingContext({token: address(_token), decimals: 6, currency: _currency});
214
+ _registerContext(_contexts[0]);
197
215
 
198
- uint256 surplus = _store.currentSurplusOf(address(_terminal), _projectId, _contexts, 18, _currency);
216
+ uint256 surplus = _currentSurplusOf(18, _currency);
199
217
  assertEq(surplus, 50e18);
200
218
  }
201
219
  }