diff --git a/contracts/src/LPAggreator.sol b/contracts/src/LPAggreator.sol index 8718f48..d09d049 100644 --- a/contracts/src/LPAggreator.sol +++ b/contracts/src/LPAggreator.sol @@ -51,8 +51,10 @@ contract LPAggreator { mapping(address => IUniswapV2Router02) public routers02; - address private constant FACTORY = 0x36B83E0D41D1dd9C73a006F0c1cbC1F096E69E34; - address private constant UNISWAP_ROUTER02_ADDRESS = 0x873789aaF553FD0B4252d0D2b72C6331c47aff2E; + address private constant FACTORY = + 0x36B83E0D41D1dd9C73a006F0c1cbC1F096E69E34; + address private constant UNISWAP_ROUTER02_ADDRESS = + 0x873789aaF553FD0B4252d0D2b72C6331c47aff2E; address private constant CETH = 0x2ED3dddae5B2F321AF0806181FBFA6D049Be47d8; constructor() public { @@ -61,7 +63,9 @@ contract LPAggreator { ); } - function removeLiquidity(RemoveLPParams memory removeParams) internal returns (uint256 amountARemoved, uint256 amountBRemoved) { + function removeLiquidity( + RemoveLPParams memory removeParams + ) internal returns (uint256 amountARemoved, uint256 amountBRemoved) { // Transfer LP from user to this contract address pair = IUniswapV2Factory(FACTORY).getPair( removeParams.tokenA, @@ -80,9 +84,8 @@ contract LPAggreator { ); // Remove liquidity - (amountARemoved, amountBRemoved) = routers02[ - UNISWAP_ROUTER02_ADDRESS - ].removeLiquidity( + (amountARemoved, amountBRemoved) = routers02[UNISWAP_ROUTER02_ADDRESS] + .removeLiquidity( removeParams.tokenA, removeParams.tokenB, removeParams.liquidity, @@ -93,7 +96,9 @@ contract LPAggreator { ); } - function addLiquidity(AddLPParams memory addParams) internal returns (uint256 amountA, uint256 amountB, uint256 liquidity) { + function addLiquidity( + AddLPParams memory addParams + ) internal returns (uint256 amountA, uint256 amountB, uint256 liquidity) { IERC20(addParams.tokenA).safeApprove( UNISWAP_ROUTER02_ADDRESS, addParams.amountADesired @@ -102,121 +107,120 @@ contract LPAggreator { UNISWAP_ROUTER02_ADDRESS, addParams.amountBDesired ); - (amountA, amountB, liquidity) = routers02[UNISWAP_ROUTER02_ADDRESS].addLiquidity( - addParams.tokenA, - addParams.tokenB, - addParams.amountADesired, - addParams.amountBDesired, - addParams.amountAMin, - addParams.amountBMin, - addParams.to, - block.timestamp - ); - - if(amountA < addParams.amountADesired) { - IERC20(addParams.tokenA).safeApprove( - UNISWAP_ROUTER02_ADDRESS, - 0 + (amountA, amountB, liquidity) = routers02[UNISWAP_ROUTER02_ADDRESS] + .addLiquidity( + addParams.tokenA, + addParams.tokenB, + addParams.amountADesired, + addParams.amountBDesired, + addParams.amountAMin, + addParams.amountBMin, + addParams.to, + block.timestamp ); + + if (amountA < addParams.amountADesired) { + IERC20(addParams.tokenA).safeApprove(UNISWAP_ROUTER02_ADDRESS, 0); } - if(amountB < addParams.amountBDesired) { - IERC20(addParams.tokenB).safeApprove( - UNISWAP_ROUTER02_ADDRESS, - 0 - ); + if (amountB < addParams.amountBDesired) { + IERC20(addParams.tokenB).safeApprove(UNISWAP_ROUTER02_ADDRESS, 0); } // Transfer remain token to user - uint256 amountETH = swapFromTokenToETH(addParams.amountADesired - amountA, addParams.tokenA, addParams.amountBDesired - amountB, addParams.tokenB); - if(amountETH > 0) { - IERC20(CETH).safeTransfer( - msg.sender, - amountETH - ); + uint256 amountETH = swapFromTokenToETH( + addParams.amountADesired - amountA, + addParams.tokenA, + addParams.amountBDesired - amountB, + addParams.tokenB + ); + if (amountETH > 0) { + IERC20(CETH).safeTransfer(msg.sender, amountETH); } } - function swapFromTokenToETH(uint256 amountA, address tokenA, uint256 amountB, address tokenB) internal returns (uint256 amountETH) { + function swapFromTokenToETH( + uint256 amountA, + address tokenA, + uint256 amountB, + address tokenB + ) internal returns (uint256 amountETH) { // Swap from removed token to ETH if (tokenA == CETH) { amountETH = amountA; - } else if(amountA > 0) { - IERC20(tokenA).safeApprove( - UNISWAP_ROUTER02_ADDRESS, - amountA - ); + } else if (amountA > 0) { + IERC20(tokenA).safeApprove(UNISWAP_ROUTER02_ADDRESS, amountA); address[] memory path = new address[](2); path[0] = tokenA; path[1] = CETH; - (uint[] memory amounts) = routers02[UNISWAP_ROUTER02_ADDRESS].swapExactTokensForTokens( - amountA, - 0, - path, - address(this), - block.timestamp - ); + uint[] memory amounts = routers02[UNISWAP_ROUTER02_ADDRESS] + .swapExactTokensForTokens( + amountA, + 0, + path, + address(this), + block.timestamp + ); amountETH += amounts[1]; } - if(tokenB == CETH) { + if (tokenB == CETH) { amountETH += amountB; - } else if(amountB > 0) { - IERC20(tokenB).safeApprove( - UNISWAP_ROUTER02_ADDRESS, - amountB - ); + } else if (amountB > 0) { + IERC20(tokenB).safeApprove(UNISWAP_ROUTER02_ADDRESS, amountB); address[] memory path = new address[](2); path[0] = tokenB; path[1] = CETH; - (uint[] memory amounts) = routers02[UNISWAP_ROUTER02_ADDRESS].swapExactTokensForTokens( - amountB, - 0, - path, - address(this), - block.timestamp - ); + uint[] memory amounts = routers02[UNISWAP_ROUTER02_ADDRESS] + .swapExactTokensForTokens( + amountB, + 0, + path, + address(this), + block.timestamp + ); amountETH += amounts[1]; } } - function swapFromETHToToken(uint256 amountETHToA, address tokenA, uint256 amountETHToB, address tokenB) internal returns (uint256 amountA, uint256 amountB) { - if(tokenA != CETH) { - IERC20(CETH).safeApprove( - UNISWAP_ROUTER02_ADDRESS, - amountETHToA - ); + function swapFromETHToToken( + uint256 amountETHToA, + address tokenA, + uint256 amountETHToB, + address tokenB + ) internal returns (uint256 amountA, uint256 amountB) { + if (tokenA != CETH) { + IERC20(CETH).safeApprove(UNISWAP_ROUTER02_ADDRESS, amountETHToA); address[] memory path = new address[](2); path[0] = CETH; path[1] = tokenA; - (uint[] memory amounts) = routers02[UNISWAP_ROUTER02_ADDRESS].swapExactTokensForTokens( - amountETHToA, - 0, - path, - address(this), - block.timestamp - ); + uint[] memory amounts = routers02[UNISWAP_ROUTER02_ADDRESS] + .swapExactTokensForTokens( + amountETHToA, + 0, + path, + address(this), + block.timestamp + ); amountA = amounts[1]; } else { amountA = amountETHToA; } - if(tokenB != CETH) { - IERC20(amountETHToB).safeApprove( - UNISWAP_ROUTER02_ADDRESS, - amountETHToB - ); + if (tokenB != CETH) { + IERC20(CETH).safeApprove(UNISWAP_ROUTER02_ADDRESS, amountETHToB); address[] memory path = new address[](2); path[0] = CETH; path[1] = tokenB; - (uint[] memory amounts) = routers02[UNISWAP_ROUTER02_ADDRESS].swapExactTokensForTokens( - amountETHToB, - 0, - path, - address(this), - block.timestamp - ); + uint[] memory amounts = routers02[UNISWAP_ROUTER02_ADDRESS] + .swapExactTokensForTokens( + amountETHToB, + 0, + path, + address(this), + block.timestamp + ); amountB = amounts[1]; } else { @@ -224,11 +228,11 @@ contract LPAggreator { } } - function transferLiquidityToOwner(address pair, uint256 liquidity) internal { - IERC20(pair).safeTransfer( - msg.sender, - liquidity - ); + function transferLiquidityToOwner( + address pair, + uint256 liquidity + ) internal { + IERC20(pair).safeTransfer(msg.sender, liquidity); } function swapLP( @@ -236,12 +240,23 @@ contract LPAggreator { AddLPParams memory addParams ) public returns (uint256 amountA, uint256 amountB, uint256 liquidity) { // Remove liquidity - (uint256 amountARemoved, uint256 amountBRemoved) = removeLiquidity(removeParams); + (uint256 amountARemoved, uint256 amountBRemoved) = removeLiquidity( + removeParams + ); // Swap from removed token to ETH - uint256 amountETH = swapFromTokenToETH(amountARemoved, removeParams.tokenA, amountBRemoved, removeParams.tokenB); - // Swap from ETH to add token - (uint256 amountAToAdd, uint256 amountBToAdd) = swapFromETHToToken(amountETH / 2, addParams.tokenA, amountETH / 2, addParams.tokenB); - + uint256 amountETH = swapFromTokenToETH( + amountARemoved, + removeParams.tokenA, + amountBRemoved, + removeParams.tokenB + ); + // Swap from ETH to add token; + (uint256 amountAToAdd, uint256 amountBToAdd) = swapFromETHToToken( + amountETH / 2, + addParams.tokenA, + amountETH / 2, + addParams.tokenB + ); // Add liquidity (amountA, amountB, liquidity) = addLiquidity( AddLPParams( diff --git a/contracts/test/testConflux.sol b/contracts/test/testConflux.sol new file mode 100644 index 0000000..27dc08f --- /dev/null +++ b/contracts/test/testConflux.sol @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.6.6; +pragma experimental ABIEncoderV2; + +import "forge-std/Test.sol"; +import "forge-std/console.sol"; + +import "../src/LPAggreator.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/safeERC20.sol"; +import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol"; +import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol"; +import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol"; + +contract TestLPAggreator is Test { + using SafeERC20 for IERC20; + address public constant CFX = 0x2ED3dddae5B2F321AF0806181FBFA6D049Be47d8; + address public constant USDT = 0x7d682e65EFC5C13Bf4E394B8f376C48e6baE0355; + address public constant USDC = 0x349298B0E20DF67dEFd6eFb8F3170cF4a32722EF; + address public constant FAUCET_ETH = + 0xcD71270F82f319E0498FF98AF8269C3f0D547c65; + address public constant FAUCET_BTC = + 0x54593e02c39aEFf52B166bd036797D2b1478de8D; + address public constant WALLET_ADDRESS = + 0x9f05e3f61a93af744112fBAa880b1aF8e1935fb8; + + address private constant UNISWAP_ROUTER02_ADDRESS = + 0x873789aaF553FD0B4252d0D2b72C6331c47aff2E; + IUniswapV2Router02 private constant uniswapRouter = + IUniswapV2Router02(UNISWAP_ROUTER02_ADDRESS); + address private constant FACTORY = + 0x36B83E0D41D1dd9C73a006F0c1cbC1F096E69E34; + + LPAggreator lpAggreator = new LPAggreator(); + + IERC20 private constant cfx = IERC20(CFX); + IERC20 private constant usdt = IERC20(USDT); + IERC20 private constant usdc = IERC20(USDC); + + uint256 private liquidity = 0; + + function setUp() public payable { + vm.startBroadcast(WALLET_ADDRESS); + IERC20(USDT).safeApprove(UNISWAP_ROUTER02_ADDRESS, 5 * 1e18); + address[] memory path = new address[](2); + path[0] = USDT; + path[1] = CFX; + uint[] memory amount = uniswapRouter.swapExactTokensForTokens( + 5 * 1e18, + 0, + path, + WALLET_ADDRESS, + block.timestamp + ); + console.log(amount[0]); + console.log(amount[1]); + console.log("CFX balance", cfx.balanceOf(WALLET_ADDRESS)); + console.log("USDT balance", usdt.balanceOf(WALLET_ADDRESS)); + + console.log("--------------------"); + uint256 amountAToAdd = 10 * 1e18; + uint256 amountBToAdd = 10 * 1e18; + IERC20 pair = IERC20(IUniswapV2Factory(FACTORY).getPair(CFX, USDT)); + console.log("pair address: %s", address(pair)); + usdt.safeApprove(UNISWAP_ROUTER02_ADDRESS, 0); + cfx.safeApprove(UNISWAP_ROUTER02_ADDRESS, 0); + // Approve uni for transferring + usdt.safeApprove(UNISWAP_ROUTER02_ADDRESS, amountAToAdd); + cfx.safeApprove(UNISWAP_ROUTER02_ADDRESS, amountBToAdd); + + ( + uint256 amountA, + uint256 amountB, + uint256 liquidityMinted + ) = uniswapRouter.addLiquidity( + CFX, + USDT, + amountAToAdd, + amountBToAdd, + 1, + 1, + address(this), + block.timestamp + ); + + liquidity += liquidityMinted; + console.log("Liquidity: %s", liquidity); + console.log("amountA: %s, amountB: %s", amountA, amountB); + console.log("pair balance: %s", pair.balanceOf(address(this))); + assertGt(pair.balanceOf(address(this)), 0); + vm.stopBroadcast(); + } + + function testSwapLP() public { + vm.startBroadcast(WALLET_ADDRESS); + IERC20 pair = IERC20(IUniswapV2Factory(FACTORY).getPair(CFX, USDT)); + console.log("--------------------"); + console.log("pair balance: %s", pair.balanceOf(address(this))); + + LPAggreator.RemoveLPParams memory removeParams = LPAggreator + .RemoveLPParams( + USDT, + CFX, + liquidity / 10, + 0, + 0, + WALLET_ADDRESS, + block.timestamp + ); + LPAggreator.AddLPParams memory addParams = LPAggreator.AddLPParams( + FAUCET_ETH, + FAUCET_BTC, + 0, + 0, + 0, + 0, + WALLET_ADDRESS, + block.timestamp + ); + IERC20(pair).safeApprove(address(lpAggreator), liquidity); + ( + uint256 amountA, + uint256 amountB, + uint256 liquidityMinted + ) = lpAggreator.swapLP(removeParams, addParams); + console.log( + "Swap liquidity success, amountA: %s, amountB: %s, liquidity: %s", + amountA, + amountB, + liquidityMinted + ); + vm.stopBroadcast(); + } +}