@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 CHANGED
@@ -1,7 +1,7 @@
1
1
  [profile.default]
2
2
  solc = '0.8.26'
3
3
  evm_version = 'cancun'
4
- optimizer_runs = 100000000
4
+ optimizer_runs = 200
5
5
  libs = ["node_modules", "lib"]
6
6
  fs_permissions = [{ access = "read-write", path = "./"}]
7
7
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananapus/router-terminal-v6",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -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] public FEE_TIERS = [uint24(3000), uint24(500), uint24(10_000), uint24(100)];
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] public V4_FEES = [uint24(3000), uint24(500), uint24(10_000), uint24(100)];
80
- int24[4] public V4_TICK_SPACINGS = [int24(60), int24(10), int24(200), int24(1)];
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
- address poolAddr = FACTORY.getPool(tokenA, tokenB, FEE_TIERS[i]);
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
- uint128 v4Best = _bestV4PoolLiquidity(tokenA, tokenB);
619
- if (v4Best > bestLiquidity) bestLiquidity = v4Best;
620
- }
621
-
622
- /// @notice Find the highest liquidity across V4 vanilla pools for a token pair.
623
- /// @param tokenA One token in the pair.
624
- /// @param tokenB The other token in the pair.
625
- /// @return bestLiquidity The highest liquidity found across V4 pools.
626
- function _bestV4PoolLiquidity(address tokenA, address tokenB) internal view returns (uint128 bestLiquidity) {
627
- if (address(POOL_MANAGER) == address(0)) return 0;
628
-
629
- // Convert WETH -> address(0) for V4 native ETH representation.
630
- address v4A = tokenA == address(WETH) ? address(0) : tokenA;
631
- address v4B = tokenB == address(WETH) ? address(0) : tokenB;
632
-
633
- // Sort currencies (currency0 < currency1).
634
- (address sorted0, address sorted1) = v4A < v4B ? (v4A, v4B) : (v4B, v4A);
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
- address poolAddr = FACTORY.getPool(normalizedTokenIn, normalizedTokenOut, FEE_TIERS[i]);
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({isV4: false, v3Pool: IUniswapV3Pool(poolAddr), v4Key: _emptyPoolKey()});
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: V4_FEES[i],
1034
- tickSpacing: V4_TICK_SPACINGS[i],
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
  //*********************************************************************//