@bananapus/core-v6 0.0.17 → 0.0.19
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/CHANGE_LOG.md +53 -13
- package/SKILLS.md +6 -0
- package/USER_JOURNEYS.md +4 -0
- package/package.json +1 -1
- package/src/JBTerminalStore.sol +357 -171
- package/src/interfaces/IJBTerminalStore.sol +70 -0
- package/test/fork/TestSequencerPriceFeedFork.sol +168 -0
- package/test/units/static/JBTerminalStore/TestCurrentReclaimableSurplusOf.sol +215 -0
- package/test/units/static/JBTerminalStore/TestPreviewCashOutFrom.sol +383 -0
- package/test/units/static/JBTerminalStore/TestPreviewPayFrom.sol +415 -0
- package/docs/book.css +0 -13
- package/docs/book.toml +0 -12
- package/docs/solidity.min.js +0 -74
- package/docs/src/README.md +0 -703
- package/docs/src/SUMMARY.md +0 -94
- package/docs/src/src/JBChainlinkV3PriceFeed.sol/contract.JBChainlinkV3PriceFeed.md +0 -83
- package/docs/src/src/JBChainlinkV3SequencerPriceFeed.sol/contract.JBChainlinkV3SequencerPriceFeed.md +0 -88
- package/docs/src/src/JBController.sol/contract.JBController.md +0 -1121
- package/docs/src/src/JBDeadline.sol/contract.JBDeadline.md +0 -84
- package/docs/src/src/JBDirectory.sol/contract.JBDirectory.md +0 -294
- package/docs/src/src/JBERC20.sol/contract.JBERC20.md +0 -190
- package/docs/src/src/JBFeelessAddresses.sol/contract.JBFeelessAddresses.md +0 -80
- package/docs/src/src/JBFundAccessLimits.sol/contract.JBFundAccessLimits.md +0 -253
- package/docs/src/src/JBMultiTerminal.sol/contract.JBMultiTerminal.md +0 -1472
- package/docs/src/src/JBPermissions.sol/contract.JBPermissions.md +0 -199
- package/docs/src/src/JBPrices.sol/contract.JBPrices.md +0 -154
- package/docs/src/src/JBProjects.sol/contract.JBProjects.md +0 -131
- package/docs/src/src/JBRulesets.sol/contract.JBRulesets.md +0 -677
- package/docs/src/src/JBSplits.sol/contract.JBSplits.md +0 -237
- package/docs/src/src/JBTerminalStore.sol/contract.JBTerminalStore.md +0 -591
- package/docs/src/src/JBTokens.sol/contract.JBTokens.md +0 -353
- package/docs/src/src/README.md +0 -25
- package/docs/src/src/abstract/JBControlled.sol/abstract.JBControlled.md +0 -64
- package/docs/src/src/abstract/JBPermissioned.sol/abstract.JBPermissioned.md +0 -84
- package/docs/src/src/abstract/README.md +0 -5
- package/docs/src/src/enums/JBApprovalStatus.sol/enum.JBApprovalStatus.md +0 -17
- package/docs/src/src/enums/README.md +0 -4
- package/docs/src/src/interfaces/IJBCashOutHook.sol/interface.IJBCashOutHook.md +0 -29
- package/docs/src/src/interfaces/IJBCashOutTerminal.sol/interface.IJBCashOutTerminal.md +0 -57
- package/docs/src/src/interfaces/IJBControlled.sol/interface.IJBControlled.md +0 -12
- package/docs/src/src/interfaces/IJBController.sol/interface.IJBController.md +0 -334
- package/docs/src/src/interfaces/IJBDirectory.sol/interface.IJBDirectory.md +0 -108
- package/docs/src/src/interfaces/IJBDirectoryAccessControl.sol/interface.IJBDirectoryAccessControl.md +0 -19
- package/docs/src/src/interfaces/IJBFeeTerminal.sol/interface.IJBFeeTerminal.md +0 -91
- package/docs/src/src/interfaces/IJBFeelessAddresses.sol/interface.IJBFeelessAddresses.md +0 -26
- package/docs/src/src/interfaces/IJBFundAccessLimits.sol/interface.IJBFundAccessLimits.md +0 -88
- package/docs/src/src/interfaces/IJBMigratable.sol/interface.IJBMigratable.md +0 -29
- package/docs/src/src/interfaces/IJBMultiTerminal.sol/interface.IJBMultiTerminal.md +0 -50
- package/docs/src/src/interfaces/IJBPayHook.sol/interface.IJBPayHook.md +0 -28
- package/docs/src/src/interfaces/IJBPayoutTerminal.sol/interface.IJBPayoutTerminal.md +0 -105
- package/docs/src/src/interfaces/IJBPermissioned.sol/interface.IJBPermissioned.md +0 -12
- package/docs/src/src/interfaces/IJBPermissions.sol/interface.IJBPermissions.md +0 -74
- package/docs/src/src/interfaces/IJBPermitTerminal.sol/interface.IJBPermitTerminal.md +0 -15
- package/docs/src/src/interfaces/IJBPriceFeed.sol/interface.IJBPriceFeed.md +0 -12
- package/docs/src/src/interfaces/IJBPrices.sol/interface.IJBPrices.md +0 -74
- package/docs/src/src/interfaces/IJBProjectUriRegistry.sol/interface.IJBProjectUriRegistry.md +0 -19
- package/docs/src/src/interfaces/IJBProjects.sol/interface.IJBProjects.md +0 -49
- package/docs/src/src/interfaces/IJBRulesetApprovalHook.sol/interface.IJBRulesetApprovalHook.md +0 -35
- package/docs/src/src/interfaces/IJBRulesetDataHook.sol/interface.IJBRulesetDataHook.md +0 -97
- package/docs/src/src/interfaces/IJBRulesets.sol/interface.IJBRulesets.md +0 -165
- package/docs/src/src/interfaces/IJBSplitHook.sol/interface.IJBSplitHook.md +0 -31
- package/docs/src/src/interfaces/IJBSplits.sol/interface.IJBSplits.md +0 -35
- package/docs/src/src/interfaces/IJBTerminal.sol/interface.IJBTerminal.md +0 -141
- package/docs/src/src/interfaces/IJBTerminalStore.sol/interface.IJBTerminalStore.md +0 -198
- package/docs/src/src/interfaces/IJBToken.sol/interface.IJBToken.md +0 -54
- package/docs/src/src/interfaces/IJBTokenUriResolver.sol/interface.IJBTokenUriResolver.md +0 -12
- package/docs/src/src/interfaces/IJBTokens.sol/interface.IJBTokens.md +0 -151
- package/docs/src/src/interfaces/README.md +0 -33
- package/docs/src/src/libraries/JBCashOuts.sol/library.JBCashOuts.md +0 -40
- package/docs/src/src/libraries/JBConstants.sol/library.JBConstants.md +0 -52
- package/docs/src/src/libraries/JBCurrencyIds.sol/library.JBCurrencyIds.md +0 -19
- package/docs/src/src/libraries/JBFees.sol/library.JBFees.md +0 -52
- package/docs/src/src/libraries/JBFixedPointNumber.sol/library.JBFixedPointNumber.md +0 -12
- package/docs/src/src/libraries/JBMetadataResolver.sol/library.JBMetadataResolver.md +0 -242
- package/docs/src/src/libraries/JBRulesetMetadataResolver.sol/library.JBRulesetMetadataResolver.md +0 -180
- package/docs/src/src/libraries/JBSplitGroupIds.sol/library.JBSplitGroupIds.md +0 -14
- package/docs/src/src/libraries/JBSurplus.sol/library.JBSurplus.md +0 -44
- package/docs/src/src/libraries/README.md +0 -12
- package/docs/src/src/periphery/JBDeadline1Day.sol/contract.JBDeadline1Day.md +0 -15
- package/docs/src/src/periphery/JBDeadline3Days.sol/contract.JBDeadline3Days.md +0 -15
- package/docs/src/src/periphery/JBDeadline3Hours.sol/contract.JBDeadline3Hours.md +0 -15
- package/docs/src/src/periphery/JBDeadline7Days.sol/contract.JBDeadline7Days.md +0 -15
- package/docs/src/src/periphery/JBMatchingPriceFeed.sol/contract.JBMatchingPriceFeed.md +0 -22
- package/docs/src/src/periphery/README.md +0 -8
- package/docs/src/src/structs/JBAccountingContext.sol/struct.JBAccountingContext.md +0 -20
- package/docs/src/src/structs/JBAfterCashOutRecordedContext.sol/struct.JBAfterCashOutRecordedContext.md +0 -43
- package/docs/src/src/structs/JBAfterPayRecordedContext.sol/struct.JBAfterPayRecordedContext.md +0 -42
- package/docs/src/src/structs/JBBeforeCashOutRecordedContext.sol/struct.JBBeforeCashOutRecordedContext.md +0 -45
- package/docs/src/src/structs/JBBeforePayRecordedContext.sol/struct.JBBeforePayRecordedContext.md +0 -41
- package/docs/src/src/structs/JBCashOutHookSpecification.sol/struct.JBCashOutHookSpecification.md +0 -22
- package/docs/src/src/structs/JBCurrencyAmount.sol/struct.JBCurrencyAmount.md +0 -17
- package/docs/src/src/structs/JBFee.sol/struct.JBFee.md +0 -20
- package/docs/src/src/structs/JBFundAccessLimitGroup.sol/struct.JBFundAccessLimitGroup.md +0 -39
- package/docs/src/src/structs/JBPayHookSpecification.sol/struct.JBPayHookSpecification.md +0 -22
- package/docs/src/src/structs/JBPermissionsData.sol/struct.JBPermissionsData.md +0 -21
- package/docs/src/src/structs/JBRuleset.sol/struct.JBRuleset.md +0 -55
- package/docs/src/src/structs/JBRulesetConfig.sol/struct.JBRulesetConfig.md +0 -51
- package/docs/src/src/structs/JBRulesetMetadata.sol/struct.JBRulesetMetadata.md +0 -79
- package/docs/src/src/structs/JBRulesetWeightCache.sol/struct.JBRulesetWeightCache.md +0 -16
- package/docs/src/src/structs/JBRulesetWithMetadata.sol/struct.JBRulesetWithMetadata.md +0 -16
- package/docs/src/src/structs/JBSingleAllowance.sol/struct.JBSingleAllowance.md +0 -26
- package/docs/src/src/structs/JBSplit.sol/struct.JBSplit.md +0 -49
- package/docs/src/src/structs/JBSplitGroup.sol/struct.JBSplitGroup.md +0 -17
- package/docs/src/src/structs/JBSplitHookContext.sol/struct.JBSplitHookContext.md +0 -29
- package/docs/src/src/structs/JBTerminalConfig.sol/struct.JBTerminalConfig.md +0 -16
- package/docs/src/src/structs/JBTokenAmount.sol/struct.JBTokenAmount.md +0 -23
- package/docs/src/src/structs/README.md +0 -25
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {Test} from "forge-std/Test.sol";
|
|
5
|
+
|
|
6
|
+
import {AggregatorV2V3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV2V3Interface.sol";
|
|
7
|
+
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
|
|
8
|
+
|
|
9
|
+
import {JBChainlinkV3SequencerPriceFeed} from "../../src/JBChainlinkV3SequencerPriceFeed.sol";
|
|
10
|
+
|
|
11
|
+
/// @notice Fork tests for JBChainlinkV3SequencerPriceFeed against the live Arbitrum sequencer uptime feed and
|
|
12
|
+
/// ETH/USD Chainlink oracle.
|
|
13
|
+
contract TestSequencerPriceFeedFork is Test {
|
|
14
|
+
// Chainlink feed addresses (Arbitrum mainnet).
|
|
15
|
+
address constant ARB_ETH_USD_FEED = 0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612;
|
|
16
|
+
address constant ARB_SEQUENCER_FEED = 0xFdB631F5EE196F0ed6FAa767959853A9F217697D;
|
|
17
|
+
|
|
18
|
+
// Staleness threshold (1 hour).
|
|
19
|
+
uint256 constant THRESHOLD = 3600;
|
|
20
|
+
|
|
21
|
+
// Grace period after sequencer restart (1 hour).
|
|
22
|
+
uint256 constant GRACE_PERIOD = 3600;
|
|
23
|
+
|
|
24
|
+
// Pinned block for reproducibility (sequencer is up at this block).
|
|
25
|
+
uint256 constant FORK_BLOCK = 300_000_000;
|
|
26
|
+
|
|
27
|
+
JBChainlinkV3SequencerPriceFeed feed;
|
|
28
|
+
|
|
29
|
+
function setUp() public {
|
|
30
|
+
string memory rpc = vm.envOr("RPC_ARBITRUM_MAINNET", string(""));
|
|
31
|
+
if (bytes(rpc).length == 0) {
|
|
32
|
+
// Skip all tests if no Arbitrum RPC is configured.
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
vm.createSelectFork(rpc, FORK_BLOCK);
|
|
37
|
+
|
|
38
|
+
feed = new JBChainlinkV3SequencerPriceFeed(
|
|
39
|
+
AggregatorV3Interface(ARB_ETH_USD_FEED),
|
|
40
|
+
THRESHOLD,
|
|
41
|
+
AggregatorV2V3Interface(ARB_SEQUENCER_FEED),
|
|
42
|
+
GRACE_PERIOD
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ------------------------------------------------------------------
|
|
47
|
+
// Helpers
|
|
48
|
+
// ------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
modifier skipIfNoRpc() {
|
|
51
|
+
if (address(feed) == address(0)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
_;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ------------------------------------------------------------------
|
|
58
|
+
// 1. Normal operation — valid price returned
|
|
59
|
+
// ------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
/// @notice Under normal conditions (sequencer up, grace period elapsed), currentUnitPrice returns a sane price.
|
|
62
|
+
function test_normalOperation_returnsValidPrice() public skipIfNoRpc {
|
|
63
|
+
uint256 price18 = feed.currentUnitPrice(18);
|
|
64
|
+
|
|
65
|
+
// ETH price should be between $500 and $50,000.
|
|
66
|
+
assertGt(price18, 500e18, "ETH price too low");
|
|
67
|
+
assertLt(price18, 50_000e18, "ETH price too high");
|
|
68
|
+
|
|
69
|
+
// Cross-check against raw latestRoundData from the price feed.
|
|
70
|
+
(, int256 rawPrice,,,) = AggregatorV3Interface(ARB_ETH_USD_FEED).latestRoundData();
|
|
71
|
+
uint256 feedDecimals = AggregatorV3Interface(ARB_ETH_USD_FEED).decimals();
|
|
72
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
73
|
+
uint256 expected18 = uint256(rawPrice) * 10 ** (18 - feedDecimals);
|
|
74
|
+
assertEq(price18, expected18, "Price mismatch vs raw feed");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ------------------------------------------------------------------
|
|
78
|
+
// 2. Sequencer down — reverts
|
|
79
|
+
// ------------------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
/// @notice When the sequencer feed reports answer=1 (down), currentUnitPrice reverts.
|
|
82
|
+
function test_sequencerDown_reverts() public skipIfNoRpc {
|
|
83
|
+
// Mock the sequencer feed to report answer=1 (down).
|
|
84
|
+
// latestRoundData() selector = 0xfeaf968c
|
|
85
|
+
vm.mockCall(
|
|
86
|
+
ARB_SEQUENCER_FEED,
|
|
87
|
+
abi.encodeWithSelector(AggregatorV3Interface.latestRoundData.selector),
|
|
88
|
+
abi.encode(
|
|
89
|
+
uint80(1), // roundId
|
|
90
|
+
int256(1), // answer = 1 → sequencer down
|
|
91
|
+
block.timestamp - GRACE_PERIOD - 100, // startedAt (irrelevant when answer=1)
|
|
92
|
+
block.timestamp, // updatedAt
|
|
93
|
+
uint80(1) // answeredInRound
|
|
94
|
+
)
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
vm.expectRevert(
|
|
98
|
+
abi.encodeWithSelector(
|
|
99
|
+
JBChainlinkV3SequencerPriceFeed.JBChainlinkV3SequencerPriceFeed_SequencerDownOrRestarting.selector,
|
|
100
|
+
block.timestamp,
|
|
101
|
+
GRACE_PERIOD,
|
|
102
|
+
block.timestamp - GRACE_PERIOD - 100
|
|
103
|
+
)
|
|
104
|
+
);
|
|
105
|
+
feed.currentUnitPrice(18);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ------------------------------------------------------------------
|
|
109
|
+
// 3. Grace period active — reverts
|
|
110
|
+
// ------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
/// @notice When the sequencer just came back up (within grace period), currentUnitPrice reverts.
|
|
113
|
+
function test_gracePeriodActive_reverts() public skipIfNoRpc {
|
|
114
|
+
// Mock the sequencer feed: answer=0 (up) but startedAt is 1 second ago (within grace period).
|
|
115
|
+
uint256 startedAt = block.timestamp - 1;
|
|
116
|
+
|
|
117
|
+
vm.mockCall(
|
|
118
|
+
ARB_SEQUENCER_FEED,
|
|
119
|
+
abi.encodeWithSelector(AggregatorV3Interface.latestRoundData.selector),
|
|
120
|
+
abi.encode(
|
|
121
|
+
uint80(1), // roundId
|
|
122
|
+
int256(0), // answer = 0 → sequencer up
|
|
123
|
+
startedAt, // startedAt = very recent
|
|
124
|
+
block.timestamp, // updatedAt
|
|
125
|
+
uint80(1) // answeredInRound
|
|
126
|
+
)
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
vm.expectRevert(
|
|
130
|
+
abi.encodeWithSelector(
|
|
131
|
+
JBChainlinkV3SequencerPriceFeed.JBChainlinkV3SequencerPriceFeed_SequencerDownOrRestarting.selector,
|
|
132
|
+
block.timestamp,
|
|
133
|
+
GRACE_PERIOD,
|
|
134
|
+
startedAt
|
|
135
|
+
)
|
|
136
|
+
);
|
|
137
|
+
feed.currentUnitPrice(18);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ------------------------------------------------------------------
|
|
141
|
+
// 4. Post-grace recovery — succeeds
|
|
142
|
+
// ------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
/// @notice After the grace period has elapsed, currentUnitPrice succeeds again.
|
|
145
|
+
function test_postGraceRecovery_succeeds() public skipIfNoRpc {
|
|
146
|
+
// Mock the sequencer feed: answer=0 (up), startedAt is well before the grace period ended.
|
|
147
|
+
uint256 startedAt = block.timestamp - GRACE_PERIOD - 100;
|
|
148
|
+
|
|
149
|
+
vm.mockCall(
|
|
150
|
+
ARB_SEQUENCER_FEED,
|
|
151
|
+
abi.encodeWithSelector(AggregatorV3Interface.latestRoundData.selector),
|
|
152
|
+
abi.encode(
|
|
153
|
+
uint80(1), // roundId
|
|
154
|
+
int256(0), // answer = 0 → sequencer up
|
|
155
|
+
startedAt, // startedAt = well in the past
|
|
156
|
+
block.timestamp, // updatedAt
|
|
157
|
+
uint80(1) // answeredInRound
|
|
158
|
+
)
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// The price feed itself is still the real Chainlink feed, so this should succeed.
|
|
162
|
+
uint256 price18 = feed.currentUnitPrice(18);
|
|
163
|
+
|
|
164
|
+
// Same sanity check: ETH price between $500 and $50,000.
|
|
165
|
+
assertGt(price18, 500e18, "ETH price too low after recovery");
|
|
166
|
+
assertLt(price18, 50_000e18, "ETH price too high after recovery");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -444,4 +444,219 @@ contract TestCurrentReclaimableSurplusOf_Local is JBTerminalStoreSetup {
|
|
|
444
444
|
uint256 reclaimable = _store.currentReclaimableSurplusOf(_projectId, _tokenCount, 1e18, 1e18);
|
|
445
445
|
assertEq(1e18, reclaimable);
|
|
446
446
|
}
|
|
447
|
+
|
|
448
|
+
function test_GivenTotalReclaimableWithSurplus() external whenProjectHasBalance {
|
|
449
|
+
// it will default to all terminals and all accounting contexts and return the reclaimable surplus
|
|
450
|
+
|
|
451
|
+
// setup calldata
|
|
452
|
+
JBAccountingContext[] memory _contexts = new JBAccountingContext[](1);
|
|
453
|
+
_contexts[0] = JBAccountingContext({token: address(_token), decimals: 18, currency: _currency});
|
|
454
|
+
|
|
455
|
+
JBRulesetMetadata memory _metadata = JBRulesetMetadata({
|
|
456
|
+
reservedPercent: 0,
|
|
457
|
+
cashOutTaxRate: JBConstants.MAX_CASH_OUT_TAX_RATE / 2,
|
|
458
|
+
baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
459
|
+
pausePay: false,
|
|
460
|
+
pauseCreditTransfers: false,
|
|
461
|
+
allowOwnerMinting: false,
|
|
462
|
+
allowSetCustomToken: false,
|
|
463
|
+
allowTerminalMigration: false,
|
|
464
|
+
allowSetTerminals: false,
|
|
465
|
+
ownerMustSendPayouts: false,
|
|
466
|
+
allowSetController: false,
|
|
467
|
+
allowAddAccountingContext: true,
|
|
468
|
+
allowAddPriceFeed: false,
|
|
469
|
+
holdFees: false,
|
|
470
|
+
useTotalSurplusForCashOuts: false,
|
|
471
|
+
useDataHookForPay: false,
|
|
472
|
+
useDataHookForCashOut: false,
|
|
473
|
+
dataHook: address(0),
|
|
474
|
+
metadata: 0
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
uint256 _packedMetadata = JBRulesetMetadataResolver.packRulesetMetadata(_metadata);
|
|
478
|
+
|
|
479
|
+
// JBRulesets return calldata
|
|
480
|
+
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
481
|
+
cycleNumber: uint48(block.timestamp),
|
|
482
|
+
id: uint48(block.timestamp),
|
|
483
|
+
basedOnId: 0,
|
|
484
|
+
start: uint48(block.timestamp),
|
|
485
|
+
duration: uint32(block.timestamp + 1000),
|
|
486
|
+
weight: 1e18,
|
|
487
|
+
weightCutPercent: 0,
|
|
488
|
+
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
489
|
+
metadata: _packedMetadata
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
// mock call to JBRulesets currentOf
|
|
493
|
+
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
494
|
+
|
|
495
|
+
// mock call to JBDirectory controllerOf
|
|
496
|
+
mockExpect(address(directory), abi.encodeCall(IJBDirectory.controllerOf, (_projectId)), abi.encode(_controller));
|
|
497
|
+
|
|
498
|
+
uint256 _supply = 1e19;
|
|
499
|
+
uint256 _surplus = 1e18;
|
|
500
|
+
uint256 _cashoutAmount = 1e18;
|
|
501
|
+
|
|
502
|
+
// mock JBDirectory terminalsOf to return the terminal
|
|
503
|
+
IJBTerminal[] memory _terminals = new IJBTerminal[](1);
|
|
504
|
+
_terminals[0] = _terminal;
|
|
505
|
+
mockExpect(address(directory), abi.encodeCall(IJBDirectory.terminalsOf, (_projectId)), abi.encode(_terminals));
|
|
506
|
+
|
|
507
|
+
// surplus call to the terminal (empty accounting contexts passed through)
|
|
508
|
+
JBAccountingContext[] memory _emptyContexts = new JBAccountingContext[](0);
|
|
509
|
+
mockExpect(
|
|
510
|
+
address(_terminal),
|
|
511
|
+
abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, _emptyContexts, 18, _currency)),
|
|
512
|
+
abi.encode(_surplus)
|
|
513
|
+
);
|
|
514
|
+
|
|
515
|
+
// mock JBController totalTokenSupplyWithReservedTokensOf
|
|
516
|
+
mockExpect(
|
|
517
|
+
address(_controller),
|
|
518
|
+
abi.encodeCall(IJBController.totalTokenSupplyWithReservedTokensOf, (_projectId)),
|
|
519
|
+
abi.encode(_supply)
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
// Call the new convenience function (no terminals, no accounting contexts).
|
|
523
|
+
uint256 reclaimable = _store.currentTotalReclaimableSurplusOf(_projectId, _cashoutAmount, 18, _currency);
|
|
524
|
+
|
|
525
|
+
// Should match the 6-param overload result.
|
|
526
|
+
uint256 assumed =
|
|
527
|
+
JBCashOuts.cashOutFrom(_surplus, _cashoutAmount, _supply, JBConstants.MAX_CASH_OUT_TAX_RATE / 2);
|
|
528
|
+
|
|
529
|
+
assertEq(assumed, reclaimable);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function test_GivenTotalReclaimableWithZeroSurplus() external {
|
|
533
|
+
// it will return zero when there is no surplus
|
|
534
|
+
|
|
535
|
+
JBAccountingContext[] memory _emptyContexts = new JBAccountingContext[](0);
|
|
536
|
+
|
|
537
|
+
// JBRulesets return calldata
|
|
538
|
+
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
539
|
+
cycleNumber: uint48(block.timestamp),
|
|
540
|
+
id: uint48(block.timestamp),
|
|
541
|
+
basedOnId: 0,
|
|
542
|
+
start: uint48(block.timestamp),
|
|
543
|
+
duration: uint32(block.timestamp + 1000),
|
|
544
|
+
weight: 1e18,
|
|
545
|
+
weightCutPercent: 0,
|
|
546
|
+
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
547
|
+
metadata: 0
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
// mock call to JBRulesets currentOf
|
|
551
|
+
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
552
|
+
|
|
553
|
+
// mock JBDirectory terminalsOf to return the terminal
|
|
554
|
+
IJBTerminal[] memory _terminals = new IJBTerminal[](1);
|
|
555
|
+
_terminals[0] = _terminal;
|
|
556
|
+
mockExpect(address(directory), abi.encodeCall(IJBDirectory.terminalsOf, (_projectId)), abi.encode(_terminals));
|
|
557
|
+
|
|
558
|
+
// mock current surplus as zero
|
|
559
|
+
mockExpect(
|
|
560
|
+
address(_terminal),
|
|
561
|
+
abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, _emptyContexts, 18, _currency)),
|
|
562
|
+
abi.encode(0)
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
uint256 reclaimable = _store.currentTotalReclaimableSurplusOf(_projectId, _tokenCount, 18, _currency);
|
|
566
|
+
assertEq(0, reclaimable);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function test_GivenTotalReclaimableMatchesSixParamOverload() external whenProjectHasBalance {
|
|
570
|
+
// it will produce the same result as calling the 6-param overload with empty arrays
|
|
571
|
+
|
|
572
|
+
JBAccountingContext[] memory _emptyContexts = new JBAccountingContext[](0);
|
|
573
|
+
|
|
574
|
+
JBRulesetMetadata memory _metadata = JBRulesetMetadata({
|
|
575
|
+
reservedPercent: 0,
|
|
576
|
+
cashOutTaxRate: JBConstants.MAX_CASH_OUT_TAX_RATE / 2,
|
|
577
|
+
baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
578
|
+
pausePay: false,
|
|
579
|
+
pauseCreditTransfers: false,
|
|
580
|
+
allowOwnerMinting: false,
|
|
581
|
+
allowSetCustomToken: false,
|
|
582
|
+
allowTerminalMigration: false,
|
|
583
|
+
allowSetTerminals: false,
|
|
584
|
+
ownerMustSendPayouts: false,
|
|
585
|
+
allowSetController: false,
|
|
586
|
+
allowAddAccountingContext: true,
|
|
587
|
+
allowAddPriceFeed: false,
|
|
588
|
+
holdFees: false,
|
|
589
|
+
useTotalSurplusForCashOuts: false,
|
|
590
|
+
useDataHookForPay: false,
|
|
591
|
+
useDataHookForCashOut: false,
|
|
592
|
+
dataHook: address(0),
|
|
593
|
+
metadata: 0
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
uint256 _packedMetadata = JBRulesetMetadataResolver.packRulesetMetadata(_metadata);
|
|
597
|
+
|
|
598
|
+
JBRuleset memory _returnedRuleset = JBRuleset({
|
|
599
|
+
cycleNumber: uint48(block.timestamp),
|
|
600
|
+
id: uint48(block.timestamp),
|
|
601
|
+
basedOnId: 0,
|
|
602
|
+
start: uint48(block.timestamp),
|
|
603
|
+
duration: uint32(block.timestamp + 1000),
|
|
604
|
+
weight: 1e18,
|
|
605
|
+
weightCutPercent: 0,
|
|
606
|
+
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
607
|
+
metadata: _packedMetadata
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
uint256 _supply = 1e19;
|
|
611
|
+
uint256 _surplus = 5e17;
|
|
612
|
+
uint256 _cashoutAmount = 1e18;
|
|
613
|
+
|
|
614
|
+
IJBTerminal[] memory _terminals = new IJBTerminal[](1);
|
|
615
|
+
_terminals[0] = _terminal;
|
|
616
|
+
|
|
617
|
+
// The new overload calls the 6-param via `this`, so JBRulesets.currentOf gets called twice.
|
|
618
|
+
// Mock it to return the same ruleset both times.
|
|
619
|
+
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
620
|
+
|
|
621
|
+
mockExpect(address(directory), abi.encodeCall(IJBDirectory.controllerOf, (_projectId)), abi.encode(_controller));
|
|
622
|
+
|
|
623
|
+
mockExpect(address(directory), abi.encodeCall(IJBDirectory.terminalsOf, (_projectId)), abi.encode(_terminals));
|
|
624
|
+
|
|
625
|
+
mockExpect(
|
|
626
|
+
address(_terminal),
|
|
627
|
+
abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, _emptyContexts, 18, _currency)),
|
|
628
|
+
abi.encode(_surplus)
|
|
629
|
+
);
|
|
630
|
+
|
|
631
|
+
mockExpect(
|
|
632
|
+
address(_controller),
|
|
633
|
+
abi.encodeCall(IJBController.totalTokenSupplyWithReservedTokensOf, (_projectId)),
|
|
634
|
+
abi.encode(_supply)
|
|
635
|
+
);
|
|
636
|
+
|
|
637
|
+
// Call the new convenience function.
|
|
638
|
+
uint256 reclaimableDefault = _store.currentTotalReclaimableSurplusOf(_projectId, _cashoutAmount, 18, _currency);
|
|
639
|
+
|
|
640
|
+
// Re-mock for the 6-param call (mocks are consumed).
|
|
641
|
+
mockExpect(address(rulesets), abi.encodeCall(IJBRulesets.currentOf, (_projectId)), abi.encode(_returnedRuleset));
|
|
642
|
+
mockExpect(address(directory), abi.encodeCall(IJBDirectory.controllerOf, (_projectId)), abi.encode(_controller));
|
|
643
|
+
mockExpect(address(directory), abi.encodeCall(IJBDirectory.terminalsOf, (_projectId)), abi.encode(_terminals));
|
|
644
|
+
mockExpect(
|
|
645
|
+
address(_terminal),
|
|
646
|
+
abi.encodeCall(IJBTerminal.currentSurplusOf, (_projectId, _emptyContexts, 18, _currency)),
|
|
647
|
+
abi.encode(_surplus)
|
|
648
|
+
);
|
|
649
|
+
mockExpect(
|
|
650
|
+
address(_controller),
|
|
651
|
+
abi.encodeCall(IJBController.totalTokenSupplyWithReservedTokensOf, (_projectId)),
|
|
652
|
+
abi.encode(_supply)
|
|
653
|
+
);
|
|
654
|
+
|
|
655
|
+
// Call the 6-param overload with empty arrays.
|
|
656
|
+
uint256 reclaimableExplicit = _store.currentReclaimableSurplusOf(
|
|
657
|
+
_projectId, _cashoutAmount, new IJBTerminal[](0), new JBAccountingContext[](0), 18, _currency
|
|
658
|
+
);
|
|
659
|
+
|
|
660
|
+
assertEq(reclaimableDefault, reclaimableExplicit);
|
|
661
|
+
}
|
|
447
662
|
}
|