harb/onchain/test/helpers/UniswapTestBase.sol
giteadmin 5db3ecb3d7 wip
2024-12-09 23:08:24 +01:00

104 lines
3.6 KiB
Solidity

// 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 {
uint160 limit;
// Determine the swap direction
bool zeroForOne = isBuy ? token0isWeth : !token0isWeth;
if (isBuy) {
vm.prank(account);
weth.transfer(address(this), amount);
} else {
vm.prank(account);
harberg.approve(address(this), amount);
}
// 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;
}
pool.swap(
account,
zeroForOne,
int256(amount),
limit,
abi.encode(account, int256(amount), isBuy)
);
}
/**
* @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");
}
}
/// @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);
}
}
}