@bananapus/core-v6 0.0.19 → 0.0.21
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 +3 -0
- package/ARCHITECTURE.md +24 -0
- package/AUDIT_INSTRUCTIONS.md +4 -2
- package/CHANGE_LOG.md +17 -4
- package/README.md +12 -2
- package/RISKS.md +10 -2
- package/SKILLS.md +5 -2
- package/USER_JOURNEYS.md +4 -2
- package/foundry.toml +1 -0
- package/package.json +1 -1
- package/src/JBController.sol +52 -5
- package/src/JBMultiTerminal.sol +197 -179
- package/src/JBTerminalStore.sol +17 -7
- package/src/interfaces/IJBCashOutTerminal.sol +30 -0
- package/src/interfaces/IJBController.sol +15 -0
- package/src/interfaces/IJBTerminal.sol +28 -0
- package/src/interfaces/IJBTerminalStore.sol +1 -5
- package/src/libraries/JBPayoutSplitGroupLib.sol +157 -0
- package/src/structs/JBCashOutHookSpecification.sol +2 -0
- package/src/structs/JBPayHookSpecification.sol +2 -0
- package/test/CoreExploitTests.t.sol +21 -10
- package/test/TestCashOutHooks.sol +6 -4
- package/test/TestDataHookFuzzing.sol +6 -2
- package/test/TestPayHooks.sol +1 -1
- package/test/TestRulesetQueueing.sol +4 -5
- package/test/TestRulesetQueuingStress.sol +5 -3
- package/test/TestTerminalPreviewParity.sol +208 -0
- package/test/fork/TestTerminalPreviewParityFork.sol +109 -0
- package/test/units/static/JBController/TestPreviewMintOf.sol +116 -0
- package/test/units/static/JBMultiTerminal/TestCashOutTokensOf.sol +144 -25
- package/test/units/static/JBMultiTerminal/TestExecutePayout.sol +11 -1
- package/test/units/static/JBMultiTerminal/TestExecuteProcessFee.sol +15 -2
- package/test/units/static/JBMultiTerminal/TestPay.sol +64 -2
- package/test/units/static/JBMultiTerminal/TestPreviewCashOutFrom.sol +116 -0
- package/test/units/static/JBMultiTerminal/TestPreviewPayFor.sol +98 -0
- package/test/units/static/JBMultiTerminal/TestProcessHeldFeesOf.sol +11 -2
- package/test/units/static/JBRulesets/TestCurrentOf.sol +8 -6
- package/test/units/static/JBRulesets/TestRulesets.sol +25 -24
- package/test/units/static/JBRulesets/TestUpcomingRulesetOf.sol +4 -17
- package/test/units/static/JBSurplus/TestSurplusFuzz.sol +49 -2
- package/test/units/static/JBTerminalStore/TestPreviewCashOutFrom.sol +96 -4
- package/test/units/static/JBTerminalStore/TestPreviewPayFrom.sol +81 -32
- package/test/units/static/JBTerminalStore/TestRecordCashOutsFor.sol +113 -2
- package/test/units/static/JBTerminalStore/TestRecordPaymentFrom.sol +227 -5
|
@@ -133,7 +133,6 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
133
133
|
);
|
|
134
134
|
|
|
135
135
|
(, uint256 previewReclaimAmount, uint256 previewTaxRate, JBCashOutHookSpecification[] memory previewSpecs) = _store.previewCashOutFrom({
|
|
136
|
-
terminal: address(this),
|
|
137
136
|
holder: address(this),
|
|
138
137
|
projectId: _projectId,
|
|
139
138
|
cashOutCount: _cashOutCount,
|
|
@@ -222,7 +221,6 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
222
221
|
uint256 balanceBefore = _store.balanceOf(address(this), _projectId, address(_token));
|
|
223
222
|
|
|
224
223
|
_store.previewCashOutFrom({
|
|
225
|
-
terminal: address(this),
|
|
226
224
|
holder: address(this),
|
|
227
225
|
projectId: _projectId,
|
|
228
226
|
cashOutCount: 5e18,
|
|
@@ -295,7 +293,6 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
295
293
|
)
|
|
296
294
|
);
|
|
297
295
|
_store.previewCashOutFrom({
|
|
298
|
-
terminal: address(this),
|
|
299
296
|
holder: address(this),
|
|
300
297
|
projectId: _projectId,
|
|
301
298
|
cashOutCount: _excessiveCashOutCount,
|
|
@@ -368,7 +365,6 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
368
365
|
);
|
|
369
366
|
|
|
370
367
|
(, uint256 reclaimAmount,,) = _store.previewCashOutFrom({
|
|
371
|
-
terminal: address(this),
|
|
372
368
|
holder: address(this),
|
|
373
369
|
projectId: _projectId,
|
|
374
370
|
cashOutCount: 5e18,
|
|
@@ -380,4 +376,100 @@ contract TestPreviewCashOutFor_Local is JBTerminalStoreSetup {
|
|
|
380
376
|
|
|
381
377
|
assertEq(reclaimAmount, 0);
|
|
382
378
|
}
|
|
379
|
+
|
|
380
|
+
function test_WithDataHookAndZeroAmountNoopSpec() external {
|
|
381
|
+
_setBalance(address(this), _balance);
|
|
382
|
+
_mockUseTotalSurplus();
|
|
383
|
+
|
|
384
|
+
JBRulesetMetadata memory _metadata = JBRulesetMetadata({
|
|
385
|
+
reservedPercent: 0,
|
|
386
|
+
cashOutTaxRate: 0,
|
|
387
|
+
baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
388
|
+
pausePay: false,
|
|
389
|
+
pauseCreditTransfers: false,
|
|
390
|
+
allowOwnerMinting: false,
|
|
391
|
+
allowSetCustomToken: false,
|
|
392
|
+
allowTerminalMigration: false,
|
|
393
|
+
allowSetTerminals: false,
|
|
394
|
+
ownerMustSendPayouts: false,
|
|
395
|
+
allowSetController: false,
|
|
396
|
+
allowAddAccountingContext: true,
|
|
397
|
+
allowAddPriceFeed: false,
|
|
398
|
+
holdFees: false,
|
|
399
|
+
useTotalSurplusForCashOuts: true,
|
|
400
|
+
useDataHookForPay: false,
|
|
401
|
+
useDataHookForCashOut: true,
|
|
402
|
+
dataHook: address(_dataHook),
|
|
403
|
+
metadata: 0
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
uint256 _packedMetadata = JBRulesetMetadataResolver.packRulesetMetadata(_metadata);
|
|
407
|
+
|
|
408
|
+
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
409
|
+
cycleNumber: uint48(block.timestamp),
|
|
410
|
+
id: uint48(block.timestamp),
|
|
411
|
+
basedOnId: 0,
|
|
412
|
+
start: uint48(block.timestamp),
|
|
413
|
+
duration: uint32(block.timestamp + 1000),
|
|
414
|
+
weight: 1e18,
|
|
415
|
+
weightCutPercent: 0,
|
|
416
|
+
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
417
|
+
metadata: _packedMetadata
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
JBAccountingContext memory _accountingContext =
|
|
421
|
+
JBAccountingContext({token: address(_token), decimals: uint8(_decimals), currency: _currency});
|
|
422
|
+
|
|
423
|
+
JBBeforeCashOutRecordedContext memory _context = JBBeforeCashOutRecordedContext({
|
|
424
|
+
terminal: address(this),
|
|
425
|
+
holder: address(this),
|
|
426
|
+
projectId: _projectId,
|
|
427
|
+
rulesetId: uint48(block.timestamp),
|
|
428
|
+
cashOutCount: 10e18,
|
|
429
|
+
totalSupply: _totalSupply,
|
|
430
|
+
surplus: JBTokenAmount({
|
|
431
|
+
token: _accountingContext.token,
|
|
432
|
+
value: 3e18,
|
|
433
|
+
decimals: _accountingContext.decimals,
|
|
434
|
+
currency: _accountingContext.currency
|
|
435
|
+
}),
|
|
436
|
+
useTotalSurplus: true,
|
|
437
|
+
cashOutTaxRate: 0,
|
|
438
|
+
beneficiaryIsFeeless: false,
|
|
439
|
+
metadata: ""
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
JBCashOutHookSpecification[] memory _spec = new JBCashOutHookSpecification[](1);
|
|
443
|
+
_spec[0] = JBCashOutHookSpecification({hook: _cashOutHook, noop: true, amount: 0, metadata: "info"});
|
|
444
|
+
|
|
445
|
+
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
446
|
+
mockExpect(address(directory), abi.encodeCall(IJBDirectory.controllerOf, (_projectId)), abi.encode(_controller));
|
|
447
|
+
mockExpect(
|
|
448
|
+
address(_controller),
|
|
449
|
+
abi.encodeCall(IJBController.totalTokenSupplyWithReservedTokensOf, (_projectId)),
|
|
450
|
+
abi.encode(_totalSupply)
|
|
451
|
+
);
|
|
452
|
+
mockExpect(
|
|
453
|
+
address(_dataHook),
|
|
454
|
+
abi.encodeCall(IJBRulesetDataHook.beforeCashOutRecordedWith, (_context)),
|
|
455
|
+
abi.encode(0, 10e18, _totalSupply, _spec)
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
(, uint256 reclaimAmount, uint256 cashOutTaxRate, JBCashOutHookSpecification[] memory hookSpecifications) = _store.previewCashOutFrom({
|
|
459
|
+
holder: address(this),
|
|
460
|
+
projectId: _projectId,
|
|
461
|
+
cashOutCount: 10e18,
|
|
462
|
+
accountingContext: _accountingContext,
|
|
463
|
+
balanceAccountingContexts: new JBAccountingContext[](0),
|
|
464
|
+
beneficiaryIsFeeless: false,
|
|
465
|
+
metadata: ""
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
assertEq(reclaimAmount, mulDiv(3e18, 10e18, _totalSupply));
|
|
469
|
+
assertEq(cashOutTaxRate, 0);
|
|
470
|
+
assertEq(hookSpecifications.length, 1);
|
|
471
|
+
assertEq(hookSpecifications[0].amount, 0);
|
|
472
|
+
assertEq(hookSpecifications[0].noop, true);
|
|
473
|
+
assertEq(hookSpecifications[0].metadata, bytes("info"));
|
|
474
|
+
}
|
|
383
475
|
}
|
|
@@ -60,13 +60,9 @@ 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);
|
|
63
64
|
_store.previewPayFrom({
|
|
64
|
-
|
|
65
|
-
payer: address(this),
|
|
66
|
-
amount: _tokenAmount,
|
|
67
|
-
projectId: _projectId,
|
|
68
|
-
beneficiary: address(this),
|
|
69
|
-
metadata: ""
|
|
65
|
+
payer: address(this), amount: _tokenAmount, projectId: _projectId, beneficiary: address(this), metadata: ""
|
|
70
66
|
});
|
|
71
67
|
}
|
|
72
68
|
|
|
@@ -116,13 +112,9 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
116
112
|
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
117
113
|
|
|
118
114
|
vm.expectRevert(JBTerminalStore.JBTerminalStore_RulesetPaymentPaused.selector);
|
|
115
|
+
vm.prank(_terminal);
|
|
119
116
|
_store.previewPayFrom({
|
|
120
|
-
|
|
121
|
-
payer: address(this),
|
|
122
|
-
amount: _tokenAmount,
|
|
123
|
-
projectId: _projectId,
|
|
124
|
-
beneficiary: address(this),
|
|
125
|
-
metadata: ""
|
|
117
|
+
payer: address(this), amount: _tokenAmount, projectId: _projectId, beneficiary: address(this), metadata: ""
|
|
126
118
|
});
|
|
127
119
|
}
|
|
128
120
|
|
|
@@ -173,12 +165,7 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
173
165
|
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
174
166
|
|
|
175
167
|
(, uint256 previewTokenCount, JBPayHookSpecification[] memory previewSpecs) = _store.previewPayFrom({
|
|
176
|
-
|
|
177
|
-
payer: address(this),
|
|
178
|
-
amount: _tokenAmount,
|
|
179
|
-
projectId: _projectId,
|
|
180
|
-
beneficiary: address(this),
|
|
181
|
-
metadata: ""
|
|
168
|
+
payer: address(this), amount: _tokenAmount, projectId: _projectId, beneficiary: address(this), metadata: ""
|
|
182
169
|
});
|
|
183
170
|
|
|
184
171
|
// Mock for record call
|
|
@@ -236,7 +223,7 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
236
223
|
});
|
|
237
224
|
|
|
238
225
|
JBPayHookSpecification[] memory _spec = new JBPayHookSpecification[](1);
|
|
239
|
-
_spec[0] = JBPayHookSpecification({hook: _payHook, amount: _defaultValue / 2, metadata: ""});
|
|
226
|
+
_spec[0] = JBPayHookSpecification({hook: _payHook, noop: false, amount: _defaultValue / 2, metadata: ""});
|
|
240
227
|
|
|
241
228
|
// The data hook context will use the terminal address passed to preview / msg.sender for record.
|
|
242
229
|
// Since we call both from address(this), they match.
|
|
@@ -261,12 +248,7 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
261
248
|
);
|
|
262
249
|
|
|
263
250
|
(, uint256 previewTokenCount, JBPayHookSpecification[] memory previewSpecs) = _store.previewPayFrom({
|
|
264
|
-
|
|
265
|
-
payer: address(this),
|
|
266
|
-
amount: _tokenAmount,
|
|
267
|
-
projectId: _projectId,
|
|
268
|
-
beneficiary: address(this),
|
|
269
|
-
metadata: ""
|
|
251
|
+
payer: address(this), amount: _tokenAmount, projectId: _projectId, beneficiary: address(this), metadata: ""
|
|
270
252
|
});
|
|
271
253
|
|
|
272
254
|
// Mock for record call
|
|
@@ -333,13 +315,9 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
333
315
|
|
|
334
316
|
uint256 balanceBefore = _store.balanceOf(_terminal, _projectId, address(_token));
|
|
335
317
|
|
|
318
|
+
vm.prank(_terminal);
|
|
336
319
|
_store.previewPayFrom({
|
|
337
|
-
|
|
338
|
-
payer: address(this),
|
|
339
|
-
amount: _tokenAmount,
|
|
340
|
-
projectId: _projectId,
|
|
341
|
-
beneficiary: address(this),
|
|
342
|
-
metadata: ""
|
|
320
|
+
payer: address(this), amount: _tokenAmount, projectId: _projectId, beneficiary: address(this), metadata: ""
|
|
343
321
|
});
|
|
344
322
|
|
|
345
323
|
uint256 balanceAfter = _store.balanceOf(_terminal, _projectId, address(_token));
|
|
@@ -401,15 +379,86 @@ contract TestPreviewPayFrom_Local is JBTerminalStoreSetup {
|
|
|
401
379
|
|
|
402
380
|
uint256 expectedCount = mulDiv(_defaultValue, 1e18, 2e18);
|
|
403
381
|
|
|
382
|
+
vm.prank(_terminal);
|
|
404
383
|
(, uint256 tokenCount,) = _store.previewPayFrom({
|
|
384
|
+
payer: address(this), amount: _tokenAmount, projectId: _projectId, beneficiary: address(this), metadata: ""
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
assertEq(tokenCount, expectedCount);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function test_WithDataHookAndZeroAmountNoopSpec() external {
|
|
391
|
+
JBTokenAmount memory _tokenAmount = JBTokenAmount({
|
|
392
|
+
token: address(_token), value: _defaultValue, decimals: _defaultDecimals, currency: _currency
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
JBRulesetMetadata memory _metadata = JBRulesetMetadata({
|
|
396
|
+
reservedPercent: 0,
|
|
397
|
+
cashOutTaxRate: JBConstants.MAX_CASH_OUT_TAX_RATE,
|
|
398
|
+
baseCurrency: uint32(uint160(address(_token))),
|
|
399
|
+
pausePay: false,
|
|
400
|
+
pauseCreditTransfers: false,
|
|
401
|
+
allowOwnerMinting: false,
|
|
402
|
+
allowSetCustomToken: false,
|
|
403
|
+
allowTerminalMigration: false,
|
|
404
|
+
allowSetTerminals: false,
|
|
405
|
+
ownerMustSendPayouts: false,
|
|
406
|
+
allowSetController: false,
|
|
407
|
+
allowAddAccountingContext: true,
|
|
408
|
+
allowAddPriceFeed: false,
|
|
409
|
+
holdFees: false,
|
|
410
|
+
useTotalSurplusForCashOuts: false,
|
|
411
|
+
useDataHookForPay: true,
|
|
412
|
+
useDataHookForCashOut: false,
|
|
413
|
+
dataHook: address(_dataHook),
|
|
414
|
+
metadata: 0
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
uint256 _packedMetadata = JBRulesetMetadataResolver.packRulesetMetadata(_metadata);
|
|
418
|
+
|
|
419
|
+
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
420
|
+
cycleNumber: uint48(block.timestamp),
|
|
421
|
+
id: uint48(block.timestamp),
|
|
422
|
+
basedOnId: 0,
|
|
423
|
+
start: uint48(block.timestamp),
|
|
424
|
+
duration: uint32(block.timestamp + 1000),
|
|
425
|
+
weight: 1e18,
|
|
426
|
+
weightCutPercent: 0,
|
|
427
|
+
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
428
|
+
metadata: _packedMetadata
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
JBPayHookSpecification[] memory _spec = new JBPayHookSpecification[](1);
|
|
432
|
+
_spec[0] = JBPayHookSpecification({hook: _payHook, noop: true, amount: 0, metadata: "info"});
|
|
433
|
+
|
|
434
|
+
JBBeforePayRecordedContext memory _context = JBBeforePayRecordedContext({
|
|
405
435
|
terminal: _terminal,
|
|
406
436
|
payer: address(this),
|
|
407
437
|
amount: _tokenAmount,
|
|
408
438
|
projectId: _projectId,
|
|
439
|
+
rulesetId: uint48(block.timestamp),
|
|
409
440
|
beneficiary: address(this),
|
|
441
|
+
weight: _returnedRuleset.weight,
|
|
442
|
+
reservedPercent: _returnedRuleset.reservedPercent(),
|
|
410
443
|
metadata: ""
|
|
411
444
|
});
|
|
412
445
|
|
|
413
|
-
|
|
446
|
+
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
447
|
+
mockExpect(
|
|
448
|
+
address(_dataHook),
|
|
449
|
+
abi.encodeCall(IJBRulesetDataHook.beforePayRecordedWith, (_context)),
|
|
450
|
+
abi.encode(1e18 / 2, _spec)
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
vm.prank(_terminal);
|
|
454
|
+
(, uint256 tokenCount, JBPayHookSpecification[] memory hookSpecifications) = _store.previewPayFrom({
|
|
455
|
+
payer: address(this), amount: _tokenAmount, projectId: _projectId, beneficiary: address(this), metadata: ""
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
assertEq(tokenCount, 1e18 / 2);
|
|
459
|
+
assertEq(hookSpecifications.length, 1);
|
|
460
|
+
assertEq(hookSpecifications[0].amount, 0);
|
|
461
|
+
assertEq(hookSpecifications[0].noop, true);
|
|
462
|
+
assertEq(hookSpecifications[0].metadata, bytes("info"));
|
|
414
463
|
}
|
|
415
464
|
}
|
|
@@ -428,7 +428,7 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
|
|
|
428
428
|
|
|
429
429
|
// return data
|
|
430
430
|
JBCashOutHookSpecification[] memory _spec = new JBCashOutHookSpecification[](1);
|
|
431
|
-
_spec[0] = JBCashOutHookSpecification({hook: _cashOutHook, amount: 0, metadata: ""});
|
|
431
|
+
_spec[0] = JBCashOutHookSpecification({hook: _cashOutHook, noop: false, amount: 0, metadata: ""});
|
|
432
432
|
|
|
433
433
|
// mock call to data hook beforeCashOutRecordedWith
|
|
434
434
|
mockExpect(
|
|
@@ -541,7 +541,7 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
|
|
|
541
541
|
|
|
542
542
|
// return data
|
|
543
543
|
JBCashOutHookSpecification[] memory _spec = new JBCashOutHookSpecification[](1);
|
|
544
|
-
_spec[0] = JBCashOutHookSpecification({hook: _cashOutHook, amount: 0, metadata: ""});
|
|
544
|
+
_spec[0] = JBCashOutHookSpecification({hook: _cashOutHook, noop: false, amount: 0, metadata: ""});
|
|
545
545
|
|
|
546
546
|
// The mock will only match if the context has beneficiaryIsFeeless=true.
|
|
547
547
|
mockExpect(
|
|
@@ -563,6 +563,117 @@ contract TestRecordCashOutsFor_Local is JBTerminalStoreSetup {
|
|
|
563
563
|
assertEq(expectedCashOuts, reclaimed);
|
|
564
564
|
}
|
|
565
565
|
|
|
566
|
+
function test_GivenTheHookReturnsANoopSpecWithAmount()
|
|
567
|
+
external
|
|
568
|
+
whenCurrentRulesetUseTotalSurplusForCashOutsEqTrueWithHook
|
|
569
|
+
{
|
|
570
|
+
mockExpect(
|
|
571
|
+
address(_controller),
|
|
572
|
+
abi.encodeCall(IJBController.totalTokenSupplyWithReservedTokensOf, (_projectId)),
|
|
573
|
+
abi.encode(_totalSupply)
|
|
574
|
+
);
|
|
575
|
+
|
|
576
|
+
JBAccountingContext memory _accountingContexts =
|
|
577
|
+
JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
|
|
578
|
+
JBAccountingContext[] memory _balanceContexts = new JBAccountingContext[](1);
|
|
579
|
+
_balanceContexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
|
|
580
|
+
|
|
581
|
+
JBBeforeCashOutRecordedContext memory _context = JBBeforeCashOutRecordedContext({
|
|
582
|
+
terminal: address(this),
|
|
583
|
+
holder: address(this),
|
|
584
|
+
projectId: _projectId,
|
|
585
|
+
rulesetId: uint48(block.timestamp),
|
|
586
|
+
cashOutCount: 1e18,
|
|
587
|
+
totalSupply: _totalSupply,
|
|
588
|
+
surplus: JBTokenAmount({
|
|
589
|
+
token: _accountingContexts.token,
|
|
590
|
+
value: 3e18,
|
|
591
|
+
decimals: _accountingContexts.decimals,
|
|
592
|
+
currency: _accountingContexts.currency
|
|
593
|
+
}),
|
|
594
|
+
useTotalSurplus: true,
|
|
595
|
+
cashOutTaxRate: 0,
|
|
596
|
+
beneficiaryIsFeeless: false,
|
|
597
|
+
metadata: ""
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
JBCashOutHookSpecification[] memory _spec = new JBCashOutHookSpecification[](1);
|
|
601
|
+
_spec[0] = JBCashOutHookSpecification({hook: _cashOutHook, noop: true, amount: 1, metadata: ""});
|
|
602
|
+
|
|
603
|
+
mockExpect(
|
|
604
|
+
address(_dataHook),
|
|
605
|
+
abi.encodeCall(IJBRulesetDataHook.beforeCashOutRecordedWith, (_context)),
|
|
606
|
+
abi.encode(0, 1e18, _totalSupply, _spec)
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
vm.expectRevert(abi.encodeWithSelector(JBTerminalStore.JBTerminalStore_NoopHookSpecHasAmount.selector, 1));
|
|
610
|
+
_store.recordCashOutFor({
|
|
611
|
+
holder: address(this),
|
|
612
|
+
projectId: _projectId,
|
|
613
|
+
cashOutCount: 1e18,
|
|
614
|
+
accountingContext: _accountingContexts,
|
|
615
|
+
balanceAccountingContexts: _balanceContexts,
|
|
616
|
+
beneficiaryIsFeeless: false,
|
|
617
|
+
metadata: ""
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function test_GivenALaterHookReturnsANoopSpecWithAmount()
|
|
622
|
+
external
|
|
623
|
+
whenCurrentRulesetUseTotalSurplusForCashOutsEqTrueWithHook
|
|
624
|
+
{
|
|
625
|
+
mockExpect(
|
|
626
|
+
address(_controller),
|
|
627
|
+
abi.encodeCall(IJBController.totalTokenSupplyWithReservedTokensOf, (_projectId)),
|
|
628
|
+
abi.encode(_totalSupply)
|
|
629
|
+
);
|
|
630
|
+
|
|
631
|
+
JBAccountingContext memory _accountingContexts =
|
|
632
|
+
JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
|
|
633
|
+
JBAccountingContext[] memory _balanceContexts = new JBAccountingContext[](1);
|
|
634
|
+
_balanceContexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
|
|
635
|
+
|
|
636
|
+
JBBeforeCashOutRecordedContext memory _context = JBBeforeCashOutRecordedContext({
|
|
637
|
+
terminal: address(this),
|
|
638
|
+
holder: address(this),
|
|
639
|
+
projectId: _projectId,
|
|
640
|
+
rulesetId: uint48(block.timestamp),
|
|
641
|
+
cashOutCount: 1e18,
|
|
642
|
+
totalSupply: _totalSupply,
|
|
643
|
+
surplus: JBTokenAmount({
|
|
644
|
+
token: _accountingContexts.token,
|
|
645
|
+
value: 3e18,
|
|
646
|
+
decimals: _accountingContexts.decimals,
|
|
647
|
+
currency: _accountingContexts.currency
|
|
648
|
+
}),
|
|
649
|
+
useTotalSurplus: true,
|
|
650
|
+
cashOutTaxRate: 0,
|
|
651
|
+
beneficiaryIsFeeless: false,
|
|
652
|
+
metadata: ""
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
JBCashOutHookSpecification[] memory _spec = new JBCashOutHookSpecification[](2);
|
|
656
|
+
_spec[0] = JBCashOutHookSpecification({hook: _cashOutHook, noop: false, amount: 0, metadata: ""});
|
|
657
|
+
_spec[1] = JBCashOutHookSpecification({hook: _cashOutHook, noop: true, amount: 1, metadata: ""});
|
|
658
|
+
|
|
659
|
+
mockExpect(
|
|
660
|
+
address(_dataHook),
|
|
661
|
+
abi.encodeCall(IJBRulesetDataHook.beforeCashOutRecordedWith, (_context)),
|
|
662
|
+
abi.encode(0, 1e18, _totalSupply, _spec)
|
|
663
|
+
);
|
|
664
|
+
|
|
665
|
+
vm.expectRevert(abi.encodeWithSelector(JBTerminalStore.JBTerminalStore_NoopHookSpecHasAmount.selector, 1));
|
|
666
|
+
_store.recordCashOutFor({
|
|
667
|
+
holder: address(this),
|
|
668
|
+
projectId: _projectId,
|
|
669
|
+
cashOutCount: 1e18,
|
|
670
|
+
accountingContext: _accountingContexts,
|
|
671
|
+
balanceAccountingContexts: _balanceContexts,
|
|
672
|
+
beneficiaryIsFeeless: false,
|
|
673
|
+
metadata: ""
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
|
|
566
677
|
// Probably unnecessary even though it may give us a bit of cov %.. skipping for now
|
|
567
678
|
/* function test_WhenTheCurrentRulesetUseTotalSurplusForCashOutsEqFalse() external {
|
|
568
679
|
// it will use the standard surplus calculation
|