@bananapus/router-terminal-v6 0.0.57 → 0.0.59
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/package.json +2 -2
- package/src/JBRouterTerminal.sol +36 -19
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bananapus/router-terminal-v6",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.59",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'nana-router-terminal-v6'"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@bananapus/buyback-hook-v6": "^0.0.
|
|
27
|
+
"@bananapus/buyback-hook-v6": "^0.0.64",
|
|
28
28
|
"@bananapus/core-v6": "^0.0.72",
|
|
29
29
|
"@bananapus/permission-ids-v6": "^0.0.27",
|
|
30
30
|
"@bananapus/univ4-router-v6": "^0.0.46",
|
package/src/JBRouterTerminal.sol
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
pragma solidity 0.8.28;
|
|
3
3
|
|
|
4
4
|
import {IJBCashOutTerminal} from "@bananapus/core-v6/src/interfaces/IJBCashOutTerminal.sol";
|
|
5
|
+
import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
5
6
|
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
6
7
|
import {IJBPermitTerminal} from "@bananapus/core-v6/src/interfaces/IJBPermitTerminal.sol";
|
|
7
8
|
import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
|
|
@@ -154,11 +155,11 @@ contract JBRouterTerminal is
|
|
|
154
155
|
/// @notice Pre-computed metadata ID for "permit2".
|
|
155
156
|
bytes4 internal immutable _PERMIT2_ID;
|
|
156
157
|
|
|
157
|
-
/// @notice Pre-computed metadata ID for "
|
|
158
|
-
bytes4 internal immutable
|
|
158
|
+
/// @notice Pre-computed metadata ID for "cashOut" (the cash-out reclaim floor).
|
|
159
|
+
bytes4 internal immutable _CASH_OUT_ID;
|
|
159
160
|
|
|
160
|
-
/// @notice Pre-computed metadata ID for "
|
|
161
|
-
bytes4 internal immutable
|
|
161
|
+
/// @notice Pre-computed metadata ID for "pay" (the pay-phase swap quote).
|
|
162
|
+
bytes4 internal immutable _PAY_ID;
|
|
162
163
|
|
|
163
164
|
//*********************************************************************//
|
|
164
165
|
// --------------------- public stored properties -------------------- //
|
|
@@ -220,8 +221,8 @@ contract JBRouterTerminal is
|
|
|
220
221
|
|
|
221
222
|
// Pre-compute metadata IDs to avoid hashing string literals on every call.
|
|
222
223
|
_PERMIT2_ID = JBMetadataResolver.getId("permit2");
|
|
223
|
-
|
|
224
|
-
|
|
224
|
+
_CASH_OUT_ID = JBMetadataResolver.getId("cashOut");
|
|
225
|
+
_PAY_ID = JBMetadataResolver.getId("pay");
|
|
225
226
|
}
|
|
226
227
|
|
|
227
228
|
//*********************************************************************//
|
|
@@ -1136,7 +1137,7 @@ contract JBRouterTerminal is
|
|
|
1136
1137
|
/// @param destProjectId The ID of the destination project.
|
|
1137
1138
|
/// @param token The current token to process.
|
|
1138
1139
|
/// @param amount The amount of the current token.
|
|
1139
|
-
/// @param metadata Bytes in `JBMetadataResolver`'s format (may contain
|
|
1140
|
+
/// @param metadata Bytes in `JBMetadataResolver`'s format (may contain a `cashOut` reclaim floor).
|
|
1140
1141
|
/// @return destTerminal The terminal that accepts the final token (address(0) if no direct acceptance found).
|
|
1141
1142
|
/// @return finalToken The token after all cashouts.
|
|
1142
1143
|
/// @return finalAmount The amount of the final token.
|
|
@@ -1180,6 +1181,8 @@ contract JBRouterTerminal is
|
|
|
1180
1181
|
sourceProjectId: sourceProjectId, destProjectId: destProjectId, preferredToken: preferredToken
|
|
1181
1182
|
});
|
|
1182
1183
|
|
|
1184
|
+
_claimRouterCreditsFor({projectId: sourceProjectId});
|
|
1185
|
+
|
|
1183
1186
|
uint256 cashOutCount = amount;
|
|
1184
1187
|
uint256 balanceBefore = _balanceOf({token: tokenToReclaim, account: address(this)});
|
|
1185
1188
|
|
|
@@ -1235,12 +1238,26 @@ contract JBRouterTerminal is
|
|
|
1235
1238
|
revert JBRouterTerminal_CashOutLoopLimit({maxIterations: _MAX_CASHOUT_ITERATIONS});
|
|
1236
1239
|
}
|
|
1237
1240
|
|
|
1241
|
+
/// @notice Converts this router's internal project-token credits into ERC-20s before a source cash-out.
|
|
1242
|
+
/// @dev Core burns holder credits before ERC-20 balances. Normalizing first keeps a source cash-out scoped to
|
|
1243
|
+
/// transferable token balances already visible to the router.
|
|
1244
|
+
/// @param projectId The Juicebox project whose tokens are being cashed out.
|
|
1245
|
+
function _claimRouterCreditsFor(uint256 projectId) internal {
|
|
1246
|
+
uint256 creditCount = TOKENS.creditBalanceOf({holder: address(this), projectId: projectId});
|
|
1247
|
+
if (creditCount == 0) return;
|
|
1248
|
+
|
|
1249
|
+
IJBController controller = IJBController(address(DIRECTORY.controllerOf(projectId)));
|
|
1250
|
+
controller.claimTokensFor({
|
|
1251
|
+
holder: address(this), projectId: projectId, tokenCount: creditCount, beneficiary: address(this)
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1238
1255
|
/// @notice Convert tokenIn to tokenOut. No-op if same, wrap/unwrap for native/wrapped-native, or swap via Uniswap.
|
|
1239
1256
|
/// @param tokenIn The token to convert from.
|
|
1240
1257
|
/// @param tokenOut The token to convert into.
|
|
1241
1258
|
/// @param amount The amount to convert.
|
|
1242
1259
|
/// @param projectId The project ID (passed through to swap callback data).
|
|
1243
|
-
/// @param metadata Bytes in `JBMetadataResolver`'s format (may contain
|
|
1260
|
+
/// @param metadata Bytes in `JBMetadataResolver`'s format (may contain a `pay` swap quote).
|
|
1244
1261
|
/// @param refundTo The address to receive leftover input tokens from partial fills.
|
|
1245
1262
|
/// @return The amount of tokenOut produced.
|
|
1246
1263
|
function _convert(
|
|
@@ -1422,7 +1439,7 @@ contract JBRouterTerminal is
|
|
|
1422
1439
|
/// @param tokenIn The token to swap from.
|
|
1423
1440
|
/// @param tokenOut The token to swap into.
|
|
1424
1441
|
/// @param amount The amount of tokenIn to swap.
|
|
1425
|
-
/// @param metadata Bytes in `JBMetadataResolver`'s format (may contain
|
|
1442
|
+
/// @param metadata Bytes in `JBMetadataResolver`'s format (may contain a `pay` swap quote).
|
|
1426
1443
|
/// @param refundTo The address to receive leftover input tokens from partial fills.
|
|
1427
1444
|
/// @return amountOut The amount of tokenOut received.
|
|
1428
1445
|
function _handleSwap(
|
|
@@ -1587,7 +1604,7 @@ contract JBRouterTerminal is
|
|
|
1587
1604
|
/// @param destProjectId The destination project to reach.
|
|
1588
1605
|
/// @param tokenIn The current route input token.
|
|
1589
1606
|
/// @param amount The current route input amount.
|
|
1590
|
-
/// @param metadata Metadata that may include a
|
|
1607
|
+
/// @param metadata Metadata that may include a `cashOut` reclaim floor.
|
|
1591
1608
|
/// @param preferredToken The preferred token to target during any cashout loop.
|
|
1592
1609
|
/// @return resolvedTerminal The terminal found by the cashout loop, or address(0) if conversion should continue.
|
|
1593
1610
|
/// @return routedTokenIn The token that remains to be routed after the cashout step.
|
|
@@ -2263,7 +2280,7 @@ contract JBRouterTerminal is
|
|
|
2263
2280
|
/// 3. Thin pools, newly initialized pools, and unusually large swaps should not rely on this fallback.
|
|
2264
2281
|
///
|
|
2265
2282
|
/// Mitigations in place:
|
|
2266
|
-
/// 1. Users SHOULD provide a `
|
|
2283
|
+
/// 1. Users SHOULD provide a `pay` swap quote in the payment metadata (obtained from an off-chain
|
|
2267
2284
|
/// quoter or RPC simulation). The quote must encode the output token and minimum output amount. When present,
|
|
2268
2285
|
/// this function is bypassed entirely — see `_pickPoolAndQuote`.
|
|
2269
2286
|
/// 2. When a hook implements `IGeomeanOracle.observe(...)`, this function uses that oracle-derived tick instead
|
|
@@ -2276,7 +2293,7 @@ contract JBRouterTerminal is
|
|
|
2276
2293
|
/// this V4 spot-price path altogether.
|
|
2277
2294
|
///
|
|
2278
2295
|
/// Despite these mitigations, the spot-based fallback does NOT provide full MEV protection. Integrators and
|
|
2279
|
-
/// front-ends should supply `
|
|
2296
|
+
/// front-ends should supply `pay` swap-quote metadata for V4 swaps whenever possible so the user's slippage
|
|
2280
2297
|
/// tolerance reflects a recent, off-chain-verified price. When no external quote can be provided, this fallback
|
|
2281
2298
|
/// is still available as an accepted-risk convenience path.
|
|
2282
2299
|
/// @param key The V4 pool key describing the pool to quote against.
|
|
@@ -2376,11 +2393,11 @@ contract JBRouterTerminal is
|
|
|
2376
2393
|
}
|
|
2377
2394
|
}
|
|
2378
2395
|
|
|
2379
|
-
/// @notice Parse the optional `
|
|
2396
|
+
/// @notice Parse the optional `cashOut` metadata (the minimum-reclaim floor).
|
|
2380
2397
|
/// @param metadata The metadata to inspect for minimum reclaim amounts.
|
|
2381
2398
|
/// @return minTokensReclaimed The minimum reclaim amount, or 0 if none is specified.
|
|
2382
2399
|
function _minReclaimedFrom(bytes calldata metadata) internal view returns (uint256 minTokensReclaimed) {
|
|
2383
|
-
(bool exists, bytes memory minData) = _getDataFor({metadata: metadata, id:
|
|
2400
|
+
(bool exists, bytes memory minData) = _getDataFor({metadata: metadata, id: _CASH_OUT_ID});
|
|
2384
2401
|
if (exists) minTokensReclaimed = abi.decode(minData, (uint256));
|
|
2385
2402
|
}
|
|
2386
2403
|
|
|
@@ -2418,10 +2435,10 @@ contract JBRouterTerminal is
|
|
|
2418
2435
|
/// @dev For V4 pools without TWAP-capable hooks, `minAmountOut` is derived from the same-block spot tick, which is
|
|
2419
2436
|
/// manipulable via sandwich attacks. This is an accepted risk for integrations that cannot source external quotes,
|
|
2420
2437
|
/// especially when routing through deep pools and routine swap sizes, but it should not be treated as full MEV
|
|
2421
|
-
/// protection. Integrators should still supply `
|
|
2438
|
+
/// protection. Integrators should still supply `pay` swap-quote metadata whenever they can.
|
|
2422
2439
|
///
|
|
2423
2440
|
/// Priority for `minAmountOut`:
|
|
2424
|
-
/// 1. **User-provided quote** — If `
|
|
2441
|
+
/// 1. **User-provided quote** — If a `pay` swap quote is present in `metadata`, it is used after confirming the
|
|
2425
2442
|
/// quote's output token matches the selected route. This is the recommended path for MEV protection,
|
|
2426
2443
|
/// especially for V4 pools.
|
|
2427
2444
|
/// 2. **V3 TWAP** — If the best pool is V3, uses a manipulation-resistant time-weighted average price.
|
|
@@ -2430,7 +2447,7 @@ contract JBRouterTerminal is
|
|
|
2430
2447
|
/// same block (see `_getV4SpotQuote` security note). The sigmoid slippage formula provides a floor but not
|
|
2431
2448
|
/// full MEV protection.
|
|
2432
2449
|
///
|
|
2433
|
-
/// @param metadata Bytes in `JBMetadataResolver`'s format (may contain
|
|
2450
|
+
/// @param metadata Bytes in `JBMetadataResolver`'s format (may contain a `pay` swap quote).
|
|
2434
2451
|
/// @param normalizedTokenIn The normalized input token address.
|
|
2435
2452
|
/// @param amount The amount of tokens to swap.
|
|
2436
2453
|
/// @param normalizedTokenOut The normalized output token address.
|
|
@@ -2452,9 +2469,9 @@ contract JBRouterTerminal is
|
|
|
2452
2469
|
revert JBRouterTerminal_NoPoolFound({tokenIn: normalizedTokenIn, tokenOut: normalizedTokenOut});
|
|
2453
2470
|
}
|
|
2454
2471
|
|
|
2455
|
-
// `
|
|
2472
|
+
// `pay` is encoded as `(tokenOut, minAmountOut)`. Binding the quote to its output token prevents
|
|
2456
2473
|
// metadata quoted for one route from being replayed against another route with a weaker floor.
|
|
2457
|
-
(bool exists, bytes memory quote) = _getDataFor({metadata: metadata, id:
|
|
2474
|
+
(bool exists, bytes memory quote) = _getDataFor({metadata: metadata, id: _PAY_ID});
|
|
2458
2475
|
|
|
2459
2476
|
if (exists) {
|
|
2460
2477
|
(address quotedTokenOut, uint256 quotedMinAmountOut) = abi.decode(quote, (address, uint256));
|