@bananapus/router-terminal-v6 0.0.22 → 0.0.24
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 +3 -3
- package/script/Deploy.s.sol +12 -6
- package/src/JBRouterTerminal.sol +33 -7
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.24",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@bananapus/address-registry-v6": "^0.0.16",
|
|
21
|
-
"@bananapus/core-v6": "^0.0.
|
|
22
|
-
"@bananapus/permission-ids-v6": "^0.0.
|
|
21
|
+
"@bananapus/core-v6": "^0.0.30",
|
|
22
|
+
"@bananapus/permission-ids-v6": "^0.0.15",
|
|
23
23
|
"@openzeppelin/contracts": "^5.6.1",
|
|
24
24
|
"@uniswap/permit2": "github:Uniswap/permit2",
|
|
25
25
|
"@uniswap/v3-core": "github:Uniswap/v3-core#0.8",
|
package/script/Deploy.s.sol
CHANGED
|
@@ -62,32 +62,38 @@ contract DeployScript is Script, Sphinx {
|
|
|
62
62
|
} else if (block.chainid == 10) {
|
|
63
63
|
weth = 0x4200000000000000000000000000000000000006;
|
|
64
64
|
factory = 0x1F98431c8aD98523631AE4a59f267346ea31F984;
|
|
65
|
-
|
|
65
|
+
// https://docs.uniswap.org/contracts/v4/deployments
|
|
66
|
+
poolManager = 0x9a13F98Cb987694C9F086b1F5eB990EeA8264Ec3;
|
|
66
67
|
// Base Mainnet
|
|
67
68
|
} else if (block.chainid == 8453) {
|
|
68
69
|
weth = 0x4200000000000000000000000000000000000006;
|
|
69
70
|
factory = 0x33128a8fC17869897dcE68Ed026d694621f6FDfD;
|
|
70
|
-
|
|
71
|
+
// https://docs.uniswap.org/contracts/v4/deployments
|
|
72
|
+
poolManager = 0x498581fF718922c3f8e6A244956aF099B2652b2b;
|
|
71
73
|
// Optimism Sepolia
|
|
72
74
|
} else if (block.chainid == 11_155_420) {
|
|
73
75
|
weth = 0x4200000000000000000000000000000000000006;
|
|
74
76
|
factory = 0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24;
|
|
75
|
-
|
|
77
|
+
// https://docs.uniswap.org/contracts/v4/deployments
|
|
78
|
+
poolManager = 0x1390B1276c3C0dd59E0e666d4cF97e30267E72E0;
|
|
76
79
|
// BASE Sepolia
|
|
77
80
|
} else if (block.chainid == 84_532) {
|
|
78
81
|
weth = 0x4200000000000000000000000000000000000006;
|
|
79
82
|
factory = 0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24;
|
|
80
|
-
|
|
83
|
+
// https://docs.uniswap.org/contracts/v4/deployments
|
|
84
|
+
poolManager = 0x05E73354cFDd6745C338b50BcFDfA3Aa6fA03408;
|
|
81
85
|
// Arbitrum Mainnet
|
|
82
86
|
} else if (block.chainid == 42_161) {
|
|
83
87
|
weth = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1;
|
|
84
88
|
factory = 0x1F98431c8aD98523631AE4a59f267346ea31F984;
|
|
85
|
-
|
|
89
|
+
// https://docs.uniswap.org/contracts/v4/deployments
|
|
90
|
+
poolManager = 0x360E68faCcca8cA495c1B759Fd9EEe466db9FB32;
|
|
86
91
|
// Arbitrum Sepolia
|
|
87
92
|
} else if (block.chainid == 421_614) {
|
|
88
93
|
weth = 0x980B62Da83eFf3D4576C647993b0c1D7faf17c73;
|
|
89
94
|
factory = 0x248AB79Bbb9bC29bB72f7Cd42F17e054Fc40188e;
|
|
90
|
-
|
|
95
|
+
// https://docs.uniswap.org/contracts/v4/deployments
|
|
96
|
+
poolManager = 0xFB3e0C6F74eB1a21CC1Da29aeC80D2Dfe6C9a317;
|
|
91
97
|
} else {
|
|
92
98
|
revert("Invalid RPC / no juice contracts deployed on this network");
|
|
93
99
|
}
|
package/src/JBRouterTerminal.sol
CHANGED
|
@@ -543,9 +543,18 @@ contract JBRouterTerminal is
|
|
|
543
543
|
|
|
544
544
|
(uint256 sourceProjectId, uint256 creditAmount) = abi.decode(creditData, (uint256, uint256));
|
|
545
545
|
|
|
546
|
-
//
|
|
546
|
+
// Resolve the actual credit holder. When called via an intermediary (e.g. JBRouterTerminalRegistry),
|
|
547
|
+
// _msgSender() is the intermediary — use its originalPayer to find the true holder.
|
|
548
|
+
address holder = _msgSender();
|
|
549
|
+
if (msg.sender.code.length > 0) {
|
|
550
|
+
try IJBPayerTracker(msg.sender).originalPayer() returns (address payer) {
|
|
551
|
+
if (payer != address(0)) holder = payer;
|
|
552
|
+
} catch {}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// Pull credits from the holder (requires holder to have granted TRANSFER_CREDITS to this contract).
|
|
547
556
|
TOKENS.transferCreditsFrom({
|
|
548
|
-
holder:
|
|
557
|
+
holder: holder, projectId: sourceProjectId, recipient: address(this), count: creditAmount
|
|
549
558
|
});
|
|
550
559
|
|
|
551
560
|
return creditAmount;
|
|
@@ -678,6 +687,8 @@ contract JBRouterTerminal is
|
|
|
678
687
|
// This propagates slippage protection through multi-hop cashouts instead of dropping it.
|
|
679
688
|
if (minTokensReclaimed != 0 && previousExpectedAmount != 0) {
|
|
680
689
|
minTokensReclaimed = mulDiv(minTokensReclaimed, amount, previousExpectedAmount);
|
|
690
|
+
// minTokensReclaimed may round to 0 here — that is intentional.
|
|
691
|
+
// A 0 minimum is valid and means no slippage protection for this hop.
|
|
681
692
|
}
|
|
682
693
|
|
|
683
694
|
// Update for next iteration.
|
|
@@ -1400,26 +1411,33 @@ contract JBRouterTerminal is
|
|
|
1400
1411
|
returns (uint256 minAmountOut)
|
|
1401
1412
|
{
|
|
1402
1413
|
PoolId id = key.toId();
|
|
1414
|
+
|
|
1415
|
+
// The tick used for quoting — prefer TWAP over spot for MEV resistance.
|
|
1403
1416
|
int24 tick;
|
|
1417
|
+
|
|
1418
|
+
// Track whether the oracle hook provided a TWAP so we know whether to fall back to spot.
|
|
1404
1419
|
bool usedTwap;
|
|
1405
1420
|
|
|
1406
|
-
//
|
|
1421
|
+
// If the pool has a hook, try querying it as a geomean oracle (e.g., JBUniswapV4Hook implements this).
|
|
1407
1422
|
if (address(key.hooks) != address(0)) {
|
|
1423
|
+
// Build the two-element lookback array: [_TWAP_WINDOW seconds ago, now].
|
|
1408
1424
|
uint32[] memory secondsAgos = new uint32[](2);
|
|
1409
|
-
secondsAgos[0] = _TWAP_WINDOW;
|
|
1410
|
-
secondsAgos[1] = 0;
|
|
1425
|
+
secondsAgos[0] = _TWAP_WINDOW; // Start of the window (30 seconds ago).
|
|
1426
|
+
secondsAgos[1] = 0; // End of the window (current block).
|
|
1427
|
+
|
|
1428
|
+
// Ask the hook for cumulative tick data over the window. Silently catch if it doesn't support it.
|
|
1411
1429
|
// slither-disable-next-line unused-return
|
|
1412
1430
|
try IGeomeanOracle(address(key.hooks)).observe(key, secondsAgos) returns (
|
|
1413
1431
|
int56[] memory tickCumulatives, uint160[] memory
|
|
1414
1432
|
) {
|
|
1415
|
-
//
|
|
1433
|
+
// Derive the arithmetic mean tick: (cumulative_now - cumulative_start) / elapsed_seconds.
|
|
1416
1434
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
1417
1435
|
tick = int24((tickCumulatives[1] - tickCumulatives[0]) / int56(int32(_TWAP_WINDOW)));
|
|
1418
1436
|
usedTwap = true;
|
|
1419
1437
|
} catch {}
|
|
1420
1438
|
}
|
|
1421
1439
|
|
|
1422
|
-
//
|
|
1440
|
+
// If no TWAP was available (no hook, or hook doesn't implement observe), use the instantaneous spot tick.
|
|
1423
1441
|
if (!usedTwap) {
|
|
1424
1442
|
// slither-disable-next-line unused-return
|
|
1425
1443
|
(, tick,,) = _getSlot0(id);
|
|
@@ -1509,6 +1527,12 @@ contract JBRouterTerminal is
|
|
|
1509
1527
|
|
|
1510
1528
|
if (exists) {
|
|
1511
1529
|
(minAmountOut) = abi.decode(quote, (uint256));
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
// Treat a decoded value of 0 the same as "not provided" so that a stale or default-zero quote
|
|
1533
|
+
// does not silently disable slippage protection. Fall through to automatic quoting.
|
|
1534
|
+
if (minAmountOut != 0) {
|
|
1535
|
+
// User-provided quote is valid; skip automatic quoting.
|
|
1512
1536
|
} else if (pool.isV4) {
|
|
1513
1537
|
minAmountOut = _getV4SpotQuote({
|
|
1514
1538
|
key: pool.v4Key,
|
|
@@ -1601,6 +1625,8 @@ contract JBRouterTerminal is
|
|
|
1601
1625
|
// Scale the minimum proportionally for the next step based on the actual cashout ratio.
|
|
1602
1626
|
if (minTokensReclaimed != 0 && previousExpectedAmount != 0) {
|
|
1603
1627
|
minTokensReclaimed = mulDiv(minTokensReclaimed, amount, previousExpectedAmount);
|
|
1628
|
+
// minTokensReclaimed may round to 0 here — that is intentional.
|
|
1629
|
+
// A 0 minimum is valid and means no slippage protection for this hop.
|
|
1604
1630
|
}
|
|
1605
1631
|
|
|
1606
1632
|
// Continue previewing from the token reclaimed in this hop.
|