2019-03-17 10:56:42 +00:00
|
|
|
pragma solidity 0.5.0;
|
|
|
|
|
|
|
|
|
|
|
|
import "./safemath.sol";
|
|
|
|
|
|
|
|
interface IERC20 {
|
|
|
|
function balanceOf(address who) external view returns (uint256);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
interface AddressRegistry {
|
|
|
|
function getAddr(string calldata name) external view returns (address);
|
|
|
|
}
|
|
|
|
|
|
|
|
interface UniswapFactoryInterface {
|
|
|
|
// Get Exchange and Token Info
|
|
|
|
function getExchange(address token) external view returns (address exchange);
|
|
|
|
function getToken(address exchange) external view returns (address token);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Solidity Interface
|
|
|
|
interface UniswapExchange {
|
|
|
|
// Address of ERC20 token sold on this exchange
|
|
|
|
function tokenAddress() external view returns (address token);
|
|
|
|
// Address of Uniswap Factory
|
|
|
|
function factoryAddress() external view returns (address factory);
|
|
|
|
// Get Prices
|
|
|
|
function getEthToTokenInputPrice(uint256 eth_sold) external view returns (uint256 tokens_bought);
|
|
|
|
function getEthToTokenOutputPrice(uint256 tokens_bought) external view returns (uint256 eth_sold);
|
|
|
|
function getTokenToEthInputPrice(uint256 tokens_sold) external view returns (uint256 eth_bought);
|
|
|
|
function getTokenToEthOutputPrice(uint256 eth_bought) external view returns (uint256 tokens_sold);
|
|
|
|
// Trade ETH to ERC20
|
|
|
|
function ethToTokenSwapInput(uint256 min_tokens, uint256 deadline) external payable returns (uint256 tokens_bought);
|
|
|
|
function ethToTokenTransferInput(uint256 min_tokens, uint256 deadline, address recipient) external payable returns (uint256 tokens_bought);
|
|
|
|
function ethToTokenSwapOutput(uint256 tokens_bought, uint256 deadline) external payable returns (uint256 eth_sold);
|
|
|
|
function ethToTokenTransferOutput(uint256 tokens_bought, uint256 deadline, address recipient) external payable returns (uint256 eth_sold);
|
|
|
|
// Trade ERC20 to ETH
|
|
|
|
function tokenToEthSwapInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline) external returns (uint256 eth_bought);
|
|
|
|
function tokenToEthTransferInput(uint256 tokens_sold, uint256 min_tokens, uint256 deadline, address recipient) external returns (uint256 eth_bought);
|
|
|
|
function tokenToEthSwapOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline) external returns (uint256 tokens_sold);
|
|
|
|
function tokenToEthTransferOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline, address recipient) external returns (uint256 tokens_sold);
|
|
|
|
// Trade ERC20 to ERC20
|
|
|
|
function tokenToTokenSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address token_addr) external returns (uint256 tokens_bought);
|
|
|
|
function tokenToTokenTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address token_addr) external returns (uint256 tokens_bought);
|
|
|
|
function tokenToTokenSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address token_addr) external returns (uint256 tokens_sold);
|
|
|
|
function tokenToTokenTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address token_addr) external returns (uint256 tokens_sold);
|
|
|
|
// Trade ERC20 to Custom Pool
|
|
|
|
function tokenToExchangeSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address exchange_addr) external returns (uint256 tokens_bought);
|
|
|
|
function tokenToExchangeTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address exchange_addr) external returns (uint256 tokens_bought);
|
|
|
|
function tokenToExchangeSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address exchange_addr) external returns (uint256 tokens_sold);
|
|
|
|
function tokenToExchangeTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address exchange_addr) external returns (uint256 tokens_sold);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
contract Registry {
|
|
|
|
address public addressRegistry;
|
|
|
|
modifier onlyAdmin() {
|
|
|
|
require(msg.sender == getAddress("admin"), "Permission Denied");
|
|
|
|
_;
|
|
|
|
}
|
|
|
|
function getAddress(string memory name) internal view returns (address) {
|
|
|
|
AddressRegistry addrReg = AddressRegistry(addressRegistry);
|
|
|
|
return addrReg.getAddr(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
contract Trade is Registry {
|
|
|
|
|
|
|
|
using SafeMath for uint;
|
|
|
|
|
2019-03-17 13:29:01 +00:00
|
|
|
// Get Uniswap's Exchange address from Factory Contract
|
|
|
|
function _getExchangeAddress(address _token) internal view returns (address) {
|
|
|
|
UniswapFactoryInterface uniswapMain = UniswapFactoryInterface(getAddress("uniswap"));
|
|
|
|
return uniswapMain.getExchange(_token);
|
|
|
|
}
|
|
|
|
|
2019-03-20 18:59:57 +00:00
|
|
|
// Check required ETH Quantity to execute code
|
|
|
|
function _getToken(
|
|
|
|
address trader,
|
|
|
|
address src,
|
|
|
|
uint srcAmt,
|
|
|
|
address eth
|
|
|
|
)
|
|
|
|
internal
|
|
|
|
returns (uint ethQty)
|
|
|
|
{
|
|
|
|
if (src == eth) {
|
|
|
|
require(msg.value == srcAmt, "Invalid Operation");
|
|
|
|
ethQty = srcAmt;
|
|
|
|
} else {
|
|
|
|
IERC20 tokenFunctions = IERC20(src);
|
|
|
|
tokenFunctions.transferFrom(trader, address(this), srcAmt);
|
|
|
|
ethQty = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @title Uniswap's get expected rate from source
|
|
|
|
* @param src - Token address to sell (for ETH it's "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
|
|
|
|
* @param dest - Token address to buy (for ETH it's "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
|
|
|
|
* @param srcAmt - source token amount
|
2019-03-17 13:29:01 +00:00
|
|
|
*/
|
2019-03-20 18:59:57 +00:00
|
|
|
function getExpectedRateSrcUniswap(address src, address dest, uint srcAmt) external view returns (uint256) {
|
2019-03-17 13:29:01 +00:00
|
|
|
if (src == getAddress("eth")) {
|
|
|
|
// define uniswap exchange with dest address
|
|
|
|
UniswapExchange exchangeContract = UniswapExchange(_getExchangeAddress(dest));
|
2019-03-20 18:59:57 +00:00
|
|
|
return exchangeContract.getEthToTokenInputPrice(srcAmt);
|
2019-03-17 13:29:01 +00:00
|
|
|
} else if (dest == getAddress("eth")) {
|
|
|
|
// define uniswap exchange with src address
|
|
|
|
UniswapExchange exchangeContract = UniswapExchange(_getExchangeAddress(src));
|
2019-03-20 18:59:57 +00:00
|
|
|
return exchangeContract.getTokenToEthInputPrice(srcAmt);
|
2019-03-19 10:37:42 +00:00
|
|
|
} else {
|
|
|
|
UniswapExchange exchangeContractSrc = UniswapExchange(_getExchangeAddress(src));
|
|
|
|
UniswapExchange exchangeContractDest = UniswapExchange(_getExchangeAddress(dest));
|
2019-03-20 18:59:57 +00:00
|
|
|
uint ethQty = exchangeContractSrc.getTokenToEthInputPrice(srcAmt);
|
2019-03-19 10:37:42 +00:00
|
|
|
return exchangeContractDest.getEthToTokenInputPrice(ethQty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-20 18:59:57 +00:00
|
|
|
/**
|
|
|
|
* @title Uniswap's get expected rate from dest
|
|
|
|
* @param src - Token address to sell (for ETH it's "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
|
|
|
|
* @param dest - Token address to buy (for ETH it's "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
|
|
|
|
* @param destAmt - dest token amount
|
|
|
|
*/
|
2019-03-21 09:59:45 +00:00
|
|
|
function getExpectedRateDestUniswap(
|
|
|
|
address src,
|
|
|
|
address dest,
|
|
|
|
uint destAmt
|
|
|
|
) external view returns (uint256) {
|
2019-03-19 10:37:42 +00:00
|
|
|
address eth = getAddress("eth");
|
|
|
|
if (src == eth) {
|
|
|
|
// define uniswap exchange with dest address
|
|
|
|
UniswapExchange exchangeContract = UniswapExchange(_getExchangeAddress(dest));
|
2019-03-20 18:59:57 +00:00
|
|
|
return exchangeContract.getEthToTokenOutputPrice(destAmt);
|
2019-03-19 10:37:42 +00:00
|
|
|
} else if (dest == eth) {
|
|
|
|
// define uniswap exchange with src address
|
|
|
|
UniswapExchange exchangeContract = UniswapExchange(_getExchangeAddress(src));
|
2019-03-20 18:59:57 +00:00
|
|
|
return exchangeContract.getTokenToEthOutputPrice(destAmt);
|
2019-03-17 13:29:01 +00:00
|
|
|
} else {
|
|
|
|
UniswapExchange exchangeContractSrc = UniswapExchange(_getExchangeAddress(src));
|
|
|
|
UniswapExchange exchangeContractDest = UniswapExchange(_getExchangeAddress(dest));
|
2019-03-20 18:59:57 +00:00
|
|
|
uint ethQty = exchangeContractDest.getTokenToEthInputPrice(destAmt);
|
2019-03-19 10:37:42 +00:00
|
|
|
return exchangeContractSrc.getEthToTokenInputPrice(ethQty);
|
2019-03-17 13:29:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-19 10:37:42 +00:00
|
|
|
|
2019-03-21 09:59:45 +00:00
|
|
|
/**
|
|
|
|
* @title Uniswap's trade when token to sell Amount fixed
|
|
|
|
* @param src - Token address to sell (for ETH it's "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
|
|
|
|
* @param srcAmt - amount of token for sell
|
|
|
|
* @param dest - Token address to buy (for ETH it's "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
|
|
|
|
* @param minDestAmt - min amount of token to buy (slippage)
|
|
|
|
* @param deadline - time for this transaction to be valid
|
|
|
|
*/
|
2019-03-19 10:37:42 +00:00
|
|
|
function tradeSrcUniswap(
|
2019-03-21 09:59:45 +00:00
|
|
|
address src,
|
|
|
|
uint srcAmt,
|
|
|
|
address dest,
|
|
|
|
uint minDestAmt,
|
|
|
|
uint deadline
|
2019-03-17 13:29:01 +00:00
|
|
|
) public payable returns (uint) {
|
2019-03-19 10:37:42 +00:00
|
|
|
|
|
|
|
address eth = getAddress("eth");
|
|
|
|
address user = msg.sender;
|
2019-03-20 18:59:57 +00:00
|
|
|
uint ethQty = _getToken(
|
2019-03-19 10:37:42 +00:00
|
|
|
user,
|
|
|
|
src,
|
|
|
|
srcAmt,
|
|
|
|
eth
|
|
|
|
);
|
|
|
|
|
|
|
|
if (src == eth) {
|
|
|
|
UniswapExchange exchangeContract = UniswapExchange(_getExchangeAddress(dest));
|
2019-03-20 18:59:57 +00:00
|
|
|
uint tokensBought = exchangeContract.ethToTokenTransferInput.value(ethQty)(minDestAmt, deadline, user);
|
2019-03-19 10:37:42 +00:00
|
|
|
return tokensBought;
|
|
|
|
} else if (dest == eth) {
|
|
|
|
UniswapExchange exchangeContract = UniswapExchange(_getExchangeAddress(src));
|
2019-03-20 18:59:57 +00:00
|
|
|
uint ethBought = exchangeContract.tokenToEthTransferInput(srcAmt, minDestAmt, deadline, user);
|
2019-03-19 10:37:42 +00:00
|
|
|
return ethBought;
|
|
|
|
} else {
|
2019-03-20 18:59:57 +00:00
|
|
|
UniswapExchange exchangeContract = UniswapExchange(_getExchangeAddress(src));
|
|
|
|
uint ethBought = exchangeContract.getTokenToEthInputPrice(srcAmt);
|
2019-03-21 09:59:45 +00:00
|
|
|
uint tokensBought = exchangeContract.tokenToTokenTransferInput(srcAmt, minDestAmt, uint(0), deadline, user, dest);
|
2019-03-20 18:59:57 +00:00
|
|
|
return tokensBought;
|
2019-03-19 10:37:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-21 09:59:45 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @title Uniswap's trade when token to buy Amount fixed
|
|
|
|
* @param src - Token address to sell (for ETH it's "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
|
|
|
|
* @param maxSrcAmt - max amount of token for sell (slippage)
|
|
|
|
* @param dest - Token address to buy (for ETH it's "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
|
|
|
|
* @param destAmt - amount of token to buy
|
|
|
|
* @param deadline - time for this transaction to be valid
|
|
|
|
*/
|
|
|
|
function tradeDestUniswap(
|
|
|
|
address src,
|
|
|
|
uint maxSrcAmt,
|
|
|
|
address dest,
|
|
|
|
uint destAmt,
|
|
|
|
uint deadline
|
|
|
|
) public payable returns (uint) {
|
|
|
|
|
|
|
|
address eth = getAddress("eth");
|
|
|
|
address user = msg.sender;
|
|
|
|
uint ethQty = _getToken(
|
|
|
|
user,
|
|
|
|
src,
|
|
|
|
maxSrcAmt,
|
|
|
|
eth
|
|
|
|
);
|
|
|
|
|
|
|
|
if (src == eth) {
|
|
|
|
UniswapExchange exchangeContract = UniswapExchange(_getExchangeAddress(dest));
|
|
|
|
uint ethSold = exchangeContract.ethToTokenTransferInput.value(ethQty)(destAmt, deadline, user);
|
|
|
|
if (ethSold < ethQty) {
|
|
|
|
uint srcToReturn = ethQty - ethSold;
|
|
|
|
msg.sender.transfer(srcToReturn);
|
|
|
|
}
|
|
|
|
return ethSold;
|
|
|
|
} else if (dest == eth) {
|
|
|
|
UniswapExchange exchangeContract = UniswapExchange(_getExchangeAddress(src));
|
|
|
|
uint tokensSold = exchangeContract.tokenToEthTransferInput(destAmt, maxSrcAmt, deadline, user);
|
|
|
|
if (tokensSold < maxSrcAmt) {
|
|
|
|
IERC20 srcTkn = IERC20(src);
|
|
|
|
uint srcToReturn = maxSrcAmt - tokensSold;
|
|
|
|
srcTkn.transfer(user, srcToReturn);
|
|
|
|
}
|
|
|
|
return tokensSold;
|
|
|
|
} else {
|
|
|
|
UniswapExchange exchangeContractSrc = UniswapExchange(_getExchangeAddress(src));
|
|
|
|
UniswapExchange exchangeContractdest = UniswapExchange(_getExchangeAddress(dest));
|
|
|
|
uint ethBought = exchangeContractdest.getTokenToEthInputPrice(destAmt);
|
|
|
|
uint tokensSold = exchangeContractSrc.tokenToTokenTransferOutput(destAmt, maxSrcAmt, uint(0-1), deadline, user, dest);
|
|
|
|
if (tokensSold < maxSrcAmt) {
|
|
|
|
IERC20 srcTkn = IERC20(src);
|
|
|
|
uint srcToReturn = maxSrcAmt - tokensSold;
|
|
|
|
srcTkn.transfer(user, srcToReturn);
|
|
|
|
}
|
|
|
|
return tokensSold;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-03-17 10:56:42 +00:00
|
|
|
}
|