smart-contract/contracts/Bin/Kyber.sol
2019-03-23 04:07:27 +05:30

216 lines
6.5 KiB
Solidity

pragma solidity ^0.5.0;
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "Assertion Failed");
return c;
}
}
interface IERC20 {
function balanceOf(address who) external view returns (uint256);
function allowance(address _owner, address _spender) 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 Kyber {
// Kyber's trade function
function trade(address src, uint srcAmount, address dest, address destAddress, uint maxDestAmount, uint minConversionRate, address walletId) external payable returns (uint);
// Kyber's Get expected Rate function
function getExpectedRate(address src, address dest, uint srcQty) external view returns (uint, uint);
}
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 helper is Registry {
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;
}
}
// approve to Kyber Proxy contract
function _approveKyber(address token) internal returns (bool) {
address kyberProxy = _getAddress("kyber");
IERC20 tokenFunctions = IERC20(token);
return tokenFunctions.approve(kyberProxy, uint(0-1));
}
// Check Allowance to Kyber Proxy contract
function _allowanceKyber(address token) internal view returns (uint) {
address kyberProxy = _getAddress("kyber");
IERC20 tokenFunctions = IERC20(token);
return tokenFunctions.allowance(address(this), kyberProxy);
}
// Check allowance, if not approve
function _allowanceApproveKyber(address token) internal returns (bool) {
uint allowanceGiven = _allowanceKyber(token);
if (allowanceGiven == 0) {
return _approveKyber(token);
} else {
return true;
}
}
}
contract Trade is helper {
using SafeMath for uint;
event KyberTrade(address src, uint srcAmt, address dest, uint destAmt, address beneficiary, uint minConversionRate, address affiliate);
function getExpectedRateKyber(address src, address dest, uint srcAmt) public view returns (uint, uint) {
Kyber kyberFunctions = Kyber(_getAddress("kyber"));
return kyberFunctions.getExpectedRate(src, dest, srcAmt);
}
/**
* @title Kyber'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)
*/
function tradeSrcKyber(
address src, // token to sell
uint srcAmt, // amount of token for sell
address dest, // token to buy
uint minDestAmt // minimum slippage rate
) public payable returns (uint tokensBought) {
address eth = _getAddress("eth");
uint ethQty = _getToken(
msg.sender,
src,
srcAmt,
eth
);
if (src != eth) {
_allowanceApproveKyber(src);
}
// Interacting with Kyber Proxy Contract
Kyber kyberFunctions = Kyber(_getAddress("kyber"));
tokensBought = kyberFunctions.trade.value(ethQty)(
src,
srcAmt,
dest,
msg.sender,
uint(0-1),
minDestAmt,
_getAddress("admin")
);
emit KyberTrade(src, srcAmt, dest, tokensBought, msg.sender, minDestAmt, _getAddress("admin"));
}
/**
* @title Kyber's trade when token to sell 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
*/
function tradeDestKyber(
address src, // token to sell
uint maxSrcAmt, // amount of token for sell
address dest, // token to buy
uint destAmt // minimum slippage rate
) public payable returns (uint tokensBought) {
address eth = _getAddress("eth");
uint ethQty = _getToken(
msg.sender,
src,
maxSrcAmt,
eth
);
if (src != eth) {
_allowanceApproveKyber(src);
}
// Interacting with Kyber Proxy Contract
Kyber kyberFunctions = Kyber(_getAddress("kyber"));
tokensBought = kyberFunctions.trade.value(ethQty)(
src,
maxSrcAmt,
dest,
msg.sender,
destAmt,
destAmt - 1,
_getAddress("admin")
);
// maxDestAmt usecase implementated
if (src == eth && address(this).balance > 0) {
msg.sender.transfer(address(this).balance);
} else if (src != eth) {
// as there is no balanceOf of eth
IERC20 srcTkn = IERC20(src);
uint srcBal = srcTkn.balanceOf(address(this));
if (srcBal > 0) {
srcTkn.transfer(msg.sender, srcBal);
}
}
emit KyberTrade(src, maxSrcAmt, dest, tokensBought, msg.sender, destAmt, _getAddress("admin"));
}
}
contract InstaKyber is Trade {
constructor(address rAddr) public {
addressRegistry = rAddr;
}
function() external payable {}
}