Skip to content

Commit

Permalink
initial migration to solc@0.6.6 (Uniswap#10)
Browse files Browse the repository at this point in the history
* initial migration to solc@0.6.6

* make syntax consistent

* switch back to using published build artifacts
  • Loading branch information
NoahZinsmeister committed Apr 17, 2020
1 parent 0b08acb commit 1d6faef
Show file tree
Hide file tree
Showing 23 changed files with 133 additions and 137 deletions.
21 changes: 10 additions & 11 deletions contracts/ExampleFlashSwap.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity =0.5.16;
pragma solidity =0.6.6;

import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Callee.sol';

Expand All @@ -10,21 +10,20 @@ import './interfaces/IERC20.sol';
import './interfaces/IWETH.sol';

contract ExampleFlashSwap is IUniswapV2Callee, UniswapV2Library {
IUniswapV1Factory public factoryV1;
IWETH public WETH;
IUniswapV1Factory immutable factoryV1;
IWETH immutable WETH;

constructor(address _factoryV1) public {
constructor(address _factory, address _factoryV1, address router) UniswapV2Library(_factory) public {
factoryV1 = IUniswapV1Factory(_factoryV1);
// router address is identical across mainnet and testnets but differs between testing and deployed environments
WETH = IWETH(IUniswapV2Router01(0x84e924C5E04438D2c1Df1A981f7E7104952e6de1).WETH());
WETH = IWETH(IUniswapV2Router01(router).WETH());
}

// needs to accept ETH from any V1 exchange and WETH. 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
function() external payable {}
receive() external payable {}

// gets tokens/WETH via a V2 flash swap, swaps for the ETH/tokens on V1, repays V2, and keeps the rest!
function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external {
function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external override {
address[] memory path = new address[](2);
uint amountToken;
uint amountETH;
Expand All @@ -49,14 +48,14 @@ contract ExampleFlashSwap is IUniswapV2Callee, UniswapV2Library {
uint amountReceived = exchangeV1.tokenToEthSwapInput(amountToken, minETH, uint(-1));
uint amountRequired = getAmountsIn(amountToken, path)[0];
assert(amountReceived > amountRequired); // fail if we didn't get enough ETH back to repay our flash loan
WETH.deposit.value(amountRequired)();
WETH.deposit{value: amountRequired}();
assert(WETH.transfer(msg.sender, amountRequired)); // return WETH to V2 pair
(bool success,) = sender.call.value(amountReceived - amountRequired)(new bytes(0)); // keep the rest! (ETH)
(bool success,) = sender.call{value: amountReceived - amountRequired}(new bytes(0)); // keep the rest! (ETH)
assert(success);
} else {
(uint minTokens) = abi.decode(data, (uint)); // slippage parameter for V1, passed in by caller
WETH.withdraw(amountETH);
uint amountReceived = exchangeV1.ethToTokenSwapInput.value(amountETH)(minTokens, uint(-1));
uint amountReceived = exchangeV1.ethToTokenSwapInput{value: amountETH}(minTokens, uint(-1));
uint amountRequired = getAmountsIn(amountETH, path)[0];
assert(amountReceived > amountRequired); // fail if we didn't get enough tokens back to repay our flash loan
assert(token.transfer(msg.sender, amountRequired)); // return tokens to V2 pair
Expand Down
29 changes: 17 additions & 12 deletions contracts/ExampleOracleSimple.sol
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
pragma solidity =0.5.16;
pragma solidity =0.6.6;

import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';

import './UniswapV2Library.sol';
import './libraries/UQ112x112.sol';

contract ExampleOracleSimple is UniswapV2Library {
contract ExampleOracleSimple {
using UQ112x112 for uint224;

uint public constant PERIOD = 24 hours;
address public token0;
address public token1;
IUniswapV2Pair public pair;

IUniswapV2Pair immutable pair;
address public immutable token0;
address public immutable token1;

uint public price0CumulativeLast;
uint public price1CumulativeLast;
uint32 public blockTimestampLast;
uint224 public price0Average;
uint224 public price1Average;

constructor(address tokenA, address tokenB) public {
(token0, token1) = sortTokens(tokenA, tokenB);
pair = IUniswapV2Pair(pairFor(token0, token1));
price0CumulativeLast = pair.price0CumulativeLast(); // fetch the current accumulated price value (1 / 0)
price1CumulativeLast = pair.price1CumulativeLast(); // fetch the current accumulated price value (0 / 1)
constructor(address factory, address tokenA, address tokenB) public {
IUniswapV2Pair _pair = IUniswapV2Pair(IUniswapV2Factory(factory).getPair(tokenA, tokenB));
pair = _pair;
token0 = _pair.token0();
token1 = _pair.token1();
price0CumulativeLast = _pair.price0CumulativeLast(); // fetch the current accumulated price value (1 / 0)
price1CumulativeLast = _pair.price1CumulativeLast(); // fetch the current accumulated price value (0 / 1)
uint112 reserve0;
uint112 reserve1;
(reserve0, reserve1, blockTimestampLast) = pair.getReserves();
(reserve0, reserve1, blockTimestampLast) = _pair.getReserves();
assert(reserve0 != 0 && reserve1 != 0); // ensure that there's liquidity in the pair
assert(blockTimestampLast != 0); // ensure there's a price history
}
Expand Down
24 changes: 13 additions & 11 deletions contracts/UniswapV2Library.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
pragma solidity =0.5.16;
pragma solidity =0.6.6;

import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';

import './interfaces/IUniswapV2Library.sol';
Expand All @@ -9,8 +8,11 @@ import './libraries/SafeMath.sol';
contract UniswapV2Library is IUniswapV2Library {
using SafeMath for uint;

// factory address is identical across mainnet and testnets but differs between testing and deployed environments
IUniswapV2Factory public constant factory = IUniswapV2Factory(0xdCCc660F92826649754E357b11bd41C31C0609B9);
address public immutable override factory;

constructor(address _factory) public {
factory = _factory;
}

// returns sorted token addresses, used to handle return values from pairs sorted in this order
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
Expand All @@ -20,13 +22,13 @@ contract UniswapV2Library is IUniswapV2Library {
}

// calculates the CREATE2 address for a pair without making any external calls
function pairFor(address tokenA, address tokenB) internal pure returns (address pair) {
function pairFor(address tokenA, address tokenB) internal view returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(uint(keccak256(abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'0b77fb54a078d9399fa29cac94f5b35b9f11611b456ab507c7f46754712b642b' // init code hash
hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash
))));
}

Expand All @@ -38,14 +40,14 @@ contract UniswapV2Library is IUniswapV2Library {
}

// given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
function quote(uint amountA, uint reserveA, uint reserveB) public pure returns (uint amountB) {
function quote(uint amountA, uint reserveA, uint reserveB) public pure override returns (uint amountB) {
require(amountA > 0, 'UniswapV2Helper: INSUFFICIENT_AMOUNT');
require(reserveA > 0 && reserveB > 0, 'UniswapV2Helper: INSUFFICIENT_LIQUIDITY');
amountB = amountA.mul(reserveB) / reserveA;
}

// given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) public pure returns (uint amountOut) {
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) public pure override returns (uint amountOut) {
require(amountIn > 0, 'UniswapV2Helper: INSUFFICIENT_INPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Helper: INSUFFICIENT_LIQUIDITY');
uint amountInWithFee = amountIn.mul(997);
Expand All @@ -55,7 +57,7 @@ contract UniswapV2Library is IUniswapV2Library {
}

// given an output amount of an asset and pair reserves, returns a required input amount of the other asset
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) public pure returns (uint amountIn) {
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) public pure override returns (uint amountIn) {
require(amountOut > 0, 'UniswapV2Helper: INSUFFICIENT_OUTPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Helper: INSUFFICIENT_LIQUIDITY');
uint numerator = reserveIn.mul(amountOut).mul(1000);
Expand All @@ -64,7 +66,7 @@ contract UniswapV2Library is IUniswapV2Library {
}

// performs chained getAmountOut calculations on any number of pairs
function getAmountsOut(uint amountIn, address[] memory path) public view returns (uint[] memory amounts) {
function getAmountsOut(uint amountIn, address[] memory path) public view override returns (uint[] memory amounts) {
require(path.length >= 2, 'UniswapV2Helper: INVALID_PATH');
amounts = new uint[](path.length);
amounts[0] = amountIn;
Expand All @@ -75,7 +77,7 @@ contract UniswapV2Library is IUniswapV2Library {
}

// performs chained getAmountIn calculations on any number of pairs
function getAmountsIn(uint amountOut, address[] memory path) public view returns (uint[] memory amounts) {
function getAmountsIn(uint amountOut, address[] memory path) public view override returns (uint[] memory amounts) {
require(path.length >= 2, 'UniswapV2Helper: INVALID_PATH');
amounts = new uint[](path.length);
amounts[amounts.length - 1] = amountOut;
Expand Down
21 changes: 12 additions & 9 deletions contracts/UniswapV2Migrator.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity =0.5.16;
pragma solidity =0.6.6;

import './interfaces/IUniswapV2Migrator.sol';
import './interfaces/V1/IUniswapV1Factory.sol';
Expand All @@ -7,9 +7,8 @@ import './interfaces/IUniswapV2Router01.sol';
import './interfaces/IERC20.sol';

contract UniswapV2Migrator is IUniswapV2Migrator {
IUniswapV1Factory public factoryV1;
// router address is identical across mainnet and testnets but differs between testing and deployed environments
IUniswapV2Router01 public constant router = IUniswapV2Router01(0x84e924C5E04438D2c1Df1A981f7E7104952e6de1);
IUniswapV1Factory immutable factoryV1;
IUniswapV2Router01 immutable router;

function _safeApprove(address token, address to, uint value) private {
// bytes4(keccak256(bytes('approve(address,uint256)')));
Expand All @@ -24,25 +23,29 @@ contract UniswapV2Migrator is IUniswapV2Migrator {
}

function _safeTransferETH(address to, uint value) private {
(bool success,) = to.call.value(value)(new bytes(0));
(bool success,) = to.call{value: value}(new bytes(0));
require(success, 'ETH_TRANSFER_FAILED');
}

constructor(address _factoryV1) public {
constructor(address _factoryV1, address _router) public {
factoryV1 = IUniswapV1Factory(_factoryV1);
router = IUniswapV2Router01(_router);
}

// needs to accept ETH 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
function() external payable {}
receive() external payable {}

function migrate(address token, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external {
function migrate(address token, uint amountTokenMin, uint amountETHMin, address to, uint deadline)
external
override
{
IUniswapV1Exchange exchangeV1 = IUniswapV1Exchange(factoryV1.getExchange(token));
uint liquidityV1 = exchangeV1.balanceOf(msg.sender);
require(exchangeV1.transferFrom(msg.sender, address(this), liquidityV1), 'TRANSFER_FROM_FAILED');
(uint amountETHV1, uint amountTokenV1) = exchangeV1.removeLiquidity(liquidityV1, 1, 1, uint(-1));
_safeApprove(token, address(router), amountTokenV1);
(uint amountTokenV2, uint amountETHV2,) = router.addLiquidityETH.value(amountETHV1)(
(uint amountTokenV2, uint amountETHV2,) = router.addLiquidityETH{value: amountETHV1}(
token,
amountTokenV1,
amountTokenMin,
Expand Down
Loading

0 comments on commit 1d6faef

Please sign in to comment.