finish initial contracts
This commit is contained in:
45
contracts/ERC20.sol
Normal file
45
contracts/ERC20.sol
Normal file
@ -0,0 +1,45 @@
|
||||
pragma solidity ^0.5.11;
|
||||
import "./SafeMath.sol";
|
||||
|
||||
|
||||
contract ERC20 {
|
||||
using SafeMath for uint256;
|
||||
|
||||
mapping (address => uint256) public balanceOf;
|
||||
mapping (address => mapping (address => uint256)) public allowance;
|
||||
|
||||
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||
event Approval(address indexed owner, address indexed spender, uint256 value);
|
||||
|
||||
uint256 public totalSupply;
|
||||
uint256 internal constant MAX_UINT256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
|
||||
|
||||
function transfer(address to, uint256 value) public returns (bool) {
|
||||
balanceOf[msg.sender] = balanceOf[msg.sender].sub(value);
|
||||
balanceOf[to] = balanceOf[to].add(value);
|
||||
emit Transfer(msg.sender, to, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function transferFrom(address from, address to, uint256 value) public returns (bool) {
|
||||
if (allowance[from][msg.sender] < MAX_UINT256) {
|
||||
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
|
||||
}
|
||||
balanceOf[from] = balanceOf[from].sub(value);
|
||||
balanceOf[to] = balanceOf[to].add(value);
|
||||
emit Transfer(from, to, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function approve(address spender, uint256 value) public returns (bool) {
|
||||
allowance[msg.sender][spender] = value;
|
||||
emit Approval(msg.sender, spender, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function burn(uint256 value) public {
|
||||
totalSupply = totalSupply.sub(value);
|
||||
balanceOf[msg.sender] = balanceOf[msg.sender].sub(value);
|
||||
emit Transfer(msg.sender, address(0), value);
|
||||
}
|
||||
}
|
||||
40
contracts/SafeMath.sol
Normal file
40
contracts/SafeMath.sol
Normal file
@ -0,0 +1,40 @@
|
||||
pragma solidity ^0.5.11;
|
||||
|
||||
library SafeMath {
|
||||
|
||||
function add(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
uint256 c = a + b;
|
||||
require(c >= a, "SafeMath: addition overflow");
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
require(b <= a, "SafeMath: subtraction overflow");
|
||||
uint256 c = a - b;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
|
||||
// benefit is lost if 'b' is also tested.
|
||||
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
uint256 c = a * b;
|
||||
require(c / a == b, "SafeMath: multiplication overflow");
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
function div(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
// Solidity only automatically asserts when dividing by 0
|
||||
require(b > 0, "SafeMath: division by zero");
|
||||
uint256 c = a / b;
|
||||
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
344
contracts/UniswapExchange.sol
Normal file
344
contracts/UniswapExchange.sol
Normal file
@ -0,0 +1,344 @@
|
||||
pragma solidity ^0.5.11;
|
||||
import './ERC20.sol';
|
||||
import './interfaces/IERC20.sol';
|
||||
import './interfaces/IUniswapFactory.sol';
|
||||
import './interfaces/IUniswapExchange.sol';
|
||||
|
||||
|
||||
contract UniswapExchange is ERC20 {
|
||||
|
||||
event TokenPurchase(address indexed buyer, uint256 indexed ethSold, uint256 indexed tokensBought);
|
||||
event EthPurchase(address indexed buyer, uint256 indexed tokensSold, uint256 indexed ethBought);
|
||||
event AddLiquidity(address indexed provider, uint256 indexed ethAmount, uint256 indexed tokenAmount);
|
||||
event RemoveLiquidity(address indexed provider, uint256 indexed ethAmount, uint256 indexed tokenAmount);
|
||||
|
||||
string public name; // Uniswap V1
|
||||
string public symbol; // UNI-V1
|
||||
uint256 public decimals; // 18
|
||||
IERC20 token; // address of the ERC20 token traded on this contract
|
||||
IUniswapFactory factory; // interface for the factory that created this contract
|
||||
|
||||
bool private rentrancyLock = false;
|
||||
|
||||
modifier nonReentrant() {
|
||||
require(!rentrancyLock);
|
||||
rentrancyLock = true;
|
||||
_;
|
||||
rentrancyLock = false;
|
||||
}
|
||||
|
||||
|
||||
constructor(address tokenAddr) public {
|
||||
require(
|
||||
address(factory) == address(0) && address(token) == address(0) && tokenAddr != address(0),
|
||||
'INVALID_ADDRESS'
|
||||
);
|
||||
factory = IUniswapFactory(msg.sender);
|
||||
token = IERC20(tokenAddr);
|
||||
name = 'Uniswap V2';
|
||||
symbol = 'UNI-V2';
|
||||
decimals = 18;
|
||||
}
|
||||
|
||||
|
||||
function () external payable {
|
||||
ethToTokenInput(msg.value, 1, block.timestamp, msg.sender, msg.sender);
|
||||
}
|
||||
|
||||
|
||||
function getInputPrice(uint256 inputAmount, uint256 inputReserve, uint256 outputReserve) public pure returns (uint256) {
|
||||
require(inputReserve > 0 && outputReserve > 0, 'INVALID_VALUE');
|
||||
uint256 inputAmountWithFee = inputAmount.mul(997);
|
||||
uint256 numerator = inputAmountWithFee.mul(outputReserve);
|
||||
uint256 denominator = inputReserve.mul(1000).add(inputAmountWithFee);
|
||||
return numerator / denominator;
|
||||
}
|
||||
|
||||
|
||||
function getOutputPrice(uint256 outputAmount, uint256 inputReserve, uint256 outputReserve) public pure returns (uint256) {
|
||||
require(inputReserve > 0 && outputReserve > 0);
|
||||
uint256 numerator = inputReserve.mul(outputAmount).mul(1000);
|
||||
uint256 denominator = (outputReserve.sub(outputAmount)).mul(997);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
function ethToTokenSwapInput(uint256 minTokens, uint256 deadline) public payable returns (uint256) {
|
||||
return ethToTokenInput(msg.value, minTokens, deadline, msg.sender, msg.sender);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
require(token.transfer(recipient, tokensBought));
|
||||
emit TokenPurchase(buyer, ethSold, tokensBought);
|
||||
return ethSold;
|
||||
}
|
||||
|
||||
|
||||
function ethToTokenSwapOutput(uint256 tokensBought, uint256 deadline) public payable returns(uint256) {
|
||||
return ethToTokenOutput(tokensBought, msg.value, deadline, msg.sender, msg.sender);
|
||||
}
|
||||
|
||||
|
||||
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 tokenToEthSwapInput(uint256 tokensSold, uint256 minEth, uint256 deadline) public returns (uint256) {
|
||||
return tokenToEthInput(tokensSold, minEth, deadline, msg.sender, msg.sender);
|
||||
}
|
||||
|
||||
|
||||
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 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 tokenToTokenInput(
|
||||
uint256 tokensSold,
|
||||
uint256 minTokensBought,
|
||||
uint256 minEthBought,
|
||||
uint256 deadline,
|
||||
address buyer,
|
||||
address recipient,
|
||||
address payable exchangeAddr)
|
||||
private nonReentrant returns (uint256)
|
||||
{
|
||||
require(deadline >= block.timestamp && tokensSold > 0 && minTokensBought > 0 && minEthBought > 0);
|
||||
require(exchangeAddr != address(this) && exchangeAddr != address(0));
|
||||
uint256 tokenReserve = token.balanceOf(address(this));
|
||||
uint256 ethBought = getInputPrice(tokensSold, tokenReserve, address(this).balance);
|
||||
require(ethBought >= minEthBought);
|
||||
require(token.transferFrom(buyer, address(this), tokensSold));
|
||||
uint256 tokensBought = IUniswapExchange(exchangeAddr).ethToTokenTransferInput.value(ethBought)(minTokensBought, deadline, recipient);
|
||||
emit EthPurchase(buyer, tokensSold, ethBought);
|
||||
return tokensBought;
|
||||
}
|
||||
|
||||
|
||||
function tokenToTokenSwapInput(
|
||||
uint256 tokensSold,
|
||||
uint256 minTokensBought,
|
||||
uint256 minEthBought,
|
||||
uint256 deadline,
|
||||
address tokenAddr)
|
||||
public returns (uint256)
|
||||
{
|
||||
address payable exchangeAddr = factory.getExchange(tokenAddr);
|
||||
return tokenToTokenInput(tokensSold, minTokensBought, minEthBought, deadline, msg.sender, msg.sender, exchangeAddr);
|
||||
}
|
||||
|
||||
|
||||
function tokenToTokenTransferInput(
|
||||
uint256 tokensSold,
|
||||
uint256 minTokensBought,
|
||||
uint256 minEthBought,
|
||||
uint256 deadline,
|
||||
address recipient,
|
||||
address tokenAddr)
|
||||
public returns (uint256)
|
||||
{
|
||||
address payable exchangeAddr = factory.getExchange(tokenAddr);
|
||||
return tokenToTokenInput(tokensSold, minTokensBought, minEthBought, deadline, msg.sender, recipient, exchangeAddr);
|
||||
}
|
||||
|
||||
function tokenToTokenOutput(
|
||||
uint256 tokensBought,
|
||||
uint256 maxTokensSold,
|
||||
uint256 maxEthSold,
|
||||
uint256 deadline,
|
||||
address buyer,
|
||||
address recipient,
|
||||
address payable exchangeAddr)
|
||||
private nonReentrant returns (uint256)
|
||||
{
|
||||
require(deadline >= block.timestamp && (tokensBought > 0 && maxEthSold > 0));
|
||||
require(exchangeAddr != address(this) && exchangeAddr != address(0));
|
||||
uint256 ethBought = IUniswapExchange(exchangeAddr).getEthToTokenOutputPrice(tokensBought);
|
||||
uint256 tokenReserve = token.balanceOf(address(this));
|
||||
uint256 tokensSold = getOutputPrice(ethBought, tokenReserve, address(this).balance);
|
||||
// tokens sold is always > 0
|
||||
require(maxTokensSold >= tokensSold && maxEthSold >= ethBought);
|
||||
require(token.transferFrom(buyer, address(this), tokensSold));
|
||||
IUniswapExchange(exchangeAddr).ethToTokenTransferOutput.value(ethBought)(tokensBought, deadline, recipient);
|
||||
emit EthPurchase(buyer, tokensSold, ethBought);
|
||||
return tokensSold;
|
||||
}
|
||||
|
||||
|
||||
function tokenToTokenSwapOutput(
|
||||
uint256 tokensBought,
|
||||
uint256 maxTokensSold,
|
||||
uint256 maxEthSold,
|
||||
uint256 deadline,
|
||||
address tokenAddr)
|
||||
public returns (uint256)
|
||||
{
|
||||
address payable exchangeAddr = factory.getExchange(tokenAddr);
|
||||
return tokenToTokenOutput(tokensBought, maxTokensSold, maxEthSold, deadline, msg.sender, msg.sender, exchangeAddr);
|
||||
}
|
||||
|
||||
|
||||
function tokenToTokenTransferOutput(
|
||||
uint256 tokensBought,
|
||||
uint256 maxTokensSold,
|
||||
uint256 maxEthSold,
|
||||
uint256 deadline,
|
||||
address recipient,
|
||||
address tokenAddr)
|
||||
public returns (uint256)
|
||||
{
|
||||
address payable exchangeAddr = factory.getExchange(tokenAddr);
|
||||
return tokenToTokenOutput(tokensBought, maxTokensSold, maxEthSold, deadline, msg.sender, recipient, exchangeAddr);
|
||||
}
|
||||
|
||||
|
||||
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, 'UniswapExchange#addLiquidity: INVALID_ARGUMENT');
|
||||
uint256 totalLiquidity = totalSupply;
|
||||
|
||||
if (totalLiquidity > 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);
|
||||
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);
|
||||
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;
|
||||
totalSupply = initialLiquidity;
|
||||
balanceOf[msg.sender] = initialLiquidity;
|
||||
require(token.transferFrom(msg.sender, address(this), tokenAmount));
|
||||
emit AddLiquidity(msg.sender, msg.value, tokenAmount);
|
||||
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);
|
||||
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);
|
||||
emit Transfer(msg.sender, address(0), amount);
|
||||
return (ethAmount, tokenAmount);
|
||||
}
|
||||
}
|
||||
28
contracts/UniswapFactory.sol
Normal file
28
contracts/UniswapFactory.sol
Normal file
@ -0,0 +1,28 @@
|
||||
pragma solidity ^0.5.11;
|
||||
import "./UniswapExchange.sol";
|
||||
import "./interfaces/IUniswapExchange.sol";
|
||||
|
||||
|
||||
contract UniswapFactory {
|
||||
|
||||
event NewExchange(address indexed token, address indexed exchange);
|
||||
|
||||
uint256 public tokenCount;
|
||||
mapping (address => address) public getExchange;
|
||||
mapping (address => address) internal getToken;
|
||||
mapping (uint256 => address) internal getTokenWithId;
|
||||
|
||||
function createExchange(address token) public returns (address) {
|
||||
require(token != address(0));
|
||||
require(getExchange[token] == address(0), 'EXCHANGE_EXISTS');
|
||||
UniswapExchange exchange = new UniswapExchange(token);
|
||||
exchange.setup(token);
|
||||
getExchange[token] = address(exchange);
|
||||
getToken[address(exchange)] = token;
|
||||
uint256 tokenId = tokenCount + 1;
|
||||
tokenCount = tokenId;
|
||||
getTokenWithId[tokenId] = token;
|
||||
emit NewExchange(token, address(exchange));
|
||||
return address(exchange);
|
||||
}
|
||||
}
|
||||
16
contracts/interfaces/IERC20.sol
Normal file
16
contracts/interfaces/IERC20.sol
Normal file
@ -0,0 +1,16 @@
|
||||
pragma solidity ^0.5.11;
|
||||
|
||||
/**
|
||||
* @title ERC20 interface
|
||||
* @dev see https://eips.ethereum.org/EIPS/eip-20
|
||||
*/
|
||||
interface IERC20 {
|
||||
function transfer(address to, uint256 value) external returns (bool);
|
||||
function approve(address spender, uint256 value) external returns (bool);
|
||||
function transferFrom(address from, address to, uint256 value) external returns (bool);
|
||||
function totalSupply() external view returns (uint256);
|
||||
function balanceOf(address who) external view returns (uint256);
|
||||
function allowance(address owner, address spender) external view returns (uint256);
|
||||
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||
event Approval(address indexed owner, address indexed spender, uint256 value);
|
||||
}
|
||||
254
contracts/interfaces/IUniswapExchange.sol
Normal file
254
contracts/interfaces/IUniswapExchange.sol
Normal file
@ -0,0 +1,254 @@
|
||||
pragma solidity ^0.5.0;
|
||||
|
||||
interface IUniswapExchange {
|
||||
event TokenPurchase(address indexed buyer, uint256 indexed eth_sold, uint256 indexed tokens_bought);
|
||||
event EthPurchase(address indexed buyer, uint256 indexed tokens_sold, uint256 indexed eth_bought);
|
||||
event AddLiquidity(address indexed provider, uint256 indexed eth_amount, uint256 indexed token_amount);
|
||||
event RemoveLiquidity(address indexed provider, uint256 indexed eth_amount, uint256 indexed token_amount);
|
||||
|
||||
/**
|
||||
* @notice Convert ETH to Tokens.
|
||||
* @dev User specifies exact input (msg.value).
|
||||
* @dev User cannot specify minimum output or deadline.
|
||||
*/
|
||||
function () external payable;
|
||||
|
||||
/**
|
||||
* @dev Pricing function for converting between ETH && Tokens.
|
||||
* @param inputAmount Amount of ETH or Tokens being sold.
|
||||
* @param inputReserve Amount of ETH or Tokens (input type) in exchange reserves.
|
||||
* @param outputReserve Amount of ETH or Tokens (output type) in exchange reserves.
|
||||
* @return Amount of ETH or Tokens bought.
|
||||
*/
|
||||
function getInputPrice(uint256 inputAmount, uint256 inputReserve, uint256 outputReserve) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Pricing function for converting between ETH && Tokens.
|
||||
* @param outputAmount Amount of ETH or Tokens being bought.
|
||||
* @param inputReserve Amount of ETH or Tokens (input type) in exchange reserves.
|
||||
* @param outputReserve Amount of ETH or Tokens (output type) in exchange reserves.
|
||||
* @return Amount of ETH or Tokens sold.
|
||||
*/
|
||||
function getOutputPrice(uint256 outputAmount, uint256 inputReserve, uint256 outputReserve) external view returns (uint256);
|
||||
|
||||
|
||||
/**
|
||||
* @notice Convert ETH to Tokens.
|
||||
* @dev User specifies exact input (msg.value) && minimum output.
|
||||
* @param minTokens Minimum Tokens bought.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @return Amount of Tokens bought.
|
||||
*/
|
||||
function ethToTokenSwapInput(uint256 minTokens, uint256 deadline) external payable returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Convert ETH to Tokens && transfers Tokens to recipient.
|
||||
* @dev User specifies exact input (msg.value) && minimum output
|
||||
* @param minTokens Minimum Tokens bought.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @param recipient The address that receives output Tokens.
|
||||
* @return Amount of Tokens bought.
|
||||
*/
|
||||
function ethToTokenTransferInput(uint256 minTokens, uint256 deadline, address recipient) external payable returns(uint256);
|
||||
|
||||
|
||||
/**
|
||||
* @notice Convert ETH to Tokens.
|
||||
* @dev User specifies maximum input (msg.value) && exact output.
|
||||
* @param tokensBought Amount of tokens bought.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @return Amount of ETH sold.
|
||||
*/
|
||||
function ethToTokenSwapOutput(uint256 tokensBought, uint256 deadline) external payable returns(uint256);
|
||||
|
||||
/**
|
||||
* @notice Convert ETH to Tokens && transfers Tokens to recipient.
|
||||
* @dev User specifies maximum input (msg.value) && exact output.
|
||||
* @param tokensBought Amount of tokens bought.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @param recipient The address that receives output Tokens.
|
||||
* @return Amount of ETH sold.
|
||||
*/
|
||||
function ethToTokenTransferOutput(uint256 tokensBought, uint256 deadline, address recipient) external payable returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Convert Tokens to ETH.
|
||||
* @dev User specifies exact input && minimum output.
|
||||
* @param tokensSold Amount of Tokens sold.
|
||||
* @param minEth Minimum ETH purchased.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @return Amount of ETH bought.
|
||||
*/
|
||||
function tokenToEthSwapInput(uint256 tokensSold, uint256 minEth, uint256 deadline) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Convert Tokens to ETH && transfers ETH to recipient.
|
||||
* @dev User specifies exact input && minimum output.
|
||||
* @param tokensSold Amount of Tokens sold.
|
||||
* @param minEth Minimum ETH purchased.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @param recipient The address that receives output ETH.
|
||||
* @return Amount of ETH bought.
|
||||
*/
|
||||
function tokenToEthTransferInput(uint256 tokensSold, uint256 minEth, uint256 deadline, address recipient) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Convert Tokens to ETH.
|
||||
* @dev User specifies maximum input && exact output.
|
||||
* @param ethBought Amount of ETH purchased.
|
||||
* @param maxTokens Maximum Tokens sold.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @return Amount of Tokens sold.
|
||||
*/
|
||||
function tokenToEthSwapOutput(uint256 ethBought, uint256 maxTokens, uint256 deadline) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Convert Tokens to ETH && transfers ETH to recipient.
|
||||
* @dev User specifies maximum input && exact output.
|
||||
* @param ethBought Amount of ETH purchased.
|
||||
* @param maxTokens Maximum Tokens sold.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @param recipient The address that receives output ETH.
|
||||
* @return Amount of Tokens sold.
|
||||
*/
|
||||
function tokenToEthTransferOutput(uint256 ethBought, uint256 maxTokens, uint256 deadline, address recipient) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Convert Tokens (token) to Tokens (tokenAddr).
|
||||
* @dev User specifies exact input && minimum output.
|
||||
* @param tokensSold Amount of Tokens sold.
|
||||
* @param minTokensBought Minimum Tokens (tokenAddr) purchased.
|
||||
* @param minEthBought Minimum ETH purchased as intermediary.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @param tokenAddr The address of the token being purchased.
|
||||
* @return Amount of Tokens (tokenAddr) bought.
|
||||
*/
|
||||
function tokenToTokenSwapInput(
|
||||
uint256 tokensSold,
|
||||
uint256 minTokensBought,
|
||||
uint256 minEthBought,
|
||||
uint256 deadline,
|
||||
address tokenAddr)
|
||||
external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Convert Tokens (token) to Tokens (tokenAddr) && transfers
|
||||
* Tokens (tokenAddr) to recipient.
|
||||
* @dev User specifies exact input && minimum output.
|
||||
* @param tokensSold Amount of Tokens sold.
|
||||
* @param minTokensBought Minimum Tokens (tokenAddr) purchased.
|
||||
* @param minEthBought Minimum ETH purchased as intermediary.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @param recipient The address that receives output ETH.
|
||||
* @param tokenAddr The address of the token being purchased.
|
||||
* @return Amount of Tokens (tokenAddr) bought.
|
||||
*/
|
||||
function tokenToTokenTransferInput(
|
||||
uint256 tokensSold,
|
||||
uint256 minTokensBought,
|
||||
uint256 minEthBought,
|
||||
uint256 deadline,
|
||||
address recipient,
|
||||
address tokenAddr)
|
||||
external returns (uint256);
|
||||
|
||||
|
||||
/**
|
||||
* @notice Convert Tokens (token) to Tokens (tokenAddr).
|
||||
* @dev User specifies maximum input && exact output.
|
||||
* @param tokensBought Amount of Tokens (tokenAddr) bought.
|
||||
* @param maxTokensSold Maximum Tokens (token) sold.
|
||||
* @param maxEthSold Maximum ETH purchased as intermediary.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @param tokenAddr The address of the token being purchased.
|
||||
* @return Amount of Tokens (token) sold.
|
||||
*/
|
||||
function tokenToTokenSwapOutput(
|
||||
uint256 tokensBought,
|
||||
uint256 maxTokensSold,
|
||||
uint256 maxEthSold,
|
||||
uint256 deadline,
|
||||
address tokenAddr)
|
||||
external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Convert Tokens (token) to Tokens (tokenAddr) && transfers
|
||||
* Tokens (tokenAddr) to recipient.
|
||||
* @dev User specifies maximum input && exact output.
|
||||
* @param tokensBought Amount of Tokens (tokenAddr) bought.
|
||||
* @param maxTokensSold Maximum Tokens (token) sold.
|
||||
* @param maxEthSold Maximum ETH purchased as intermediary.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @param recipient The address that receives output ETH.
|
||||
* @param tokenAddr The address of the token being purchased.
|
||||
* @return Amount of Tokens (token) sold.
|
||||
*/
|
||||
function tokenToTokenTransferOutput(
|
||||
uint256 tokensBought,
|
||||
uint256 maxTokensSold,
|
||||
uint256 maxEthSold,
|
||||
uint256 deadline,
|
||||
address recipient,
|
||||
address tokenAddr)
|
||||
external returns (uint256);
|
||||
|
||||
|
||||
/**
|
||||
* @notice Public price function for ETH to Token trades with an exact input.
|
||||
* @param ethSold Amount of ETH sold.
|
||||
* @return Amount of Tokens that can be bought with input ETH.
|
||||
*/
|
||||
function getEthToTokenInputPrice(uint256 ethSold) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Public price function for ETH to Token trades with an exact output.
|
||||
* @param tokensBought Amount of Tokens bought.
|
||||
* @return Amount of ETH needed to buy output Tokens.
|
||||
*/
|
||||
function getEthToTokenOutputPrice(uint256 tokensBought) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Public price function for Token to ETH trades with an exact input.
|
||||
* @param tokensSold Amount of Tokens sold.
|
||||
* @return Amount of ETH that can be bought with input Tokens.
|
||||
*/
|
||||
function getTokenToEthInputPrice(uint256 tokensSold) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Public price function for Token to ETH trades with an exact output.
|
||||
* @param ethBought Amount of output ETH.
|
||||
* @return Amount of Tokens needed to buy output ETH.
|
||||
*/
|
||||
function getTokenToEthOutputPrice(uint256 ethBought) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @return Address of Token that is sold on this exchange.
|
||||
*/
|
||||
function tokenAddress() external view returns (address);
|
||||
|
||||
/**
|
||||
* @return Address of factory that created this exchange.
|
||||
*/
|
||||
function factoryAddress() external view returns (address);
|
||||
|
||||
|
||||
/**
|
||||
* @notice Deposit ETH && Tokens (token) at current ratio to mint UNI tokens.
|
||||
* @dev minLiquidity does nothing when total UNI supply is 0.
|
||||
* @param minLiquidity Minimum number of UNI sender will mint if total UNI supply is greater than 0.
|
||||
* @param maxTokens Maximum number of tokens deposited. Deposits max amount if total UNI supply is 0.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @return The amount of UNI minted.
|
||||
*/
|
||||
function addLiquidity(uint256 minLiquidity, uint256 maxTokens, uint256 deadline) external payable returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Burn UNI tokens to withdraw ETH && Tokens at current ratio.
|
||||
* @param amount Amount of UNI burned.
|
||||
* @param minEth Minimum ETH withdrawn.
|
||||
* @param minTokens Minimum Tokens withdrawn.
|
||||
* @param deadline Time after which this transaction can no longer be executed.
|
||||
* @return The amount of ETH && Tokens withdrawn.
|
||||
*/
|
||||
function removeLiquidity(uint256 amount, uint256 minEth, uint256 minTokens, uint256 deadline) external returns (uint256, uint256);
|
||||
}
|
||||
11
contracts/interfaces/IUniswapFactory.sol
Normal file
11
contracts/interfaces/IUniswapFactory.sol
Normal file
@ -0,0 +1,11 @@
|
||||
pragma solidity ^0.5.11;
|
||||
|
||||
interface IUniswapFactory {
|
||||
event NewExchange(address indexed token, address indexed exchange);
|
||||
|
||||
function initializeFactory(address template) external;
|
||||
function createExchange(address token) external returns (address payable);
|
||||
function getExchange(address token) external view returns (address payable);
|
||||
function getToken(address token) external view returns (address);
|
||||
function getTokenWihId(uint256 token_id) external view returns (address);
|
||||
}
|
||||
56
contracts/test_contracts/TestToken.sol
Normal file
56
contracts/test_contracts/TestToken.sol
Normal file
@ -0,0 +1,56 @@
|
||||
pragma solidity ^0.5.11;
|
||||
import "../SafeMath.sol";
|
||||
|
||||
|
||||
contract TestERC20 {
|
||||
using SafeMath for uint256;
|
||||
|
||||
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||
event Approval(address indexed owner, address indexed spender, uint256 value);
|
||||
|
||||
string public name;
|
||||
string public symbol;
|
||||
uint256 public decimals;
|
||||
uint256 public totalSupply;
|
||||
uint256 internal constant MAX_UINT256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
|
||||
mapping (address => uint256) public balanceOf;
|
||||
mapping (address => mapping (address => uint256)) public allowance;
|
||||
|
||||
|
||||
constructor(string memory _name, string memory _symbol, uint256 _decimals, uint256 supply) public {
|
||||
name = _name;
|
||||
symbol = _symbol;
|
||||
decimals = _decimals;
|
||||
totalSupply = supply;
|
||||
balanceOf[msg.sender] = supply;
|
||||
}
|
||||
|
||||
function transfer(address to, uint256 value) public returns (bool) {
|
||||
balanceOf[msg.sender] = balanceOf[msg.sender].sub(value);
|
||||
balanceOf[to] = balanceOf[to].add(value);
|
||||
emit Transfer(msg.sender, to, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function transferFrom(address from, address to, uint256 value) public returns (bool) {
|
||||
if (allowance[from][msg.sender] < MAX_UINT256) {
|
||||
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
|
||||
}
|
||||
balanceOf[from] = balanceOf[from].sub(value);
|
||||
balanceOf[to] = balanceOf[to].add(value);
|
||||
emit Transfer(from, to, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function approve(address spender, uint256 value) public returns (bool) {
|
||||
allowance[msg.sender][spender] = value;
|
||||
emit Approval(msg.sender, spender, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function burn(uint256 value) public {
|
||||
totalSupply = totalSupply.sub(value);
|
||||
balanceOf[msg.sender] = balanceOf[msg.sender].sub(value);
|
||||
emit Transfer(msg.sender, address(0), value);
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
pragma solidity ^0.5.11;
|
||||
|
||||
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
|
||||
import "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
|
||||
|
||||
|
||||
// Example class - a mock class using delivering from ERC20
|
||||
contract Token is ERC20, ERC20Detailed {
|
||||
constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 initialBalance)
|
||||
public
|
||||
ERC20Detailed(_name, _symbol, _decimals)
|
||||
{
|
||||
super._mint(msg.sender, initialBalance);
|
||||
}
|
||||
}
|
||||
0
test/testExchange.js
Normal file
0
test/testExchange.js
Normal file
0
test/testFactory.js
Normal file
0
test/testFactory.js
Normal file
Reference in New Issue
Block a user