pragma solidity =0.6.6; import './libraries/TransferHelper.sol'; import './interfaces/IAstraMigrator.sol'; import './interfaces/V1/IAstraV1Factory.sol'; import './interfaces/V1/IAstraV1Exchange.sol'; import './interfaces/IAstraRouter01.sol'; import './interfaces/IERC20.sol'; contract AstraMigrator is IAstraMigrator { IAstraV1Factory immutable factoryV1; IAstraRouter01 immutable router; constructor(address _factoryV1, address _router) public { factoryV1 = IAstraV1Factory(_factoryV1); router = IAstraRouter01(_router); } // needs to accept AMB from any v1 exchange and the router. ideally this could be enforced, as in the router, // but it's not possible because it requires a call to the v1 factory, which takes too much gas receive() external payable {} function migrate(address token, uint amountTokenMin, uint amountAMBMin, address to, uint deadline) external override { IAstraV1Exchange exchangeV1 = IAstraV1Exchange(factoryV1.getExchange(token)); uint liquidityV1 = exchangeV1.balanceOf(msg.sender); require(exchangeV1.transferFrom(msg.sender, address(this), liquidityV1), 'TRANSFER_FROM_FAILED'); (uint amountAMBV1, uint amountTokenV1) = exchangeV1.removeLiquidity(liquidityV1, 1, 1, uint(-1)); TransferHelper.safeApprove(token, address(router), amountTokenV1); (uint amountTokenV2, uint amountAMBV2,) = router.addLiquidityAMB{value: amountAMBV1}( token, amountTokenV1, amountTokenMin, amountAMBMin, to, deadline ); if (amountTokenV1 > amountTokenV2) { TransferHelper.safeApprove(token, address(router), 0); // be a good blockchain citizen, reset allowance to 0 TransferHelper.safeTransfer(token, msg.sender, amountTokenV1 - amountTokenV2); } else if (amountAMBV1 > amountAMBV2) { // addLiquidityAMB guarantees that all of amountAMBV1 or amountTokenV1 will be used, hence this else is safe TransferHelper.safeTransferAMB(msg.sender, amountAMBV1 - amountAMBV2); } } }