finish ERC20/ERC20
This commit is contained in:
@ -1,8 +1,6 @@
|
||||
pragma solidity ^0.5.11;
|
||||
import './ERC20.sol';
|
||||
import './interfaces/IERC20.sol';
|
||||
import './interfaces/IUniswapERC20Factory.sol';
|
||||
|
||||
|
||||
contract UniswapERC20 is ERC20 {
|
||||
|
||||
@ -14,9 +12,9 @@ contract UniswapERC20 is ERC20 {
|
||||
string public name; // Uniswap V2
|
||||
string public symbol; // UNI-V2
|
||||
uint256 public decimals; // 18
|
||||
IERC20 tokenA; // ERC20 token traded on this contract
|
||||
IERC20 tokenB; // ERC20 token traded on this contract
|
||||
IUniswapFactory factory; // factory that created this contract
|
||||
address public tokenA; // ERC20 token traded on this contract
|
||||
address public tokenB; // ERC20 token traded on this contract
|
||||
address public factoryAddress; // factory that created this contract
|
||||
|
||||
bool private rentrancyLock = false;
|
||||
|
||||
@ -30,9 +28,9 @@ contract UniswapERC20 is ERC20 {
|
||||
|
||||
constructor(address _tokenA, address _tokenB) public {
|
||||
require(address(_tokenA) != address(0) && _tokenB != address(0), 'INVALID_ADDRESS');
|
||||
factory = IUniswapFactory(msg.sender);
|
||||
tokenA = IERC20(_tokenA);
|
||||
tokenB = IERC20(_tokenB);
|
||||
factoryAddress = msg.sender;
|
||||
tokenA = _tokenA;
|
||||
tokenB = _tokenB;
|
||||
name = 'Uniswap V2';
|
||||
symbol = 'UNI-V2';
|
||||
decimals = 18;
|
||||
@ -61,185 +59,154 @@ contract UniswapERC20 is ERC20 {
|
||||
return (numerator / denominator).add(1);
|
||||
}
|
||||
|
||||
function ethToTokenInput(uint256 ethSold, uint256 minTokens, uint256 deadline, address buyer, address recipient) private nonReentrant returns (uint256) {
|
||||
require(deadline >= block.timestamp && ethSold > 0 && minTokens > 0);
|
||||
uint256 tokenReserve = token.balanceOf(address(this));
|
||||
uint256 tokensBought = getInputPrice(ethSold, address(this).balance.sub(ethSold), tokenReserve);
|
||||
require(tokensBought >= minTokens);
|
||||
require(token.transfer(recipient, tokensBought));
|
||||
emit TokenPurchase(buyer, ethSold, tokensBought);
|
||||
return tokensBought;
|
||||
|
||||
//TO: DO msg.sender is wrapper
|
||||
function swapInput(address inputToken, uint256 amountSold, address recipient) public nonReentrant returns (uint256) {
|
||||
address _tokenA = address(tokenA);
|
||||
address _tokenB = address(tokenB);
|
||||
bool inputIsA = inputToken == _tokenA;
|
||||
require(inputIsA || inputToken == _tokenB);
|
||||
address outputToken = _tokenA;
|
||||
if(inputIsA) {
|
||||
outputToken == _tokenB;
|
||||
}
|
||||
|
||||
uint256 inputReserve = IERC20(inputToken).balanceOf(address(this));
|
||||
uint256 outputReserve = IERC20(outputToken).balanceOf(address(this));
|
||||
uint256 amountBought = getInputPrice(amountSold, inputReserve, outputReserve);
|
||||
require(IERC20(inputToken).transferFrom(msg.sender, address(this), amountSold));
|
||||
require(IERC20(outputToken).transfer(recipient, amountBought));
|
||||
|
||||
if(inputIsA) {
|
||||
emit SwapAForB(msg.sender, amountSold, amountBought);
|
||||
} else {
|
||||
emit SwapBForA(msg.sender, amountSold, amountBought);
|
||||
}
|
||||
|
||||
return amountBought;
|
||||
}
|
||||
|
||||
|
||||
function ethToTokenSwapInput(uint256 minTokens, uint256 deadline) public payable returns (uint256) {
|
||||
return ethToTokenInput(msg.value, minTokens, deadline, msg.sender, msg.sender);
|
||||
//TO: DO msg.sender is wrapper
|
||||
function swapOutput(address outputToken, uint256 amountBought, address recipient) public nonReentrant returns (uint256) {
|
||||
address _tokenA = address(tokenA);
|
||||
address _tokenB = address(tokenB);
|
||||
bool outputIsA = outputToken == _tokenA;
|
||||
require(outputIsA || outputToken == _tokenB);
|
||||
address inputToken = _tokenA;
|
||||
if(outputIsA) {
|
||||
inputToken == _tokenB;
|
||||
}
|
||||
|
||||
uint256 inputReserve = IERC20(inputToken).balanceOf(address(this));
|
||||
uint256 outputReserve = IERC20(outputToken).balanceOf(address(this));
|
||||
uint256 amountSold = getOutputPrice(amountBought, inputReserve, outputReserve);
|
||||
require(IERC20(inputToken).transferFrom(msg.sender, address(this), amountSold));
|
||||
require(IERC20(outputToken).transfer(recipient, amountBought));
|
||||
|
||||
if(outputIsA) {
|
||||
emit SwapBForA(msg.sender, amountSold, amountBought);
|
||||
} else {
|
||||
emit SwapAForB(msg.sender, amountSold, amountBought);
|
||||
}
|
||||
|
||||
return amountSold;
|
||||
}
|
||||
|
||||
|
||||
function ethToTokenTransferInput(uint256 minTokens, uint256 deadline, address recipient) public payable returns(uint256) {
|
||||
require(recipient != address(this) && recipient != address(0));
|
||||
return ethToTokenInput(msg.value, minTokens, deadline, msg.sender, recipient);
|
||||
}
|
||||
|
||||
function ethToTokenOutput(uint256 tokensBought, uint256 maxEth, uint256 deadline, address payable buyer, address recipient) private nonReentrant returns (uint256) {
|
||||
require(deadline >= block.timestamp && tokensBought > 0 && maxEth > 0);
|
||||
uint256 tokenReserve = token.balanceOf(address(this));
|
||||
uint256 ethSold = getOutputPrice(tokensBought, address(this).balance.sub(maxEth), tokenReserve);
|
||||
// Throws if ethSold > maxEth
|
||||
uint256 ethRefund = maxEth.sub(ethSold);
|
||||
if (ethRefund > 0) {
|
||||
buyer.transfer(ethRefund);
|
||||
function getInputPrice(address inputToken, uint256 amountSold) public view returns (uint256) {
|
||||
require(amountSold > 0);
|
||||
address _tokenA = address(tokenA);
|
||||
address _tokenB = address(tokenB);
|
||||
require(inputToken == _tokenA || inputToken == _tokenB);
|
||||
address outputToken = _tokenA;
|
||||
if(inputToken == _tokenA) {
|
||||
outputToken = _tokenB;
|
||||
}
|
||||
require(token.transfer(recipient, tokensBought));
|
||||
emit TokenPurchase(buyer, ethSold, tokensBought);
|
||||
return ethSold;
|
||||
uint256 inputReserve = IERC20(inputToken).balanceOf(address(this));
|
||||
uint256 outputReserve = IERC20(outputToken).balanceOf(address(this));
|
||||
return getInputPrice(amountSold, inputReserve, outputReserve);
|
||||
}
|
||||
|
||||
|
||||
function ethToTokenSwapOutput(uint256 tokensBought, uint256 deadline) public payable returns(uint256) {
|
||||
return ethToTokenOutput(tokensBought, msg.value, deadline, msg.sender, msg.sender);
|
||||
function getOutputPrice(address outputToken, uint256 amountBought) public view returns (uint256) {
|
||||
require(amountBought > 0);
|
||||
address _tokenA = address(tokenA);
|
||||
address _tokenB = address(tokenB);
|
||||
require(outputToken == _tokenA || outputToken == _tokenB);
|
||||
address inputToken = _tokenA;
|
||||
if(outputToken == _tokenA) {
|
||||
inputToken = _tokenB;
|
||||
}
|
||||
uint256 inputReserve = IERC20(inputToken).balanceOf(address(this));
|
||||
uint256 outputReserve = IERC20(outputToken).balanceOf(address(this));
|
||||
return getOutputPrice(amountBought, inputReserve, outputReserve);
|
||||
}
|
||||
|
||||
|
||||
function ethToTokenTransferOutput(uint256 tokensBought, uint256 deadline, address recipient) public payable returns (uint256) {
|
||||
require(recipient != address(this) && recipient != address(0));
|
||||
return ethToTokenOutput(tokensBought, msg.value, deadline, msg.sender, recipient);
|
||||
}
|
||||
|
||||
function tokenToEthInput(uint256 tokensSold, uint256 minEth, uint256 deadline, address buyer, address payable recipient) private nonReentrant returns (uint256) {
|
||||
require(deadline >= block.timestamp && tokensSold > 0 && minEth > 0);
|
||||
uint256 tokenReserve = token.balanceOf(address(this));
|
||||
uint256 ethBought = getInputPrice(tokensSold, tokenReserve, address(this).balance);
|
||||
require(ethBought >= minEth);
|
||||
recipient.transfer(ethBought);
|
||||
require(token.transferFrom(buyer, address(this), tokensSold));
|
||||
emit EthPurchase(buyer, tokensSold, ethBought);
|
||||
return ethBought;
|
||||
function tokenAAddress() public view returns (address) {
|
||||
return address(tokenA);
|
||||
}
|
||||
|
||||
|
||||
function tokenToEthSwapInput(uint256 tokensSold, uint256 minEth, uint256 deadline) public returns (uint256) {
|
||||
return tokenToEthInput(tokensSold, minEth, deadline, msg.sender, msg.sender);
|
||||
function tokenBAddress() public view returns (address) {
|
||||
return address(tokenB);
|
||||
}
|
||||
|
||||
|
||||
function tokenToEthTransferInput(uint256 tokensSold, uint256 minEth, uint256 deadline, address payable recipient) public returns (uint256) {
|
||||
require(recipient != address(this) && recipient != address(0));
|
||||
return tokenToEthInput(tokensSold, minEth, deadline, msg.sender, recipient);
|
||||
}
|
||||
function addLiquidity(uint256 amountA, uint256 maxTokenB, uint256 minLiquidity) public nonReentrant returns (uint256) {
|
||||
require(amountA > 0 && maxTokenB > 0);
|
||||
uint256 _totalSupply = totalSupply;
|
||||
address _tokenA = tokenA;
|
||||
address _tokenB = tokenB;
|
||||
|
||||
function tokenToEthOutput(uint256 ethBought, uint256 maxTokens, uint256 deadline, address buyer, address payable recipient) private nonReentrant returns (uint256) {
|
||||
require(deadline >= block.timestamp && ethBought > 0);
|
||||
uint256 tokenReserve = token.balanceOf(address(this));
|
||||
uint256 tokensSold = getOutputPrice(ethBought, tokenReserve, address(this).balance);
|
||||
// tokens sold is always > 0
|
||||
require(maxTokens >= tokensSold);
|
||||
recipient.transfer(ethBought);
|
||||
require(token.transferFrom(buyer, address(this), tokensSold));
|
||||
emit EthPurchase(buyer, tokensSold, ethBought);
|
||||
return tokensSold;
|
||||
}
|
||||
|
||||
|
||||
function tokenToEthSwapOutput(uint256 ethBought, uint256 maxTokens, uint256 deadline) public returns (uint256) {
|
||||
return tokenToEthOutput(ethBought, maxTokens, deadline, msg.sender, msg.sender);
|
||||
}
|
||||
|
||||
|
||||
function tokenToEthTransferOutput(uint256 ethBought, uint256 maxTokens, uint256 deadline, address payable recipient) public returns (uint256) {
|
||||
require(recipient != address(this) && recipient != address(0));
|
||||
return tokenToEthOutput(ethBought, maxTokens, deadline, msg.sender, recipient);
|
||||
}
|
||||
|
||||
|
||||
function getEthToTokenInputPrice(uint256 ethSold) public view returns (uint256) {
|
||||
require(ethSold > 0);
|
||||
uint256 tokenReserve = token.balanceOf(address(this));
|
||||
return getInputPrice(ethSold, address(this).balance, tokenReserve);
|
||||
}
|
||||
|
||||
|
||||
function getEthToTokenOutputPrice(uint256 tokensBought) public view returns (uint256) {
|
||||
require(tokensBought > 0);
|
||||
uint256 tokenReserve = token.balanceOf(address(this));
|
||||
uint256 ethSold = getOutputPrice(tokensBought, address(this).balance, tokenReserve);
|
||||
return ethSold;
|
||||
}
|
||||
|
||||
|
||||
function getTokenToEthInputPrice(uint256 tokensSold) public view returns (uint256) {
|
||||
require(tokensSold > 0);
|
||||
uint256 tokenReserve = token.balanceOf(address(this));
|
||||
uint256 ethBought = getInputPrice(tokensSold, tokenReserve, address(this).balance);
|
||||
return ethBought;
|
||||
}
|
||||
|
||||
|
||||
function getTokenToEthOutputPrice(uint256 ethBought) public view returns (uint256) {
|
||||
require(ethBought > 0);
|
||||
uint256 tokenReserve = token.balanceOf(address(this));
|
||||
return getOutputPrice(ethBought, tokenReserve, address(this).balance);
|
||||
}
|
||||
|
||||
|
||||
function tokenAddress() public view returns (address) {
|
||||
return address(token);
|
||||
}
|
||||
|
||||
|
||||
function factoryAddress() public view returns (address) {
|
||||
return address(factory);
|
||||
}
|
||||
|
||||
|
||||
function addLiquidity(uint256 minLiquidity, uint256 maxTokens, uint256 deadline) public payable nonReentrant returns (uint256) {
|
||||
require(deadline >= block.timestamp && maxTokens > 0 && msg.value > 0, 'INVALID_INPUT');
|
||||
uint256 totalLiquidity = totalSupply;
|
||||
|
||||
if (totalLiquidity > 0) {
|
||||
if (_totalSupply > 0) {
|
||||
require(minLiquidity > 0);
|
||||
uint256 ethReserve = address(this).balance.sub(msg.value);
|
||||
uint256 tokenReserve = token.balanceOf(address(this));
|
||||
uint256 tokenAmount = (msg.value.mul(tokenReserve) / ethReserve).add(1);
|
||||
uint256 liquidityMinted = msg.value.mul(totalLiquidity) / ethReserve;
|
||||
require(maxTokens >= tokenAmount && liquidityMinted >= minLiquidity);
|
||||
|
||||
uint256 reserveA = IERC20(_tokenA).balanceOf(address(this));
|
||||
uint256 reserveB = IERC20(_tokenB).balanceOf(address(this));
|
||||
uint256 amountB = (amountA.mul(reserveB) / reserveA).add(1);
|
||||
uint256 liquidityMinted = amountA.mul(_totalSupply) / reserveA;
|
||||
require(maxTokenB >= amountB && liquidityMinted >= minLiquidity);
|
||||
balanceOf[msg.sender] = balanceOf[msg.sender].add(liquidityMinted);
|
||||
totalSupply = totalLiquidity.add(liquidityMinted);
|
||||
require(token.transferFrom(msg.sender, address(this), tokenAmount));
|
||||
emit AddLiquidity(msg.sender, msg.value, tokenAmount);
|
||||
totalSupply = _totalSupply.add(liquidityMinted);
|
||||
require(IERC20(_tokenA).transferFrom(msg.sender, address(this), amountA));
|
||||
require(IERC20(_tokenB).transferFrom(msg.sender, address(this), amountB));
|
||||
emit AddLiquidity(msg.sender, amountA, amountB);
|
||||
emit Transfer(address(0), msg.sender, liquidityMinted);
|
||||
return liquidityMinted;
|
||||
|
||||
} else {
|
||||
require(msg.value >= 1000000000, 'INVALID_VALUE');
|
||||
require(factory.getExchange(address(token)) == address(this));
|
||||
uint256 tokenAmount = maxTokens;
|
||||
uint256 initialLiquidity = address(this).balance;
|
||||
// TODO: figure out how to set this safely
|
||||
// arithemtic or geometric mean?
|
||||
uint256 initialLiquidity = amountA;
|
||||
totalSupply = initialLiquidity;
|
||||
balanceOf[msg.sender] = initialLiquidity;
|
||||
require(token.transferFrom(msg.sender, address(this), tokenAmount));
|
||||
emit AddLiquidity(msg.sender, msg.value, tokenAmount);
|
||||
require(IERC20(_tokenA).transferFrom(msg.sender, address(this), amountA));
|
||||
require(IERC20(_tokenB).transferFrom(msg.sender, address(this), maxTokenB));
|
||||
emit AddLiquidity(msg.sender, amountA, maxTokenB);
|
||||
emit Transfer(address(0), msg.sender, initialLiquidity);
|
||||
return initialLiquidity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function removeLiquidity(uint256 amount, uint256 minEth, uint256 minTokens, uint256 deadline) public nonReentrant returns (uint256, uint256) {
|
||||
require(amount > 0 && deadline >= block.timestamp && minEth > 0 && minTokens > 0);
|
||||
uint256 totalLiquidity = totalSupply;
|
||||
require(totalLiquidity > 0);
|
||||
uint256 tokenReserve = token.balanceOf(address(this));
|
||||
uint256 ethAmount = amount.mul(address(this).balance) / totalLiquidity;
|
||||
uint256 tokenAmount = amount.mul(tokenReserve) / totalLiquidity;
|
||||
require(ethAmount >= minEth && tokenAmount >= minTokens);
|
||||
function removeLiquidity(uint256 amount, uint256 minTokenA, uint256 minTokenB) public nonReentrant returns (uint256, uint256) {
|
||||
uint256 _totalSupply = totalSupply;
|
||||
require(amount > 0 && minTokenA > 0 && minTokenB > 0 && _totalSupply > 0);
|
||||
address _tokenA = tokenA;
|
||||
address _tokenB = tokenB;
|
||||
uint256 reserveA = IERC20(_tokenA).balanceOf(address(this));
|
||||
uint256 reserveB = IERC20(_tokenB).balanceOf(address(this));
|
||||
uint256 tokenAAmount = amount.mul(reserveA) / _totalSupply;
|
||||
uint256 tokenBAmount = amount.mul(reserveB) / _totalSupply;
|
||||
require(tokenAAmount >= minTokenA && tokenBAmount >= minTokenB);
|
||||
balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount);
|
||||
totalSupply = totalLiquidity.sub(amount);
|
||||
msg.sender.transfer(ethAmount);
|
||||
require(token.transfer(msg.sender, tokenAmount));
|
||||
emit RemoveLiquidity(msg.sender, ethAmount, tokenAmount);
|
||||
totalSupply = _totalSupply.sub(amount);
|
||||
require(IERC20(_tokenA).transfer(msg.sender, tokenAAmount));
|
||||
require(IERC20(_tokenB).transfer(msg.sender, tokenBAmount));
|
||||
emit RemoveLiquidity(msg.sender, tokenAAmount, tokenBAmount);
|
||||
emit Transfer(msg.sender, address(0), amount);
|
||||
return (ethAmount, tokenAmount);
|
||||
return (tokenAAmount, tokenBAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,11 +20,11 @@ contract UniswapERC20Factory {
|
||||
require(token1 != address(0) && token2 != address(0) && token1 != token2);
|
||||
require(setExchange[token1][token2] == address(0), 'EXCHANGE_EXISTS');
|
||||
|
||||
address tokenA = token1
|
||||
address tokenB = token2
|
||||
address tokenA = token1;
|
||||
address tokenB = token2;
|
||||
if(uint256(token2) < uint256(token1)) {
|
||||
tokenA = token2
|
||||
tokenB = token1
|
||||
tokenA = token2;
|
||||
tokenB = token1;
|
||||
}
|
||||
|
||||
UniswapERC20 exchange = new UniswapERC20(tokenA, tokenB);
|
||||
@ -34,7 +34,7 @@ contract UniswapERC20Factory {
|
||||
|
||||
uint256 exchangeId = exchangeCount + 1;
|
||||
exchangeCount = exchangeId;
|
||||
getExchangeWithId[exchangeId] = exchangeId;
|
||||
getExchangeWithId[exchangeId] = address(exchange);
|
||||
|
||||
emit NewERC20Exchange(tokenA, tokenB, address(exchange));
|
||||
return address(exchange);
|
||||
|
||||
Reference in New Issue
Block a user