116 lines
No EOL
4.2 KiB
Solidity
116 lines
No EOL
4.2 KiB
Solidity
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
pragma solidity ^0.8.19;
|
|
|
|
import {IUniswapV3Pool} from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
|
|
import {IWETH9} from "../../src/interfaces/IWETH9.sol";
|
|
import {Kraiken} from "../../src/Kraiken.sol";
|
|
import {TickMath} from "@aperture/uni-v3-lib/TickMath.sol";
|
|
import {LiquidityBoundaryHelper} from "../../test/helpers/LiquidityBoundaryHelper.sol";
|
|
import {ThreePositionStrategy} from "../../src/abstracts/ThreePositionStrategy.sol";
|
|
|
|
/**
|
|
* @title SwapExecutor
|
|
* @notice Helper contract to execute swaps on Uniswap V3 pools for analysis scripts
|
|
* @dev Extracted from analysis scripts to avoid code duplication
|
|
*/
|
|
contract SwapExecutor {
|
|
IUniswapV3Pool public pool;
|
|
IWETH9 public weth;
|
|
Kraiken public harberg;
|
|
bool public token0isWeth;
|
|
ThreePositionStrategy public liquidityManager;
|
|
|
|
constructor(IUniswapV3Pool _pool, IWETH9 _weth, Kraiken _harberg, bool _token0isWeth, ThreePositionStrategy _liquidityManager) {
|
|
pool = _pool;
|
|
weth = _weth;
|
|
harberg = _harberg;
|
|
token0isWeth = _token0isWeth;
|
|
liquidityManager = _liquidityManager;
|
|
}
|
|
|
|
function executeBuy(uint256 amount, address recipient) external returns (uint256) {
|
|
// Calculate maximum safe buy amount based on liquidity
|
|
uint256 maxBuyAmount = LiquidityBoundaryHelper.calculateBuyLimit(pool, liquidityManager, token0isWeth);
|
|
|
|
// Cap the amount to the safe limit
|
|
uint256 safeAmount = amount > maxBuyAmount ? maxBuyAmount : amount;
|
|
|
|
// Skip if amount is zero
|
|
if (safeAmount == 0) return 0;
|
|
|
|
// For buying HARB with WETH, we're swapping in the direction that increases HARB price
|
|
// zeroForOne = true if WETH is token0, false if WETH is token1
|
|
bool zeroForOne = token0isWeth;
|
|
|
|
// Set appropriate price limit based on swap direction
|
|
uint160 sqrtPriceLimitX96;
|
|
if (zeroForOne) {
|
|
// Price goes down (in terms of token0/token1 ratio)
|
|
sqrtPriceLimitX96 = TickMath.MIN_SQRT_RATIO + 1;
|
|
} else {
|
|
// Price goes up
|
|
sqrtPriceLimitX96 = TickMath.MAX_SQRT_RATIO - 1;
|
|
}
|
|
|
|
pool.swap(
|
|
recipient,
|
|
zeroForOne,
|
|
int256(safeAmount),
|
|
sqrtPriceLimitX96,
|
|
""
|
|
);
|
|
|
|
return safeAmount;
|
|
}
|
|
|
|
function executeSell(uint256 amount, address recipient) external returns (uint256) {
|
|
// Calculate maximum safe sell amount based on liquidity
|
|
uint256 maxSellAmount = LiquidityBoundaryHelper.calculateSellLimit(pool, liquidityManager, token0isWeth);
|
|
|
|
// Cap the amount to the safe limit
|
|
uint256 safeAmount = amount > maxSellAmount ? maxSellAmount : amount;
|
|
|
|
// Skip if amount is zero
|
|
if (safeAmount == 0) return 0;
|
|
|
|
// For selling HARB for WETH, we're swapping in the direction that decreases HARB price
|
|
// zeroForOne = false if WETH is token0, true if WETH is token1
|
|
bool zeroForOne = !token0isWeth;
|
|
|
|
// Set appropriate price limit based on swap direction
|
|
uint160 sqrtPriceLimitX96;
|
|
if (zeroForOne) {
|
|
// Price goes down (in terms of token0/token1 ratio)
|
|
sqrtPriceLimitX96 = TickMath.MIN_SQRT_RATIO + 1;
|
|
} else {
|
|
// Price goes up
|
|
sqrtPriceLimitX96 = TickMath.MAX_SQRT_RATIO - 1;
|
|
}
|
|
|
|
pool.swap(
|
|
recipient,
|
|
zeroForOne,
|
|
int256(safeAmount),
|
|
sqrtPriceLimitX96,
|
|
""
|
|
);
|
|
|
|
return safeAmount;
|
|
}
|
|
|
|
// Callback required for Uniswap V3 swaps
|
|
function uniswapV3SwapCallback(
|
|
int256 amount0Delta,
|
|
int256 amount1Delta,
|
|
bytes calldata
|
|
) external {
|
|
require(msg.sender == address(pool), "Unauthorized callback");
|
|
|
|
if (amount0Delta > 0) {
|
|
IWETH9(pool.token0()).transfer(address(pool), uint256(amount0Delta));
|
|
}
|
|
if (amount1Delta > 0) {
|
|
IWETH9(pool.token1()).transfer(address(pool), uint256(amount1Delta));
|
|
}
|
|
}
|
|
} |