@bananapus/core-v6 0.0.51 → 0.0.52
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/CHANGELOG.md +5 -0
- package/package.json +1 -1
- package/src/JBMultiTerminal.sol +46 -14
- package/src/interfaces/IJBFeeTerminal.sol +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -57,6 +57,9 @@ This file describes the verified change from `nana-core-v5` to the current `nana
|
|
|
57
57
|
- `IJBCashOutTerminal.previewCashOutFrom(...)` is new.
|
|
58
58
|
- `IJBCashOutTerminal.payAfterCashOutTokensOf(...)` is new.
|
|
59
59
|
- `IJBCashOutTerminal.addToBalanceAfterCashOutTokensOf(...)` is new.
|
|
60
|
+
- `IJBFeeTerminal.FEE()` is REMOVED. The terminal no longer re-exports the protocol fee constant; read
|
|
61
|
+
`JBConstants.FEE` directly. Off-chain integrators that previously called `terminal.FEE()` must switch to
|
|
62
|
+
reading the constant from `JBConstants`.
|
|
60
63
|
- `IJBTerminalStore.previewPayFrom(...)` and `previewCashOutFrom(...)` are new.
|
|
61
64
|
- `IJBTerminal.currentSurplusOf(...)` changed parameter shape.
|
|
62
65
|
- `JBRulesetMetadata` adds `pauseCrossProjectFeeFreeInflows` and narrows `metadata` from 14 to 13 bits.
|
|
@@ -96,6 +99,8 @@ This file describes the verified change from `nana-core-v5` to the current `nana
|
|
|
96
99
|
`HookAfterRecordCashOut` from the terminal address)
|
|
97
100
|
- Renamed functions
|
|
98
101
|
- `IJBController.addPriceFeed(...)` -> `addPriceFeedFor(...)`
|
|
102
|
+
- Removed functions
|
|
103
|
+
- `IJBFeeTerminal.FEE()` (read `JBConstants.FEE` directly)
|
|
99
104
|
- Changed function shapes
|
|
100
105
|
- `IJBTerminal.currentSurplusOf(...)`
|
|
101
106
|
- Added events
|
package/package.json
CHANGED
package/src/JBMultiTerminal.sol
CHANGED
|
@@ -81,16 +81,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
81
81
|
error JBMultiTerminal_TokenNotAccepted(address token);
|
|
82
82
|
error JBMultiTerminal_UnderMin(uint256 value, uint256 min);
|
|
83
83
|
|
|
84
|
-
//*********************************************************************//
|
|
85
|
-
// ------------------------- public constants ------------------------ //
|
|
86
|
-
//*********************************************************************//
|
|
87
|
-
|
|
88
|
-
/// @notice This terminal's fee (as a fraction out of `JBConstants.MAX_FEE`).
|
|
89
|
-
/// @dev Fees are charged on payouts to addresses and surplus allowance usage, as well as cash outs while the
|
|
90
|
-
/// cash out tax rate is less than 100%. Re-exports `JBConstants.FEE` so external callers can read it through
|
|
91
|
-
/// the `IJBFeeTerminal` interface.
|
|
92
|
-
uint256 public constant override FEE = JBConstants.FEE;
|
|
93
|
-
|
|
94
84
|
//*********************************************************************//
|
|
95
85
|
// ------------------------ internal constants ----------------------- //
|
|
96
86
|
//*********************************************************************//
|
|
@@ -260,7 +250,14 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
260
250
|
override
|
|
261
251
|
returns (uint256 reclaimAmount)
|
|
262
252
|
{
|
|
253
|
+
// Caller must hold (or be operator with) `CASH_OUT_TOKENS` permission on the source `holder`/`projectId`.
|
|
254
|
+
// Burning A's tokens is the load-bearing side effect — gating it stays at the same authority bar as the
|
|
255
|
+
// direct `cashOutTokensOf` entrypoint.
|
|
263
256
|
_requireCashOutPermissionFrom({holder: holder, projectId: projectId});
|
|
257
|
+
|
|
258
|
+
// Destination opt-out check: B's current ruleset can set `pauseCrossProjectFeeFreeInflows = true` to
|
|
259
|
+
// refuse cross-project fee-free credits. Without this gate, anyone holding A's tokens could push a
|
|
260
|
+
// deferred-fee credit onto `_feeFreeSurplusOf[B]` without B consenting.
|
|
264
261
|
_requireBeneficiaryAcceptsFeeFreeInflows(beneficiaryProjectId);
|
|
265
262
|
|
|
266
263
|
// Burn source-project tokens, run cashout-side hooks, take any hook fees, and cap source fee-free.
|
|
@@ -278,13 +275,19 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
278
275
|
// Nothing to route if the data hook returned zero reclaim.
|
|
279
276
|
if (reclaimAmount == 0) return 0;
|
|
280
277
|
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
// hardcodes `shouldReturnHeldFees: false` — this entrypoint cannot unlock B's held fees.
|
|
278
|
+
// Resolve B's primary terminal for the reclaim token. Could be this terminal (same-terminal short-
|
|
279
|
+
// circuit) or a router that swaps before depositing. Reverts if no primary terminal is registered.
|
|
284
280
|
IJBTerminal destinationTerminal = _resolveBeneficiaryTerminal(beneficiaryProjectId, tokenToReclaim);
|
|
281
|
+
|
|
282
|
+
// Snapshot B's per-context balances on this terminal BEFORE routing. The post-routing comparison
|
|
283
|
+
// identifies the bucket the reclaim actually landed in (matters for cross-token routes where a router
|
|
284
|
+
// swaps to a different token in B's accounting-context list).
|
|
285
285
|
(JBAccountingContext[] memory contexts, uint256[] memory balancesBefore) =
|
|
286
286
|
_snapshotBeneficiaryContextBalances(beneficiaryProjectId);
|
|
287
287
|
|
|
288
|
+
// Route via `_efficientAddToBalance` — handles same-terminal vs cross-terminal (with the standard
|
|
289
|
+
// `_beforeTransferTo`/`_afterTransferTo` allowance dance) and hardcodes `shouldReturnHeldFees: false`,
|
|
290
|
+
// so this entrypoint cannot be used to unlock B's held fees on top of the source-side fee skip.
|
|
288
291
|
_efficientAddToBalance({
|
|
289
292
|
terminal: destinationTerminal,
|
|
290
293
|
projectId: beneficiaryProjectId,
|
|
@@ -293,6 +296,9 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
293
296
|
metadata: addToBalanceMetadata
|
|
294
297
|
});
|
|
295
298
|
|
|
299
|
+
// Credit `_feeFreeSurplusOf[B]` on the first of B's contexts whose balance grew. This binds the
|
|
300
|
+
// skipped source-side fee on the destination side: B's next non-feeless cashout pays it. Reverts if
|
|
301
|
+
// no context grew (no delivery landed) — without delivery, the fee skip would leak.
|
|
296
302
|
_creditFirstGrowingBeneficiaryContext(beneficiaryProjectId, contexts, balancesBefore);
|
|
297
303
|
}
|
|
298
304
|
|
|
@@ -737,7 +743,14 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
737
743
|
override
|
|
738
744
|
returns (uint256 reclaimAmount, uint256 beneficiaryTokenCount)
|
|
739
745
|
{
|
|
746
|
+
// Caller must hold (or be operator with) `CASH_OUT_TOKENS` permission on the source `holder`/`projectId`.
|
|
747
|
+
// Burning A's tokens is the load-bearing side effect — gating it stays at the same authority bar as the
|
|
748
|
+
// direct `cashOutTokensOf` entrypoint.
|
|
740
749
|
_requireCashOutPermissionFrom({holder: holder, projectId: projectId});
|
|
750
|
+
|
|
751
|
+
// Destination opt-out check: B's current ruleset can set `pauseCrossProjectFeeFreeInflows = true` to
|
|
752
|
+
// refuse cross-project fee-free credits. Without this gate, anyone holding A's tokens could push a
|
|
753
|
+
// deferred-fee credit onto `_feeFreeSurplusOf[B]` without B consenting.
|
|
741
754
|
_requireBeneficiaryAcceptsFeeFreeInflows(beneficiaryProjectId);
|
|
742
755
|
|
|
743
756
|
// Burn source-project tokens, run cashout-side hooks, take any hook fees, and cap source fee-free.
|
|
@@ -1377,14 +1390,30 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1377
1390
|
)
|
|
1378
1391
|
internal
|
|
1379
1392
|
{
|
|
1393
|
+
// Walk B's accounting contexts in declared order. The first context whose balance grew is treated as
|
|
1394
|
+
// the bucket the router chose to deposit into (typically the post-swap token in a cross-token route).
|
|
1395
|
+
// We bind the deferred source-side fee to that bucket and stop — subsequent grown contexts are ignored
|
|
1396
|
+
// by design, capping the credit at one delivery delta even if a misbehaving router somehow split the
|
|
1397
|
+
// deposit across multiple buckets.
|
|
1380
1398
|
for (uint256 i; i < contexts.length;) {
|
|
1399
|
+
// Read B's post-routing balance for this context's token. Compared against the pre-routing snapshot
|
|
1400
|
+
// captured by `_snapshotBeneficiaryContextBalances` to detect the delivery delta.
|
|
1381
1401
|
uint256 balanceAfter =
|
|
1382
1402
|
STORE.balanceOf({terminal: address(this), projectId: beneficiaryProjectId, token: contexts[i].token});
|
|
1383
1403
|
|
|
1384
1404
|
if (balanceAfter > balancesBefore[i]) {
|
|
1405
|
+
// Credit the delivery delta into B's fee-free counter for this token. `unchecked` is safe:
|
|
1406
|
+
// `balanceAfter > balancesBefore[i]` is the loop condition, so the subtraction can't underflow,
|
|
1407
|
+
// and the addition can't overflow before the underlying balance does (terminal balance is the
|
|
1408
|
+
// upper bound on any cumulative credit — see the cap call below).
|
|
1385
1409
|
unchecked {
|
|
1386
1410
|
_feeFreeSurplusOf[beneficiaryProjectId][contexts[i].token] += balanceAfter - balancesBefore[i];
|
|
1387
1411
|
}
|
|
1412
|
+
|
|
1413
|
+
// Cap the credit at B's current balance for this token. If pay/addToBalance hooks pulled funds
|
|
1414
|
+
// back out during routing, the post-balance read inside `_capFeeFreeSurplus` clamps the
|
|
1415
|
+
// counter so it never exceeds what's actually sitting in B's bucket. Without this, B's later
|
|
1416
|
+
// zero-tax cashouts would over-fee phantom amounts.
|
|
1388
1417
|
_capFeeFreeSurplus({projectId: beneficiaryProjectId, token: contexts[i].token});
|
|
1389
1418
|
return;
|
|
1390
1419
|
}
|
|
@@ -1394,6 +1423,9 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1394
1423
|
}
|
|
1395
1424
|
}
|
|
1396
1425
|
|
|
1426
|
+
// No context grew. Either the destination terminal silently dropped the funds or routed them
|
|
1427
|
+
// elsewhere (e.g. to a different terminal not registered as B's primary). Revert the entire
|
|
1428
|
+
// cross-project flow so the source-side fee skip never becomes a leak — A's burn is undone too.
|
|
1397
1429
|
revert JBMultiTerminal_BeneficiaryProjectNotPaid(beneficiaryProjectId);
|
|
1398
1430
|
}
|
|
1399
1431
|
|
|
@@ -2112,7 +2144,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
2112
2144
|
projectId: projectId,
|
|
2113
2145
|
token: token,
|
|
2114
2146
|
amount: amount,
|
|
2115
|
-
fee: FEE,
|
|
2147
|
+
fee: JBConstants.FEE,
|
|
2116
2148
|
beneficiary: beneficiary,
|
|
2117
2149
|
caller: _msgSender()
|
|
2118
2150
|
});
|
|
@@ -71,9 +71,6 @@ interface IJBFeeTerminal is IJBTerminal {
|
|
|
71
71
|
address caller
|
|
72
72
|
);
|
|
73
73
|
|
|
74
|
-
/// @notice The terminal's fee as a fraction of `JBConstants.MAX_FEE`.
|
|
75
|
-
function FEE() external view returns (uint256);
|
|
76
|
-
|
|
77
74
|
/// @notice The contract that tracks feeless addresses.
|
|
78
75
|
function FEELESS_ADDRESSES() external view returns (IJBFeelessAddresses);
|
|
79
76
|
|