mirror of
https://github.com/lux-amm/v3-core.git
synced 2026-10-30 20:55:08 +00:00
206 lines
6.0 KiB
Solidity
206 lines
6.0 KiB
Solidity
pragma solidity =0.7.6;
|
|
pragma abicoder v2;
|
|
|
|
import '../../../../../contracts/test/TestERC20.sol';
|
|
import '../../../../../contracts/UniswapV3Pool.sol';
|
|
import '../../../../../contracts/UniswapV3Factory.sol';
|
|
|
|
contract SetupToken {
|
|
TestERC20 public token;
|
|
|
|
constructor() public {
|
|
// this contract will receive the total supply of 100 tokens
|
|
token = new TestERC20(1e12 ether);
|
|
}
|
|
|
|
function mintTo(address _recipient, uint256 _amount) public {
|
|
token.transfer(_recipient, _amount);
|
|
}
|
|
}
|
|
|
|
contract SetupTokens {
|
|
SetupToken tokenSetup0;
|
|
SetupToken tokenSetup1;
|
|
|
|
TestERC20 public token0;
|
|
TestERC20 public token1;
|
|
|
|
constructor() public {
|
|
// create the token wrappers
|
|
tokenSetup0 = new SetupToken();
|
|
tokenSetup1 = new SetupToken();
|
|
|
|
// switch them around so that token0's address is lower than token1's
|
|
// since this is what the uniswap factory will do when you create the pool
|
|
if (address(tokenSetup0.token()) > address(tokenSetup1.token())) {
|
|
(tokenSetup0, tokenSetup1) = (tokenSetup1, tokenSetup0);
|
|
}
|
|
|
|
// save the erc20 tokens
|
|
token0 = tokenSetup0.token();
|
|
token1 = tokenSetup1.token();
|
|
}
|
|
|
|
// mint either token0 or token1 to a chosen account
|
|
function mintTo(
|
|
uint256 _tokenIdx,
|
|
address _recipient,
|
|
uint256 _amount
|
|
) public {
|
|
require(_tokenIdx == 0 || _tokenIdx == 1, 'invalid token idx');
|
|
if (_tokenIdx == 0) tokenSetup0.mintTo(_recipient, _amount);
|
|
if (_tokenIdx == 1) tokenSetup1.mintTo(_recipient, _amount);
|
|
}
|
|
}
|
|
|
|
contract SetupUniswap {
|
|
UniswapV3Pool public pool;
|
|
TestERC20 token0;
|
|
TestERC20 token1;
|
|
|
|
// will create the following enabled fees and corresponding tickSpacing
|
|
// fee 500 + tickSpacing 10
|
|
// fee 3000 + tickSpacing 60
|
|
// fee 10000 + tickSpacing 200
|
|
UniswapV3Factory factory;
|
|
|
|
constructor(TestERC20 _token0, TestERC20 _token1) public {
|
|
factory = new UniswapV3Factory();
|
|
token0 = _token0;
|
|
token1 = _token1;
|
|
}
|
|
|
|
function createPool(uint24 _fee, uint160 _startPrice) public {
|
|
pool = UniswapV3Pool(factory.createPool(address(token0), address(token1), _fee));
|
|
pool.initialize(_startPrice);
|
|
}
|
|
}
|
|
|
|
contract UniswapMinter {
|
|
UniswapV3Pool pool;
|
|
TestERC20 token0;
|
|
TestERC20 token1;
|
|
|
|
struct MinterStats {
|
|
uint128 liq;
|
|
uint128 tL_liqGross;
|
|
int128 tL_liqNet;
|
|
uint128 tU_liqGross;
|
|
int128 tU_liqNet;
|
|
}
|
|
|
|
constructor(TestERC20 _token0, TestERC20 _token1) public {
|
|
token0 = _token0;
|
|
token1 = _token1;
|
|
}
|
|
|
|
function setPool(UniswapV3Pool _pool) public {
|
|
pool = _pool;
|
|
}
|
|
|
|
function uniswapV3MintCallback(
|
|
uint256 amount0Owed,
|
|
uint256 amount1Owed,
|
|
bytes calldata data
|
|
) external {
|
|
if (amount0Owed > 0) token0.transfer(address(pool), amount0Owed);
|
|
if (amount1Owed > 0) token1.transfer(address(pool), amount1Owed);
|
|
}
|
|
|
|
function getTickLiquidityVars(int24 _tickLower, int24 _tickUpper)
|
|
internal
|
|
view
|
|
returns (
|
|
uint128,
|
|
int128,
|
|
uint128,
|
|
int128
|
|
)
|
|
{
|
|
(uint128 tL_liqGross, int128 tL_liqNet, , ) = pool.ticks(_tickLower);
|
|
(uint128 tU_liqGross, int128 tU_liqNet, , ) = pool.ticks(_tickUpper);
|
|
return (tL_liqGross, tL_liqNet, tU_liqGross, tU_liqNet);
|
|
}
|
|
|
|
function getStats(int24 _tickLower, int24 _tickUpper) internal view returns (MinterStats memory stats) {
|
|
(uint128 tL_lg, int128 tL_ln, uint128 tU_lg, int128 tU_ln) = getTickLiquidityVars(_tickLower, _tickUpper);
|
|
return MinterStats(pool.liquidity(), tL_lg, tL_ln, tU_lg, tU_ln);
|
|
}
|
|
|
|
function doMint(
|
|
int24 _tickLower,
|
|
int24 _tickUpper,
|
|
uint128 _amount
|
|
) public returns (MinterStats memory bfre, MinterStats memory aftr) {
|
|
bfre = getStats(_tickLower, _tickUpper);
|
|
pool.mint(address(this), _tickLower, _tickUpper, _amount, new bytes(0));
|
|
aftr = getStats(_tickLower, _tickUpper);
|
|
}
|
|
|
|
function doBurn(
|
|
int24 _tickLower,
|
|
int24 _tickUpper,
|
|
uint128 _amount
|
|
) public returns (MinterStats memory bfre, MinterStats memory aftr) {
|
|
bfre = getStats(_tickLower, _tickUpper);
|
|
pool.burn(_tickLower, _tickUpper, _amount);
|
|
aftr = getStats(_tickLower, _tickUpper);
|
|
}
|
|
}
|
|
|
|
contract UniswapSwapper {
|
|
UniswapV3Pool pool;
|
|
TestERC20 token0;
|
|
TestERC20 token1;
|
|
|
|
struct SwapperStats {
|
|
uint128 liq;
|
|
uint256 feeGrowthGlobal0X128;
|
|
uint256 feeGrowthGlobal1X128;
|
|
uint256 bal0;
|
|
uint256 bal1;
|
|
int24 tick;
|
|
}
|
|
|
|
constructor(TestERC20 _token0, TestERC20 _token1) public {
|
|
token0 = _token0;
|
|
token1 = _token1;
|
|
}
|
|
|
|
function setPool(UniswapV3Pool _pool) public {
|
|
pool = _pool;
|
|
}
|
|
|
|
function uniswapV3SwapCallback(
|
|
int256 amount0Delta,
|
|
int256 amount1Delta,
|
|
bytes calldata data
|
|
) external {
|
|
if (amount0Delta > 0) token0.transfer(address(pool), uint256(amount0Delta));
|
|
if (amount1Delta > 0) token1.transfer(address(pool), uint256(amount1Delta));
|
|
}
|
|
|
|
function getStats() internal view returns (SwapperStats memory stats) {
|
|
(, int24 currentTick, , , , , ) = pool.slot0();
|
|
return
|
|
SwapperStats(
|
|
pool.liquidity(),
|
|
pool.feeGrowthGlobal0X128(),
|
|
pool.feeGrowthGlobal1X128(),
|
|
token0.balanceOf(address(this)),
|
|
token1.balanceOf(address(this)),
|
|
currentTick
|
|
);
|
|
}
|
|
|
|
function doSwap(
|
|
bool _zeroForOne,
|
|
int256 _amountSpecified,
|
|
uint160 _sqrtPriceLimitX96
|
|
) public returns (SwapperStats memory bfre, SwapperStats memory aftr) {
|
|
bfre = getStats();
|
|
pool.swap(address(this), _zeroForOne, _amountSpecified, _sqrtPriceLimitX96, new bytes(0));
|
|
aftr = getStats();
|
|
}
|
|
}
|