Files
contract/test/MirrorEnv.sol
2025-01-06 17:10:28 -04:00

162 lines
6.1 KiB
Solidity

pragma solidity 0.8.26;
//import "@forge-std/console2.sol";
import "../src/more/MockERC20.sol";
import "../src/core/Util.sol";
import {IUniswapV3Pool} from "../lib_uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import {INonfungiblePositionManager} from "../lib_uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol";
import {ISwapRouter} from "../lib_uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import {IERC20Metadata} from "../lib_uniswap/v3-periphery/contracts/interfaces/IERC20Metadata.sol";
import "./MockUtil.sol";
contract MirrorEnv {
struct MockPool {
IUniswapV3Pool pool;
bool inverted; // true iff the mock pool's token0/1 are flipped relative to the original pool
}
// map original token addresses to their mock counterparts
mapping(IERC20Metadata=>MockERC20) public tokens;
IERC20Metadata[] public tokenKeys;
function numTokens() external view returns (uint256) {
return tokenKeys.length;
}
// map original pool addresses to their mock counterparts
mapping(IUniswapV3Pool=>MockPool) public pools;
IUniswapV3Pool[] public poolKeys;
function numPools() external view returns (uint256) {
return poolKeys.length;
}
INonfungiblePositionManager immutable public nfpm;
ISwapRouter immutable public swapRouter;
constructor (INonfungiblePositionManager nfpm_, ISwapRouter swapRouter_) {
nfpm = nfpm_;
swapRouter = swapRouter_;
}
struct TokenInfo {
IERC20Metadata addr;
string name;
string symbol;
uint8 decimals;
}
function mirrorToken( TokenInfo memory info ) public returns (MockERC20 mock) {
// console2.log('MirrorEnv.mirrorToken()');
// console2.log(address(info.addr));
mock = tokens[info.addr];
if ( address(mock) == address(0) ) {
// console2.log('creating mock token');
// console2.log(info.name);
// console2.log(info.symbol);
// console2.log(info.decimals);
mock = new MockERC20(info.name, info.symbol, info.decimals);
// console2.log('setting tokens[]');
tokens[info.addr] = mock;
tokenKeys.push() = info.addr;
// console2.log('set tokens[]');
}
// console2.log(address(mock));
// console2.log('mirrorToken complete');
}
struct PoolInfo {
IUniswapV3Pool pool;
IERC20Metadata token0;
IERC20Metadata token1;
uint24 fee;
uint160 sqrtPriceX96;
uint256 amount0;
uint256 amount1;
}
// given the original pool address, create a similar pool using mock tokens
function mirrorPool( PoolInfo memory info ) public returns (MockPool memory mock) {
// console2.log('MirrorEnv.mirrorPool()');
// console2.log(address(info.pool));
mock = pools[info.pool];
// console2.log(address(mock.pool));
if ( address(mock.pool) == address(0) ) {
// console2.log('creating mirror pool');
MockERC20 token0 = tokens[info.token0];
MockERC20 token1 = tokens[info.token1];
// console2.log(address(info.token0));
// console2.log(address(token0));
// console2.log(address(info.token1));
// console2.log(address(token1));
require(address(token0)!=address(0), 'token0 not mirrored');
require(address(token1)!=address(0), 'token1 not mirrored');
// put 100th of the total liquidity on each of the 1774545 ticks
uint256 amount0 = info.amount0 * 1774545 / 100;
uint256 amount1 = info.amount1 * 1774545 / 100;
uint160 initialPrice = info.sqrtPriceX96;
bool inverted = token0 > token1;
// console2.log('got tokens. inverted?');
if( inverted ) {
(token0, token1) = (token1, token0);
(amount0, amount1) = (amount1, amount0);
initialPrice = uint160(2**96 * 2**96 / uint256(initialPrice));
}
// console2.log(inverted);
// console2.log(address(token0));
// console2.log(address(token1));
// console2.log(info.fee);
// console2.log(initialPrice);
IUniswapV3Pool mockPool = IUniswapV3Pool(nfpm.createAndInitializePoolIfNecessary(
address(token0), address(token1), info.fee, initialPrice));
mock = MockPool(mockPool, inverted);
// console2.log('mirror pool / inverted');
// console2.log(address(mockPool));
// console2.log(inverted);
pools[info.pool] = mock;
poolKeys.push() = info.pool;
// console2.log('staking');
MockUtil.stakeWide( nfpm, mockPool, amount0, amount1);
// console2.log('staked');
}
// console2.log('mirrored pool');
}
function mirrorPools( PoolInfo[] memory pool ) public returns (MockPool[] memory mock) {
mock = new MockPool[](pool.length);
for( uint i=0; i<pool.length; i++ )
mock[i] = mirrorPool(pool[i]);
}
// change the price of a mock pool based on the original pool price
function updatePool( IUniswapV3Pool pool, uint160 sqrtPriceX96 ) public returns (MockPool memory mock) {
// console2.log('updating');
// console2.log(address(pool));
mock = pools[pool];
require( address(mock.pool) != address(0), 'not mirrored' );
if (mock.inverted) {
// console2.log('inverting');
// console2.log(sqrtPriceX96);
sqrtPriceX96 = uint160(uint256(2**96 * 2**96) / uint256(sqrtPriceX96));
}
MockUtil.swapToPrice(swapRouter, mock.pool, sqrtPriceX96);
// console2.log('updated pool');
}
struct PoolUpdateInfo {
IUniswapV3Pool pool;
uint160 sqrtPriceX96;
}
function updatePools( PoolUpdateInfo[] memory infos ) public returns (MockPool[] memory mock) {
mock = new MockPool[](infos.length);
for( uint i=0; i<infos.length; i++ ) {
PoolUpdateInfo memory info = infos[i];
mock[i] = updatePool(info.pool, info.sqrtPriceX96);
}
}
}