@bananapus/router-terminal-v6 0.0.3 → 0.0.5
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/foundry.toml +1 -1
- package/package.json +1 -1
- package/src/JBRouterTerminal.sol +63 -55
package/foundry.toml
CHANGED
package/package.json
CHANGED
package/src/JBRouterTerminal.sol
CHANGED
|
@@ -71,16 +71,20 @@ contract JBRouterTerminal is
|
|
|
71
71
|
/// @notice The default TWAP window used for auto-discovered pools.
|
|
72
72
|
uint256 public constant DEFAULT_TWAP_WINDOW = 10 minutes;
|
|
73
73
|
|
|
74
|
+
/// @notice The denominator used for slippage tolerance basis points.
|
|
75
|
+
uint256 public constant SLIPPAGE_DENOMINATOR = 10_000;
|
|
76
|
+
|
|
77
|
+
//*********************************************************************//
|
|
78
|
+
// ---------------------- internal stored properties ----------------- //
|
|
79
|
+
//*********************************************************************//
|
|
80
|
+
|
|
74
81
|
/// @notice The fee tiers to search when auto-discovering V3 pools, ordered by commonality.
|
|
75
82
|
/// 3000 = 0.3%, 500 = 0.05%, 10000 = 1%, 100 = 0.01%.
|
|
76
|
-
uint24[4]
|
|
83
|
+
uint24[4] internal _FEE_TIERS = [uint24(3000), uint24(500), uint24(10_000), uint24(100)];
|
|
77
84
|
|
|
78
85
|
/// @notice The fee/tickSpacing pairings to search for V4 vanilla pools.
|
|
79
|
-
uint24[4]
|
|
80
|
-
int24[4]
|
|
81
|
-
|
|
82
|
-
/// @notice The denominator used for slippage tolerance basis points.
|
|
83
|
-
uint256 public constant SLIPPAGE_DENOMINATOR = 10_000;
|
|
86
|
+
uint24[4] internal _V4_FEES = [uint24(3000), uint24(500), uint24(10_000), uint24(100)];
|
|
87
|
+
int24[4] internal _V4_TICK_SPACINGS = [int24(60), int24(10), int24(200), int24(1)];
|
|
84
88
|
|
|
85
89
|
//*********************************************************************//
|
|
86
90
|
// ---------------- public immutable stored properties --------------- //
|
|
@@ -571,6 +575,7 @@ contract JBRouterTerminal is
|
|
|
571
575
|
bool hasFallback;
|
|
572
576
|
|
|
573
577
|
for (uint256 i; i < terminals.length; i++) {
|
|
578
|
+
// slither-disable-next-line calls-loop
|
|
574
579
|
JBAccountingContext[] memory contexts = terminals[i].accountingContextsOf(projectId);
|
|
575
580
|
|
|
576
581
|
for (uint256 j; j < contexts.length; j++) {
|
|
@@ -607,46 +612,34 @@ contract JBRouterTerminal is
|
|
|
607
612
|
function _bestPoolLiquidity(address tokenA, address tokenB) internal view returns (uint128 bestLiquidity) {
|
|
608
613
|
// Search V3.
|
|
609
614
|
for (uint256 i; i < 4; i++) {
|
|
610
|
-
|
|
615
|
+
// slither-disable-next-line calls-loop
|
|
616
|
+
address poolAddr = FACTORY.getPool(tokenA, tokenB, _FEE_TIERS[i]);
|
|
611
617
|
if (poolAddr == address(0)) continue;
|
|
612
618
|
|
|
619
|
+
// slither-disable-next-line calls-loop
|
|
613
620
|
uint128 liquidity = IUniswapV3Pool(poolAddr).liquidity();
|
|
614
621
|
if (liquidity > bestLiquidity) bestLiquidity = liquidity;
|
|
615
622
|
}
|
|
616
623
|
|
|
617
|
-
// Search V4.
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
for (uint256 i; i < 4; i++) {
|
|
637
|
-
PoolKey memory key = PoolKey({
|
|
638
|
-
currency0: Currency.wrap(sorted0),
|
|
639
|
-
currency1: Currency.wrap(sorted1),
|
|
640
|
-
fee: V4_FEES[i],
|
|
641
|
-
tickSpacing: V4_TICK_SPACINGS[i],
|
|
642
|
-
hooks: IHooks(address(0))
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
(uint160 sqrtPriceX96,,,) = POOL_MANAGER.getSlot0(key.toId());
|
|
646
|
-
if (sqrtPriceX96 == 0) continue;
|
|
647
|
-
|
|
648
|
-
uint128 liquidity = POOL_MANAGER.getLiquidity(key.toId());
|
|
649
|
-
if (liquidity > bestLiquidity) bestLiquidity = liquidity;
|
|
624
|
+
// Search V4 — reuse _discoverV4Pool with current best.
|
|
625
|
+
PoolInfo memory v4Result = _discoverV4Pool(
|
|
626
|
+
tokenA,
|
|
627
|
+
tokenB,
|
|
628
|
+
bestLiquidity,
|
|
629
|
+
PoolInfo({
|
|
630
|
+
isV4: false,
|
|
631
|
+
v3Pool: IUniswapV3Pool(address(0)),
|
|
632
|
+
v4Key: PoolKey({
|
|
633
|
+
currency0: Currency.wrap(address(0)),
|
|
634
|
+
currency1: Currency.wrap(address(0)),
|
|
635
|
+
fee: 0,
|
|
636
|
+
tickSpacing: 0,
|
|
637
|
+
hooks: IHooks(address(0))
|
|
638
|
+
})
|
|
639
|
+
})
|
|
640
|
+
);
|
|
641
|
+
if (v4Result.isV4) {
|
|
642
|
+
bestLiquidity = POOL_MANAGER.getLiquidity(v4Result.v4Key.toId());
|
|
650
643
|
}
|
|
651
644
|
}
|
|
652
645
|
|
|
@@ -821,11 +814,13 @@ contract JBRouterTerminal is
|
|
|
821
814
|
function _settleV4(Currency currency, uint256 amount) internal {
|
|
822
815
|
if (Currency.unwrap(currency) == address(0)) {
|
|
823
816
|
// Native ETH: contract already holds raw ETH.
|
|
817
|
+
// slither-disable-next-line unused-return
|
|
824
818
|
POOL_MANAGER.settle{value: amount}();
|
|
825
819
|
} else {
|
|
826
820
|
// ERC20: sync then transfer then settle.
|
|
827
821
|
POOL_MANAGER.sync(currency);
|
|
828
822
|
IERC20(Currency.unwrap(currency)).safeTransfer(address(POOL_MANAGER), amount);
|
|
823
|
+
// slither-disable-next-line unused-return
|
|
829
824
|
POOL_MANAGER.settle();
|
|
830
825
|
}
|
|
831
826
|
}
|
|
@@ -945,6 +940,7 @@ contract JBRouterTerminal is
|
|
|
945
940
|
returns (uint256 minAmountOut)
|
|
946
941
|
{
|
|
947
942
|
PoolId id = key.toId();
|
|
943
|
+
// slither-disable-next-line unused-return
|
|
948
944
|
(, int24 tick,,) = POOL_MANAGER.getSlot0(id);
|
|
949
945
|
uint128 liquidity = POOL_MANAGER.getLiquidity(id);
|
|
950
946
|
|
|
@@ -986,15 +982,27 @@ contract JBRouterTerminal is
|
|
|
986
982
|
|
|
987
983
|
// Search V3.
|
|
988
984
|
for (uint256 i; i < 4; i++) {
|
|
989
|
-
|
|
985
|
+
// slither-disable-next-line calls-loop
|
|
986
|
+
address poolAddr = FACTORY.getPool(normalizedTokenIn, normalizedTokenOut, _FEE_TIERS[i]);
|
|
990
987
|
|
|
991
988
|
if (poolAddr == address(0)) continue;
|
|
992
989
|
|
|
990
|
+
// slither-disable-next-line calls-loop
|
|
993
991
|
uint128 poolLiquidity = IUniswapV3Pool(poolAddr).liquidity();
|
|
994
992
|
|
|
995
993
|
if (poolLiquidity > bestLiquidity) {
|
|
996
994
|
bestLiquidity = poolLiquidity;
|
|
997
|
-
bestPool = PoolInfo({
|
|
995
|
+
bestPool = PoolInfo({
|
|
996
|
+
isV4: false,
|
|
997
|
+
v3Pool: IUniswapV3Pool(poolAddr),
|
|
998
|
+
v4Key: PoolKey({
|
|
999
|
+
currency0: Currency.wrap(address(0)),
|
|
1000
|
+
currency1: Currency.wrap(address(0)),
|
|
1001
|
+
fee: 0,
|
|
1002
|
+
tickSpacing: 0,
|
|
1003
|
+
hooks: IHooks(address(0))
|
|
1004
|
+
})
|
|
1005
|
+
});
|
|
998
1006
|
}
|
|
999
1007
|
}
|
|
1000
1008
|
|
|
@@ -1030,14 +1038,16 @@ contract JBRouterTerminal is
|
|
|
1030
1038
|
PoolKey memory key = PoolKey({
|
|
1031
1039
|
currency0: Currency.wrap(sorted0),
|
|
1032
1040
|
currency1: Currency.wrap(sorted1),
|
|
1033
|
-
fee:
|
|
1034
|
-
tickSpacing:
|
|
1041
|
+
fee: _V4_FEES[i],
|
|
1042
|
+
tickSpacing: _V4_TICK_SPACINGS[i],
|
|
1035
1043
|
hooks: IHooks(address(0))
|
|
1036
1044
|
});
|
|
1037
1045
|
|
|
1046
|
+
// slither-disable-next-line unused-return,calls-loop
|
|
1038
1047
|
(uint160 sqrtPriceX96,,,) = POOL_MANAGER.getSlot0(key.toId());
|
|
1039
1048
|
if (sqrtPriceX96 == 0) continue;
|
|
1040
1049
|
|
|
1050
|
+
// slither-disable-next-line calls-loop
|
|
1041
1051
|
uint128 poolLiquidity = POOL_MANAGER.getLiquidity(key.toId());
|
|
1042
1052
|
if (poolLiquidity > currentBestLiquidity) {
|
|
1043
1053
|
currentBestLiquidity = poolLiquidity;
|
|
@@ -1099,6 +1109,7 @@ contract JBRouterTerminal is
|
|
|
1099
1109
|
while (true) {
|
|
1100
1110
|
// Skip the destination check on the first iteration if we have a credit override.
|
|
1101
1111
|
if (sourceProjectIdOverride == 0) {
|
|
1112
|
+
// slither-disable-next-line calls-loop
|
|
1102
1113
|
destTerminal = DIRECTORY.primaryTerminalOf({projectId: destProjectId, token: token});
|
|
1103
1114
|
if (address(destTerminal) != address(0)) {
|
|
1104
1115
|
return (destTerminal, token, amount);
|
|
@@ -1106,6 +1117,7 @@ contract JBRouterTerminal is
|
|
|
1106
1117
|
}
|
|
1107
1118
|
|
|
1108
1119
|
// Use the override if provided, otherwise look up the project ID from the token.
|
|
1120
|
+
// slither-disable-next-line calls-loop
|
|
1109
1121
|
uint256 sourceProjectId =
|
|
1110
1122
|
sourceProjectIdOverride != 0 ? sourceProjectIdOverride : TOKENS.projectIdOf(IJBToken(token));
|
|
1111
1123
|
|
|
@@ -1119,6 +1131,7 @@ contract JBRouterTerminal is
|
|
|
1119
1131
|
_findCashOutPath({sourceProjectId: sourceProjectId, destProjectId: destProjectId});
|
|
1120
1132
|
|
|
1121
1133
|
// Cash out the source project's tokens.
|
|
1134
|
+
// slither-disable-next-line calls-loop
|
|
1122
1135
|
amount = cashOutTerminal.cashOutTokensOf({
|
|
1123
1136
|
holder: address(this),
|
|
1124
1137
|
projectId: sourceProjectId,
|
|
@@ -1155,11 +1168,13 @@ contract JBRouterTerminal is
|
|
|
1155
1168
|
address baseFallbackToken;
|
|
1156
1169
|
IJBCashOutTerminal baseFallbackTerminal;
|
|
1157
1170
|
|
|
1171
|
+
// slither-disable-next-line calls-loop
|
|
1158
1172
|
IJBTerminal[] memory terminals = DIRECTORY.terminalsOf(sourceProjectId);
|
|
1159
1173
|
|
|
1160
1174
|
for (uint256 i; i < terminals.length; i++) {
|
|
1161
1175
|
// Check if this terminal supports the IJBCashOutTerminal interface.
|
|
1162
1176
|
{
|
|
1177
|
+
// slither-disable-next-line calls-loop
|
|
1163
1178
|
try IERC165(address(terminals[i])).supportsInterface(type(IJBCashOutTerminal).interfaceId) returns (
|
|
1164
1179
|
bool supported
|
|
1165
1180
|
) {
|
|
@@ -1170,6 +1185,7 @@ contract JBRouterTerminal is
|
|
|
1170
1185
|
}
|
|
1171
1186
|
|
|
1172
1187
|
IJBCashOutTerminal terminal = IJBCashOutTerminal(address(terminals[i]));
|
|
1188
|
+
// slither-disable-next-line calls-loop
|
|
1173
1189
|
JBAccountingContext[] memory contexts = terminals[i].accountingContextsOf(sourceProjectId);
|
|
1174
1190
|
|
|
1175
1191
|
for (uint256 j; j < contexts.length; j++) {
|
|
@@ -1177,6 +1193,7 @@ contract JBRouterTerminal is
|
|
|
1177
1193
|
|
|
1178
1194
|
// Priority 1: Does the destination project directly accept this token?
|
|
1179
1195
|
{
|
|
1196
|
+
// slither-disable-next-line calls-loop
|
|
1180
1197
|
IJBTerminal destTerminal =
|
|
1181
1198
|
DIRECTORY.primaryTerminalOf({projectId: destProjectId, token: contextToken});
|
|
1182
1199
|
if (address(destTerminal) != address(0)) {
|
|
@@ -1186,6 +1203,7 @@ contract JBRouterTerminal is
|
|
|
1186
1203
|
|
|
1187
1204
|
// Priority 2: Is this a JB project token (so we can recurse)?
|
|
1188
1205
|
if (address(fallbackTerminal) == address(0) && contextToken != JBConstants.NATIVE_TOKEN) {
|
|
1206
|
+
// slither-disable-next-line calls-loop
|
|
1189
1207
|
if (TOKENS.projectIdOf(IJBToken(contextToken)) != 0) {
|
|
1190
1208
|
fallbackToken = contextToken;
|
|
1191
1209
|
fallbackTerminal = terminal;
|
|
@@ -1258,6 +1276,7 @@ contract JBRouterTerminal is
|
|
|
1258
1276
|
sigDeadline: allowance.sigDeadline
|
|
1259
1277
|
});
|
|
1260
1278
|
|
|
1279
|
+
// slither-disable-next-line reentrancy-events
|
|
1261
1280
|
try PERMIT2.permit({owner: _msgSender(), permitSingle: permitSingle, signature: allowance.signature}) {}
|
|
1262
1281
|
catch (bytes memory reason) {
|
|
1263
1282
|
emit Permit2AllowanceFailed(token, _msgSender(), reason);
|
|
@@ -1309,17 +1328,6 @@ contract JBRouterTerminal is
|
|
|
1309
1328
|
PERMIT2.transferFrom(from, to, uint160(amount), token);
|
|
1310
1329
|
}
|
|
1311
1330
|
|
|
1312
|
-
/// @notice Returns an empty PoolKey for use in V3-only PoolInfo structs.
|
|
1313
|
-
function _emptyPoolKey() internal pure returns (PoolKey memory) {
|
|
1314
|
-
return PoolKey({
|
|
1315
|
-
currency0: Currency.wrap(address(0)),
|
|
1316
|
-
currency1: Currency.wrap(address(0)),
|
|
1317
|
-
fee: 0,
|
|
1318
|
-
tickSpacing: 0,
|
|
1319
|
-
hooks: IHooks(address(0))
|
|
1320
|
-
});
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
1331
|
//*********************************************************************//
|
|
1324
1332
|
// ---------------------------- receive ----------------------------- //
|
|
1325
1333
|
//*********************************************************************//
|