2024-11-07 15:33:40 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
pragma solidity ^0.8.19;
|
|
|
|
|
|
|
|
|
|
import "forge-std/Test.sol";
|
|
|
|
|
import "@uniswap-v3-core/interfaces/IUniswapV3Pool.sol";
|
|
|
|
|
import {TickMath} from "@aperture/uni-v3-lib/TickMath.sol";
|
|
|
|
|
import "../../src/interfaces/IWETH9.sol";
|
|
|
|
|
import {Harberg} from "../../src/Harberg.sol";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @title UniswapTestBase
|
|
|
|
|
* @dev Base contract for Uniswap V3 testing, providing reusable swap logic.
|
|
|
|
|
*/
|
|
|
|
|
abstract contract UniswapTestBase is Test {
|
|
|
|
|
address account = makeAddr("alice");
|
|
|
|
|
IUniswapV3Pool public pool;
|
|
|
|
|
IWETH9 public weth;
|
|
|
|
|
Harberg public harberg;
|
|
|
|
|
bool public token0isWeth;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dev Performs a swap in the Uniswap V3 pool.
|
|
|
|
|
* @param amount The amount to swap.
|
|
|
|
|
* @param isBuy True if buying WETH, false if selling.
|
|
|
|
|
*/
|
|
|
|
|
function performSwap(uint256 amount, bool isBuy) internal {
|
2024-12-09 23:08:24 +01:00
|
|
|
uint160 limit;
|
|
|
|
|
// Determine the swap direction
|
|
|
|
|
bool zeroForOne = isBuy ? token0isWeth : !token0isWeth;
|
2024-11-07 15:33:40 +00:00
|
|
|
|
2024-12-09 23:08:24 +01:00
|
|
|
if (isBuy) {
|
|
|
|
|
vm.prank(account);
|
|
|
|
|
weth.transfer(address(this), amount);
|
|
|
|
|
} else {
|
|
|
|
|
vm.prank(account);
|
|
|
|
|
harberg.approve(address(this), amount);
|
|
|
|
|
}
|
2024-11-07 15:33:40 +00:00
|
|
|
|
2024-12-09 23:08:24 +01:00
|
|
|
// Set the sqrtPriceLimitX96 based on the swap direction
|
|
|
|
|
if (zeroForOne) {
|
|
|
|
|
// Swapping token0 for token1
|
|
|
|
|
// sqrtPriceLimitX96 must be less than current price but greater than MIN_SQRT_RATIO
|
|
|
|
|
limit = TickMath.MIN_SQRT_RATIO + 1;
|
|
|
|
|
} else {
|
|
|
|
|
// Swapping token1 for token0
|
|
|
|
|
// sqrtPriceLimitX96 must be greater than current price but less than MAX_SQRT_RATIO
|
|
|
|
|
limit = TickMath.MAX_SQRT_RATIO - 1;
|
|
|
|
|
}
|
2024-11-07 15:33:40 +00:00
|
|
|
|
2024-12-09 23:08:24 +01:00
|
|
|
pool.swap(
|
|
|
|
|
account,
|
|
|
|
|
zeroForOne,
|
|
|
|
|
int256(amount),
|
|
|
|
|
limit,
|
|
|
|
|
abi.encode(account, int256(amount), isBuy)
|
|
|
|
|
);
|
2024-11-07 15:33:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dev The Uniswap V3 swap callback.
|
|
|
|
|
*/
|
|
|
|
|
function uniswapV3SwapCallback(
|
|
|
|
|
int256 amount0Delta,
|
|
|
|
|
int256 amount1Delta,
|
|
|
|
|
bytes calldata _data
|
|
|
|
|
) external {
|
|
|
|
|
require(amount0Delta > 0 || amount1Delta > 0);
|
|
|
|
|
|
|
|
|
|
(address seller, , bool isBuy) = abi.decode(_data, (address, uint256, bool));
|
|
|
|
|
|
|
|
|
|
(, uint256 amountToPay) = amount0Delta > 0
|
|
|
|
|
? (!token0isWeth, uint256(amount0Delta))
|
|
|
|
|
: (token0isWeth, uint256(amount1Delta));
|
|
|
|
|
if (isBuy) {
|
|
|
|
|
weth.transfer(msg.sender, amountToPay);
|
|
|
|
|
} else {
|
|
|
|
|
require(harberg.transferFrom(seller, msg.sender, amountToPay), "Transfer failed");
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-09 23:08:24 +01:00
|
|
|
|
|
|
|
|
/// @notice Callback function that Uniswap V3 calls for liquidity actions requiring minting or burning of tokens.
|
|
|
|
|
/// @param amount0Owed The amount of token0 owed for the liquidity provision.
|
|
|
|
|
/// @param amount1Owed The amount of token1 owed for the liquidity provision.
|
|
|
|
|
/// @dev This function mints Harberg tokens as needed and handles WETH deposits for ETH conversions during liquidity interactions.
|
|
|
|
|
function uniswapV3MintCallback(uint256 amount0Owed, uint256 amount1Owed, bytes calldata) external {
|
|
|
|
|
// CallbackValidation.verifyCallback(factory, poolKey);
|
|
|
|
|
// take care of harb
|
|
|
|
|
uint256 harbPulled = token0isWeth ? amount1Owed : amount0Owed;
|
|
|
|
|
if (harbPulled > 0) {
|
|
|
|
|
harberg.mint(harbPulled);
|
|
|
|
|
harberg.transfer(msg.sender, harbPulled);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pack ETH
|
|
|
|
|
uint256 ethOwed = token0isWeth ? amount0Owed : amount1Owed;
|
|
|
|
|
if (weth.balanceOf(address(this)) < ethOwed) {
|
|
|
|
|
weth.deposit{value: address(this).balance}();
|
|
|
|
|
}
|
|
|
|
|
if (ethOwed > 0) {
|
|
|
|
|
weth.transfer(msg.sender, amount1Owed);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-07 15:33:40 +00:00
|
|
|
}
|