Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
6570426 | 2188 days ago | 0.001 ETH |
Loading...
Loading
Contract Name:
KyberConverter
Compiler Version
v0.4.24+commit.e67f0147
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2018-10-23 */ pragma solidity ^0.4.24; // File: contracts/vendors/kyber/ERC20Interface.sol // https://github.com/ethereum/EIPs/issues/20 interface ERC20 { function totalSupply() public view returns (uint supply); function balanceOf(address _owner) public view returns (uint balance); function transfer(address _to, uint _value) public returns (bool success); function transferFrom(address _from, address _to, uint _value) public returns (bool success); function approve(address _spender, uint _value) public returns (bool success); function allowance(address _owner, address _spender) public view returns (uint remaining); function decimals() public view returns(uint digits); event Approval(address indexed _owner, address indexed _spender, uint _value); } // File: contracts/vendors/kyber/PermissionGroups.sol contract PermissionGroups { address public admin; address public pendingAdmin; mapping(address=>bool) internal operators; mapping(address=>bool) internal alerters; address[] internal operatorsGroup; address[] internal alertersGroup; uint constant internal MAX_GROUP_SIZE = 50; constructor () public { admin = msg.sender; } modifier onlyAdmin() { require(msg.sender == admin); _; } modifier onlyOperator() { require(operators[msg.sender]); _; } modifier onlyAlerter() { require(alerters[msg.sender]); _; } function getOperators () external view returns(address[]) { return operatorsGroup; } function getAlerters () external view returns(address[]) { return alertersGroup; } event TransferAdminPending(address pendingAdmin); /** * @dev Allows the current admin to set the pendingAdmin address. * @param newAdmin The address to transfer ownership to. */ function transferAdmin(address newAdmin) public onlyAdmin { require(newAdmin != address(0)); emit TransferAdminPending(pendingAdmin); pendingAdmin = newAdmin; } /** * @dev Allows the current admin to set the admin in one tx. Useful initial deployment. * @param newAdmin The address to transfer ownership to. */ function transferAdminQuickly(address newAdmin) public onlyAdmin { require(newAdmin != address(0)); emit TransferAdminPending(newAdmin); emit AdminClaimed(newAdmin, admin); admin = newAdmin; } event AdminClaimed( address newAdmin, address previousAdmin); /** * @dev Allows the pendingAdmin address to finalize the change admin process. */ function claimAdmin() public { require(pendingAdmin == msg.sender); emit AdminClaimed(pendingAdmin, admin); admin = pendingAdmin; pendingAdmin = address(0); } event AlerterAdded (address newAlerter, bool isAdd); function addAlerter(address newAlerter) public onlyAdmin { require(!alerters[newAlerter]); // prevent duplicates. require(alertersGroup.length < MAX_GROUP_SIZE); AlerterAdded(newAlerter, true); alerters[newAlerter] = true; alertersGroup.push(newAlerter); } function removeAlerter (address alerter) public onlyAdmin { require(alerters[alerter]); alerters[alerter] = false; for (uint i = 0; i < alertersGroup.length; ++i) { if (alertersGroup[i] == alerter) { alertersGroup[i] = alertersGroup[alertersGroup.length - 1]; alertersGroup.length--; AlerterAdded(alerter, false); break; } } } event OperatorAdded(address newOperator, bool isAdd); function addOperator(address newOperator) public onlyAdmin { require(!operators[newOperator]); // prevent duplicates. require(operatorsGroup.length < MAX_GROUP_SIZE); emit OperatorAdded(newOperator, true); operators[newOperator] = true; operatorsGroup.push(newOperator); } function removeOperator (address operator) public onlyAdmin { require(operators[operator]); operators[operator] = false; for (uint i = 0; i < operatorsGroup.length; ++i) { if (operatorsGroup[i] == operator) { operatorsGroup[i] = operatorsGroup[operatorsGroup.length - 1]; operatorsGroup.length -= 1; emit OperatorAdded(operator, false); break; } } } } // File: contracts/vendors/kyber/Withdrawable.sol /** * @title Contracts that should be able to recover tokens or ethers * @author Ilan Doron * @dev This allows to recover any tokens or Ethers received in a contract. * This will prevent any accidental loss of tokens. */ contract Withdrawable is PermissionGroups { event TokenWithdraw(ERC20 token, uint amount, address sendTo); /** * @dev Withdraw all ERC20 compatible tokens * @param token ERC20 The address of the token contract */ function withdrawToken(ERC20 token, uint amount, address sendTo) external onlyAdmin { require(token.transfer(sendTo, amount)); emit TokenWithdraw(token, amount, sendTo); } event EtherWithdraw(uint amount, address sendTo); /** * @dev Withdraw Ethers */ function withdrawEther(uint amount, address sendTo) external onlyAdmin { sendTo.transfer(amount); emit EtherWithdraw(amount, sendTo); } } // File: contracts/vendors/kyber/Utils.sol /// @title Kyber constants contract contract Utils { ERC20 constant internal ETH_TOKEN_ADDRESS = ERC20(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee); uint constant internal PRECISION = (10**18); uint constant internal MAX_QTY = (10**28); // 10B tokens uint constant internal MAX_RATE = (PRECISION * 10**6); // up to 1M tokens per ETH uint constant internal MAX_DECIMALS = 18; uint constant internal ETH_DECIMALS = 18; mapping(address=>uint) internal decimals; function setDecimals(ERC20 token) internal { if (token == ETH_TOKEN_ADDRESS) decimals[token] = ETH_DECIMALS; else decimals[token] = token.decimals(); } function getDecimals(ERC20 token) internal view returns(uint) { if (token == ETH_TOKEN_ADDRESS) return ETH_DECIMALS; // save storage access uint tokenDecimals = decimals[token]; // technically, there might be token with decimals 0 // moreover, very possible that old tokens have decimals 0 // these tokens will just have higher gas fees. if(tokenDecimals == 0) return token.decimals(); return tokenDecimals; } function calcDstQty(uint srcQty, uint srcDecimals, uint dstDecimals, uint rate) internal pure returns(uint) { require(srcQty <= MAX_QTY); require(rate <= MAX_RATE); if (dstDecimals >= srcDecimals) { require((dstDecimals - srcDecimals) <= MAX_DECIMALS); return (srcQty * rate * (10**(dstDecimals - srcDecimals))) / PRECISION; } else { require((srcDecimals - dstDecimals) <= MAX_DECIMALS); return (srcQty * rate) / (PRECISION * (10**(srcDecimals - dstDecimals))); } } function calcSrcQty(uint dstQty, uint srcDecimals, uint dstDecimals, uint rate) internal pure returns(uint) { require(dstQty <= MAX_QTY); require(rate <= MAX_RATE); //source quantity is rounded up. to avoid dest quantity being too low. uint numerator; uint denominator; if (srcDecimals >= dstDecimals) { require((srcDecimals - dstDecimals) <= MAX_DECIMALS); numerator = (PRECISION * dstQty * (10**(srcDecimals - dstDecimals))); denominator = rate; } else { require((dstDecimals - srcDecimals) <= MAX_DECIMALS); numerator = (PRECISION * dstQty); denominator = (rate * (10**(dstDecimals - srcDecimals))); } return (numerator + denominator - 1) / denominator; //avoid rounding down errors } } // File: contracts/vendors/kyber/Utils2.sol contract Utils2 is Utils { /// @dev get the balance of a user. /// @param token The token type /// @return The balance function getBalance(ERC20 token, address user) public view returns(uint) { if (token == ETH_TOKEN_ADDRESS) return user.balance; else return token.balanceOf(user); } function getDecimalsSafe(ERC20 token) internal returns(uint) { if (decimals[token] == 0) { setDecimals(token); } return decimals[token]; } function calcDestAmount(ERC20 src, ERC20 dest, uint srcAmount, uint rate) internal view returns(uint) { return calcDstQty(srcAmount, getDecimals(src), getDecimals(dest), rate); } function calcSrcAmount(ERC20 src, ERC20 dest, uint destAmount, uint rate) internal view returns(uint) { return calcSrcQty(destAmount, getDecimals(src), getDecimals(dest), rate); } function calcRateFromQty(uint srcAmount, uint destAmount, uint srcDecimals, uint dstDecimals) internal pure returns(uint) { require(srcAmount <= MAX_QTY); require(destAmount <= MAX_QTY); if (dstDecimals >= srcDecimals) { require((dstDecimals - srcDecimals) <= MAX_DECIMALS); return (destAmount * PRECISION / ((10 ** (dstDecimals - srcDecimals)) * srcAmount)); } else { require((srcDecimals - dstDecimals) <= MAX_DECIMALS); return (destAmount * PRECISION * (10 ** (srcDecimals - dstDecimals)) / srcAmount); } } } // File: contracts/vendors/kyber/KyberNetworkInterface.sol /// @title Kyber Network interface interface KyberNetworkInterface { function maxGasPrice() public view returns(uint); function getUserCapInWei(address user) public view returns(uint); function getUserCapInTokenWei(address user, ERC20 token) public view returns(uint); function enabled() public view returns(bool); function info(bytes32 id) public view returns(uint); function getExpectedRate(ERC20 src, ERC20 dest, uint srcQty) public view returns (uint expectedRate, uint slippageRate); function tradeWithHint(address trader, ERC20 src, uint srcAmount, ERC20 dest, address destAddress, uint maxDestAmount, uint minConversionRate, address walletId, bytes hint) public payable returns(uint); } // File: contracts/vendors/kyber/KyberNetworkProxyInterface.sol /// @title Kyber Network interface interface KyberNetworkProxyInterface { function maxGasPrice() public view returns(uint); function getUserCapInWei(address user) public view returns(uint); function getUserCapInTokenWei(address user, ERC20 token) public view returns(uint); function enabled() public view returns(bool); function info(bytes32 id) public view returns(uint); function getExpectedRate(ERC20 src, ERC20 dest, uint srcQty) public view returns (uint expectedRate, uint slippageRate); function tradeWithHint(ERC20 src, uint srcAmount, ERC20 dest, address destAddress, uint maxDestAmount, uint minConversionRate, address walletId, bytes hint) public payable returns(uint); } // File: contracts/vendors/kyber/SimpleNetworkInterface.sol /// @title simple interface for Kyber Network interface SimpleNetworkInterface { function swapTokenToToken(ERC20 src, uint srcAmount, ERC20 dest, uint minConversionRate) public returns(uint); function swapEtherToToken(ERC20 token, uint minConversionRate) public payable returns(uint); function swapTokenToEther(ERC20 token, uint srcAmount, uint minConversionRate) public returns(uint); } // File: contracts/vendors/kyber/KyberNetworkProxy.sol //////////////////////////////////////////////////////////////////////////////////////////////////////// /// @title Kyber Network proxy for main contract contract KyberNetworkProxy is KyberNetworkProxyInterface, SimpleNetworkInterface, Withdrawable, Utils2 { KyberNetworkInterface public kyberNetworkContract; function KyberNetworkProxy(address _admin) public { require(_admin != address(0)); admin = _admin; } /// @notice use token address ETH_TOKEN_ADDRESS for ether /// @dev makes a trade between src and dest token and send dest token to destAddress /// @param src Src token /// @param srcAmount amount of src tokens /// @param dest Destination token /// @param destAddress Address to send tokens to /// @param maxDestAmount A limit on the amount of dest tokens /// @param minConversionRate The minimal conversion rate. If actual rate is lower, trade is canceled. /// @param walletId is the wallet ID to send part of the fees /// @return amount of actual dest tokens function trade( ERC20 src, uint srcAmount, ERC20 dest, address destAddress, uint maxDestAmount, uint minConversionRate, address walletId ) public payable returns(uint) { bytes memory hint; return tradeWithHint( src, srcAmount, dest, destAddress, maxDestAmount, minConversionRate, walletId, hint ); } /// @dev makes a trade between src and dest token and send dest tokens to msg sender /// @param src Src token /// @param srcAmount amount of src tokens /// @param dest Destination token /// @param minConversionRate The minimal conversion rate. If actual rate is lower, trade is canceled. /// @return amount of actual dest tokens function swapTokenToToken( ERC20 src, uint srcAmount, ERC20 dest, uint minConversionRate ) public returns(uint) { bytes memory hint; return tradeWithHint( src, srcAmount, dest, msg.sender, MAX_QTY, minConversionRate, 0, hint ); } /// @dev makes a trade from Ether to token. Sends token to msg sender /// @param token Destination token /// @param minConversionRate The minimal conversion rate. If actual rate is lower, trade is canceled. /// @return amount of actual dest tokens function swapEtherToToken(ERC20 token, uint minConversionRate) public payable returns(uint) { bytes memory hint; return tradeWithHint( ETH_TOKEN_ADDRESS, msg.value, token, msg.sender, MAX_QTY, minConversionRate, 0, hint ); } /// @dev makes a trade from token to Ether, sends Ether to msg sender /// @param token Src token /// @param srcAmount amount of src tokens /// @param minConversionRate The minimal conversion rate. If actual rate is lower, trade is canceled. /// @return amount of actual dest tokens function swapTokenToEther(ERC20 token, uint srcAmount, uint minConversionRate) public returns(uint) { bytes memory hint; return tradeWithHint( token, srcAmount, ETH_TOKEN_ADDRESS, msg.sender, MAX_QTY, minConversionRate, 0, hint ); } struct UserBalance { uint srcBalance; uint destBalance; } event ExecuteTrade(address indexed trader, ERC20 src, ERC20 dest, uint actualSrcAmount, uint actualDestAmount); /// @notice use token address ETH_TOKEN_ADDRESS for ether /// @dev makes a trade between src and dest token and send dest token to destAddress /// @param src Src token /// @param srcAmount amount of src tokens /// @param dest Destination token /// @param destAddress Address to send tokens to /// @param maxDestAmount A limit on the amount of dest tokens /// @param minConversionRate The minimal conversion rate. If actual rate is lower, trade is canceled. /// @param walletId is the wallet ID to send part of the fees /// @param hint will give hints for the trade. /// @return amount of actual dest tokens function tradeWithHint( ERC20 src, uint srcAmount, ERC20 dest, address destAddress, uint maxDestAmount, uint minConversionRate, address walletId, bytes hint ) public payable returns(uint) { require(src == ETH_TOKEN_ADDRESS || msg.value == 0); UserBalance memory userBalanceBefore; userBalanceBefore.srcBalance = getBalance(src, msg.sender); userBalanceBefore.destBalance = getBalance(dest, destAddress); if (src == ETH_TOKEN_ADDRESS) { userBalanceBefore.srcBalance += msg.value; } else { require(src.transferFrom(msg.sender, kyberNetworkContract, srcAmount)); } uint reportedDestAmount = kyberNetworkContract.tradeWithHint.value(msg.value)( msg.sender, src, srcAmount, dest, destAddress, maxDestAmount, minConversionRate, walletId, hint ); TradeOutcome memory tradeOutcome = calculateTradeOutcome( userBalanceBefore.srcBalance, userBalanceBefore.destBalance, src, dest, destAddress ); require(reportedDestAmount == tradeOutcome.userDeltaDestAmount); require(tradeOutcome.userDeltaDestAmount <= maxDestAmount); require(tradeOutcome.actualRate >= minConversionRate); ExecuteTrade(msg.sender, src, dest, tradeOutcome.userDeltaSrcAmount, tradeOutcome.userDeltaDestAmount); return tradeOutcome.userDeltaDestAmount; } event KyberNetworkSet(address newNetworkContract, address oldNetworkContract); function setKyberNetworkContract(KyberNetworkInterface _kyberNetworkContract) public onlyAdmin { require(_kyberNetworkContract != address(0)); KyberNetworkSet(_kyberNetworkContract, kyberNetworkContract); kyberNetworkContract = _kyberNetworkContract; } function getExpectedRate(ERC20 src, ERC20 dest, uint srcQty) public view returns(uint expectedRate, uint slippageRate) { return kyberNetworkContract.getExpectedRate(src, dest, srcQty); } function getUserCapInWei(address user) public view returns(uint) { return kyberNetworkContract.getUserCapInWei(user); } function getUserCapInTokenWei(address user, ERC20 token) public view returns(uint) { return kyberNetworkContract.getUserCapInTokenWei(user, token); } function maxGasPrice() public view returns(uint) { return kyberNetworkContract.maxGasPrice(); } function enabled() public view returns(bool) { return kyberNetworkContract.enabled(); } function info(bytes32 field) public view returns(uint) { return kyberNetworkContract.info(field); } struct TradeOutcome { uint userDeltaSrcAmount; uint userDeltaDestAmount; uint actualRate; } function calculateTradeOutcome (uint srcBalanceBefore, uint destBalanceBefore, ERC20 src, ERC20 dest, address destAddress) internal returns(TradeOutcome outcome) { uint userSrcBalanceAfter; uint userDestBalanceAfter; userSrcBalanceAfter = getBalance(src, msg.sender); userDestBalanceAfter = getBalance(dest, destAddress); //protect from underflow require(userDestBalanceAfter > destBalanceBefore); require(srcBalanceBefore > userSrcBalanceAfter); outcome.userDeltaDestAmount = userDestBalanceAfter - destBalanceBefore; outcome.userDeltaSrcAmount = srcBalanceBefore - userSrcBalanceAfter; outcome.actualRate = calcRateFromQty( outcome.userDeltaSrcAmount, outcome.userDeltaDestAmount, getDecimalsSafe(src), getDecimalsSafe(dest) ); } } // File: contracts/vendors/kyber/KyberReserveInterface.sol /// @title Kyber Reserve contract interface KyberReserveInterface { function trade( ERC20 srcToken, uint srcAmount, ERC20 destToken, address destAddress, uint conversionRate, bool validate ) public payable returns(bool); function getConversionRate(ERC20 src, ERC20 dest, uint srcQty, uint blockNumber) public view returns(uint); } // File: contracts/vendors/kyber/WhiteListInterface.sol contract WhiteListInterface { function getUserCapInWei(address user) external view returns (uint userCapWei); } // File: contracts/vendors/kyber/ExpectedRateInterface.sol interface ExpectedRateInterface { function getExpectedRate(ERC20 src, ERC20 dest, uint srcQty) public view returns (uint expectedRate, uint slippageRate); } // File: contracts/vendors/kyber/FeeBurnerInterface.sol interface FeeBurnerInterface { function handleFees (uint tradeWeiAmount, address reserve, address wallet) public returns(bool); } // File: contracts/vendors/kyber/KyberNetwork.sol //////////////////////////////////////////////////////////////////////////////////////////////////////// /// @title Kyber Network main contract contract KyberNetwork is Withdrawable, Utils2, KyberNetworkInterface { uint public negligibleRateDiff = 10; // basic rate steps will be in 0.01% KyberReserveInterface[] public reserves; mapping(address=>bool) public isReserve; WhiteListInterface public whiteListContract; ExpectedRateInterface public expectedRateContract; FeeBurnerInterface public feeBurnerContract; address public kyberNetworkProxyContract; uint public maxGasPriceValue = 50 * 1000 * 1000 * 1000; // 50 gwei bool public isEnabled = false; // network is enabled mapping(bytes32=>uint) public infoFields; // this is only a UI field for external app. mapping(address=>address[]) public reservesPerTokenSrc; //reserves supporting token to eth mapping(address=>address[]) public reservesPerTokenDest;//reserves support eth to token function KyberNetwork(address _admin) public { require(_admin != address(0)); admin = _admin; } event EtherReceival(address indexed sender, uint amount); /* solhint-disable no-complex-fallback */ // To avoid users trying to swap tokens using default payable function. We added this short code // to verify Ethers will be received only from reserves if transferred without a specific function call. function() public payable { require(isReserve[msg.sender]); EtherReceival(msg.sender, msg.value); } /* solhint-enable no-complex-fallback */ struct TradeInput { address trader; ERC20 src; uint srcAmount; ERC20 dest; address destAddress; uint maxDestAmount; uint minConversionRate; address walletId; bytes hint; } function tradeWithHint( address trader, ERC20 src, uint srcAmount, ERC20 dest, address destAddress, uint maxDestAmount, uint minConversionRate, address walletId, bytes hint ) public payable returns(uint) { require(hint.length == 0); require(msg.sender == kyberNetworkProxyContract); TradeInput memory tradeInput; tradeInput.trader = trader; tradeInput.src = src; tradeInput.srcAmount = srcAmount; tradeInput.dest = dest; tradeInput.destAddress = destAddress; tradeInput.maxDestAmount = maxDestAmount; tradeInput.minConversionRate = minConversionRate; tradeInput.walletId = walletId; tradeInput.hint = hint; return trade(tradeInput); } event AddReserveToNetwork(KyberReserveInterface reserve, bool add); /// @notice can be called only by admin /// @dev add or deletes a reserve to/from the network. /// @param reserve The reserve address. /// @param add If true, the add reserve. Otherwise delete reserve. function addReserve(KyberReserveInterface reserve, bool add) public onlyAdmin { if (add) { require(!isReserve[reserve]); reserves.push(reserve); isReserve[reserve] = true; AddReserveToNetwork(reserve, true); } else { isReserve[reserve] = false; // will have trouble if more than 50k reserves... for (uint i = 0; i < reserves.length; i++) { if (reserves[i] == reserve) { reserves[i] = reserves[reserves.length - 1]; reserves.length--; AddReserveToNetwork(reserve, false); break; } } } } event ListReservePairs(address reserve, ERC20 src, ERC20 dest, bool add); /// @notice can be called only by admin /// @dev allow or prevent a specific reserve to trade a pair of tokens /// @param reserve The reserve address. /// @param token token address /// @param ethToToken will it support ether to token trade /// @param tokenToEth will it support token to ether trade /// @param add If true then list this pair, otherwise unlist it. function listPairForReserve(address reserve, ERC20 token, bool ethToToken, bool tokenToEth, bool add) public onlyAdmin { require(isReserve[reserve]); if (ethToToken) { listPairs(reserve, token, false, add); ListReservePairs(reserve, ETH_TOKEN_ADDRESS, token, add); } if (tokenToEth) { listPairs(reserve, token, true, add); if (add) { token.approve(reserve, 2**255); // approve infinity } else { token.approve(reserve, 0); } ListReservePairs(reserve, token, ETH_TOKEN_ADDRESS, add); } setDecimals(token); } function setWhiteList(WhiteListInterface whiteList) public onlyAdmin { require(whiteList != address(0)); whiteListContract = whiteList; } function setExpectedRate(ExpectedRateInterface expectedRate) public onlyAdmin { require(expectedRate != address(0)); expectedRateContract = expectedRate; } function setFeeBurner(FeeBurnerInterface feeBurner) public onlyAdmin { require(feeBurner != address(0)); feeBurnerContract = feeBurner; } function setParams( uint _maxGasPrice, uint _negligibleRateDiff ) public onlyAdmin { require(_negligibleRateDiff <= 100 * 100); // at most 100% maxGasPriceValue = _maxGasPrice; negligibleRateDiff = _negligibleRateDiff; } function setEnable(bool _enable) public onlyAdmin { if (_enable) { require(whiteListContract != address(0)); require(feeBurnerContract != address(0)); require(expectedRateContract != address(0)); require(kyberNetworkProxyContract != address(0)); } isEnabled = _enable; } function setInfo(bytes32 field, uint value) public onlyOperator { infoFields[field] = value; } event KyberProxySet(address proxy, address sender); function setKyberProxy(address networkProxy) public onlyAdmin { require(networkProxy != address(0)); kyberNetworkProxyContract = networkProxy; KyberProxySet(kyberNetworkProxyContract, msg.sender); } /// @dev returns number of reserves /// @return number of reserves function getNumReserves() public view returns(uint) { return reserves.length; } /// @notice should be called off chain with as much gas as needed /// @dev get an array of all reserves /// @return An array of all reserves function getReserves() public view returns(KyberReserveInterface[]) { return reserves; } function maxGasPrice() public view returns(uint) { return maxGasPriceValue; } function getExpectedRate(ERC20 src, ERC20 dest, uint srcQty) public view returns(uint expectedRate, uint slippageRate) { require(expectedRateContract != address(0)); return expectedRateContract.getExpectedRate(src, dest, srcQty); } function getUserCapInWei(address user) public view returns(uint) { return whiteListContract.getUserCapInWei(user); } function getUserCapInTokenWei(address user, ERC20 token) public view returns(uint) { //future feature user; token; require(false); } struct BestRateResult { uint rate; address reserve1; address reserve2; uint weiAmount; uint rateSrcToEth; uint rateEthToDest; uint destAmount; } /// @notice use token address ETH_TOKEN_ADDRESS for ether /// @dev best conversion rate for a pair of tokens, if number of reserves have small differences. randomize /// @param src Src token /// @param dest Destination token /// @return obsolete - used to return best reserve index. not relevant anymore for this API. function findBestRate(ERC20 src, ERC20 dest, uint srcAmount) public view returns(uint obsolete, uint rate) { BestRateResult memory result = findBestRateTokenToToken(src, dest, srcAmount); return(0, result.rate); } function enabled() public view returns(bool) { return isEnabled; } function info(bytes32 field) public view returns(uint) { return infoFields[field]; } /* solhint-disable code-complexity */ // Not sure how solhing defines complexity. Anyway, from our point of view, below code follows the required // algorithm to choose a reserve, it has been tested, reviewed and found to be clear enough. //@dev this function always src or dest are ether. can't do token to token function searchBestRate(ERC20 src, ERC20 dest, uint srcAmount) public view returns(address, uint) { uint bestRate = 0; uint bestReserve = 0; uint numRelevantReserves = 0; //return 1 for ether to ether if (src == dest) return (reserves[bestReserve], PRECISION); address[] memory reserveArr; if (src == ETH_TOKEN_ADDRESS) { reserveArr = reservesPerTokenDest[dest]; } else { reserveArr = reservesPerTokenSrc[src]; } if (reserveArr.length == 0) return (reserves[bestReserve], bestRate); uint[] memory rates = new uint[](reserveArr.length); uint[] memory reserveCandidates = new uint[](reserveArr.length); for (uint i = 0; i < reserveArr.length; i++) { //list all reserves that have this token. rates[i] = (KyberReserveInterface(reserveArr[i])).getConversionRate(src, dest, srcAmount, block.number); if (rates[i] > bestRate) { //best rate is highest rate bestRate = rates[i]; } } if (bestRate > 0) { uint random = 0; uint smallestRelevantRate = (bestRate * 10000) / (10000 + negligibleRateDiff); for (i = 0; i < reserveArr.length; i++) { if (rates[i] >= smallestRelevantRate) { reserveCandidates[numRelevantReserves++] = i; } } if (numRelevantReserves > 1) { //when encountering small rate diff from bestRate. draw from relevant reserves random = uint(block.blockhash(block.number-1)) % numRelevantReserves; } bestReserve = reserveCandidates[random]; bestRate = rates[bestReserve]; } return (reserveArr[bestReserve], bestRate); } /* solhint-enable code-complexity */ function findBestRateTokenToToken(ERC20 src, ERC20 dest, uint srcAmount) internal view returns(BestRateResult result) { (result.reserve1, result.rateSrcToEth) = searchBestRate(src, ETH_TOKEN_ADDRESS, srcAmount); result.weiAmount = calcDestAmount(src, ETH_TOKEN_ADDRESS, srcAmount, result.rateSrcToEth); (result.reserve2, result.rateEthToDest) = searchBestRate(ETH_TOKEN_ADDRESS, dest, result.weiAmount); result.destAmount = calcDestAmount(ETH_TOKEN_ADDRESS, dest, result.weiAmount, result.rateEthToDest); result.rate = calcRateFromQty(srcAmount, result.destAmount, getDecimals(src), getDecimals(dest)); } function listPairs(address reserve, ERC20 token, bool isTokenToEth, bool add) internal { uint i; address[] storage reserveArr = reservesPerTokenDest[token]; if (isTokenToEth) { reserveArr = reservesPerTokenSrc[token]; } for (i = 0; i < reserveArr.length; i++) { if (reserve == reserveArr[i]) { if (add) { break; //already added } else { //remove reserveArr[i] = reserveArr[reserveArr.length - 1]; reserveArr.length--; } } } if (add && i == reserveArr.length) { //if reserve wasn't found add it reserveArr.push(reserve); } } event KyberTrade(address srcAddress, ERC20 srcToken, uint srcAmount, address destAddress, ERC20 destToken, uint destAmount); /* solhint-disable function-max-lines */ // Most of the lins here are functions calls spread over multiple lines. We find this function readable enough // and keep its size as is. /// @notice use token address ETH_TOKEN_ADDRESS for ether /// @dev trade api for kyber network. /// @param tradeInput structure of trade inputs function trade(TradeInput tradeInput) internal returns(uint) { require(isEnabled); require(tx.gasprice <= maxGasPriceValue); require(validateTradeInput(tradeInput.src, tradeInput.srcAmount, tradeInput.dest, tradeInput.destAddress)); BestRateResult memory rateResult = findBestRateTokenToToken(tradeInput.src, tradeInput.dest, tradeInput.srcAmount); require(rateResult.rate > 0); require(rateResult.rate < MAX_RATE); require(rateResult.rate >= tradeInput.minConversionRate); uint actualDestAmount; uint weiAmount; uint actualSrcAmount; (actualSrcAmount, weiAmount, actualDestAmount) = calcActualAmounts(tradeInput.src, tradeInput.dest, tradeInput.srcAmount, tradeInput.maxDestAmount, rateResult); if (actualSrcAmount < tradeInput.srcAmount) { //if there is "change" send back to trader if (tradeInput.src == ETH_TOKEN_ADDRESS) { tradeInput.trader.transfer(tradeInput.srcAmount - actualSrcAmount); } else { tradeInput.src.transfer(tradeInput.trader, (tradeInput.srcAmount - actualSrcAmount)); } } // verify trade size is smaller than user cap require(weiAmount <= getUserCapInWei(tradeInput.trader)); //do the trade //src to ETH require(doReserveTrade( tradeInput.src, actualSrcAmount, ETH_TOKEN_ADDRESS, this, weiAmount, KyberReserveInterface(rateResult.reserve1), rateResult.rateSrcToEth, true)); //Eth to dest require(doReserveTrade( ETH_TOKEN_ADDRESS, weiAmount, tradeInput.dest, tradeInput.destAddress, actualDestAmount, KyberReserveInterface(rateResult.reserve2), rateResult.rateEthToDest, true)); //when src is ether, reserve1 is doing a "fake" trade. (ether to ether) - don't burn. //when dest is ether, reserve2 is doing a "fake" trade. (ether to ether) - don't burn. if (tradeInput.src != ETH_TOKEN_ADDRESS) require(feeBurnerContract.handleFees(weiAmount, rateResult.reserve1, tradeInput.walletId)); if (tradeInput.dest != ETH_TOKEN_ADDRESS) require(feeBurnerContract.handleFees(weiAmount, rateResult.reserve2, tradeInput.walletId)); KyberTrade(tradeInput.trader, tradeInput.src, actualSrcAmount, tradeInput.destAddress, tradeInput.dest, actualDestAmount); return actualDestAmount; } /* solhint-enable function-max-lines */ function calcActualAmounts (ERC20 src, ERC20 dest, uint srcAmount, uint maxDestAmount, BestRateResult rateResult) internal view returns(uint actualSrcAmount, uint weiAmount, uint actualDestAmount) { if (rateResult.destAmount > maxDestAmount) { actualDestAmount = maxDestAmount; weiAmount = calcSrcAmount(ETH_TOKEN_ADDRESS, dest, actualDestAmount, rateResult.rateEthToDest); actualSrcAmount = calcSrcAmount(src, ETH_TOKEN_ADDRESS, weiAmount, rateResult.rateSrcToEth); require(actualSrcAmount <= srcAmount); } else { actualDestAmount = rateResult.destAmount; actualSrcAmount = srcAmount; weiAmount = rateResult.weiAmount; } } /// @notice use token address ETH_TOKEN_ADDRESS for ether /// @dev do one trade with a reserve /// @param src Src token /// @param amount amount of src tokens /// @param dest Destination token /// @param destAddress Address to send tokens to /// @param reserve Reserve to use /// @param validate If true, additional validations are applicable /// @return true if trade is successful function doReserveTrade( ERC20 src, uint amount, ERC20 dest, address destAddress, uint expectedDestAmount, KyberReserveInterface reserve, uint conversionRate, bool validate ) internal returns(bool) { uint callValue = 0; if (src == dest) { //this is for a "fake" trade when both src and dest are ethers. if (destAddress != (address(this))) destAddress.transfer(amount); return true; } if (src == ETH_TOKEN_ADDRESS) { callValue = amount; } // reserve sends tokens/eth to network. network sends it to destination require(reserve.trade.value(callValue)(src, amount, dest, this, conversionRate, validate)); if (destAddress != address(this)) { //for token to token dest address is network. and Ether / token already here... if (dest == ETH_TOKEN_ADDRESS) { destAddress.transfer(expectedDestAmount); } else { require(dest.transfer(destAddress, expectedDestAmount)); } } return true; } /// @notice use token address ETH_TOKEN_ADDRESS for ether /// @dev checks that user sent ether/tokens to contract before trade /// @param src Src token /// @param srcAmount amount of src tokens /// @return true if tradeInput is valid function validateTradeInput(ERC20 src, uint srcAmount, ERC20 dest, address destAddress) internal view returns(bool) { require(srcAmount <= MAX_QTY); require(srcAmount != 0); require(destAddress != address(0)); require(src != dest); if (src == ETH_TOKEN_ADDRESS) { require(msg.value == srcAmount); } else { require(msg.value == 0); //funds should have been moved to this contract already. require(src.balanceOf(this) >= srcAmount); } return true; } } // File: contracts/interfaces/Token.sol contract Token { function transfer(address _to, uint _value) public returns (bool success); function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); function allowance(address _owner, address _spender) public view returns (uint256 remaining); function approve(address _spender, uint256 _value) public returns (bool success); function increaseApproval (address _spender, uint _addedValue) public returns (bool success); function balanceOf(address _owner) public view returns (uint256 balance); } // File: contracts/interfaces/TokenConverter.sol contract TokenConverter { address public constant ETH_ADDRESS = 0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee; function getReturn(Token _fromToken, Token _toToken, uint256 _fromAmount) external view returns (uint256 amount); function convert(Token _fromToken, Token _toToken, uint256 _fromAmount, uint256 _minReturn) external payable returns (uint256 amount); } // File: contracts/interfaces/AvailableProvider.sol interface AvailableProvider { function isAvailable(Token _from, Token _to, uint256 _amount) external view returns (bool); } // File: contracts/utils/Ownable.sol contract Ownable { address public owner; event SetOwner(address _owner); modifier onlyOwner() { require(msg.sender == owner, "msg.sender is not the owner"); _; } constructor() public { owner = msg.sender; emit SetOwner(msg.sender); } /** @dev Transfers the ownership of the contract. @param _to Address of the new owner */ function transferTo(address _to) public onlyOwner returns (bool) { require(_to != address(0), "Can't transfer to address 0x0"); emit SetOwner(_to); owner = _to; return true; } } // File: contracts/KyberProxy.sol contract KyberConverter is TokenConverter, AvailableProvider, Ownable { ERC20 constant internal ETH_TOKEN_ADDRESS = ERC20(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee); KyberNetworkProxy kyber; event Swap(address indexed sender, ERC20 srcToken, ERC20 destToken, uint amount); event WithdrawTokens(address _token, address _to, uint256 _amount); event WithdrawEth(address _to, uint256 _amount); event SetKyber(address _kyber); constructor (KyberNetworkProxy _kyber) public { kyber = _kyber; emit SetKyber(_kyber); } function setKyber(KyberNetworkProxy _kyber) external onlyOwner returns (bool) { kyber = _kyber; emit SetKyber(_kyber); return true; } function isAvailable(Token, Token, uint256) external view returns (bool) { KyberNetworkProxy _kyber = kyber; return tx.gasprice <= _kyber.maxGasPrice() && _kyber.enabled(); } function getReturn( Token from, Token to, uint256 srcQty ) external view returns (uint256) { ERC20 srcToken = ERC20(from); ERC20 destToken = ERC20(to); (uint256 amount,) = kyber.getExpectedRate(srcToken, destToken, srcQty); return amount; } function convert( Token from, Token to, uint256 srcQty, uint256 minReturn ) external payable returns (uint256 destAmount) { ERC20 srcToken = ERC20(from); ERC20 destToken = ERC20(to); if (srcToken == ETH_TOKEN_ADDRESS && destToken != ETH_TOKEN_ADDRESS) { require(msg.value == srcQty, "ETH not enought"); execSwapEtherToToken(srcToken, srcQty, msg.sender); } else if (srcToken != ETH_TOKEN_ADDRESS && destToken == ETH_TOKEN_ADDRESS) { require(msg.value == 0, "ETH not required"); execSwapTokenToEther(srcToken, srcQty, destToken); } else { require(msg.value == 0, "ETH not required"); execSwapTokenToToken(srcToken, srcQty, destToken, msg.sender); } require(destAmount > minReturn, "Return amount too low"); emit Swap(msg.sender, srcToken, destToken, destAmount); return destAmount; } /* @dev Swap the user's ETH to ERC20 token @param token destination token contract address @param destAddress address to send swapped tokens to */ function execSwapEtherToToken( ERC20 token, uint srcQty, address destAddress ) internal returns (uint) { // Swap the ETH to ERC20 token uint destAmount = kyber.swapEtherToToken.value(srcQty)(token, 0); // Send the swapped tokens to the destination address require(token.transfer(destAddress, destAmount), "Error sending tokens"); return destAmount; } /* @dev Swap the user's ERC20 token to ETH @param token source token contract address @param tokenQty amount of source tokens @param destAddress address to send swapped ETH to */ function execSwapTokenToEther( ERC20 token, uint256 tokenQty, address destAddress ) internal returns (uint) { // Check that the player has transferred the token to this contract require(token.transferFrom(msg.sender, this, tokenQty), "Error pulling tokens"); // Set the spender's token allowance to tokenQty require(token.approve(kyber, tokenQty), "Error pulling tokens"); // Swap the ERC20 token to ETH uint destAmount = kyber.swapTokenToEther(token, tokenQty, 0); // Send the swapped ETH to the destination address require(destAddress.send(destAmount), "Error sending ETH"); return destAmount; } /* @dev Swap the user's ERC20 token to another ERC20 token @param srcToken source token contract address @param srcQty amount of source tokens @param destToken destination token contract address @param destAddress address to send swapped tokens to */ function execSwapTokenToToken( ERC20 srcToken, uint256 srcQty, ERC20 destToken, address destAddress ) internal returns (uint) { // Check that the player has transferred the token to this contract require(srcToken.transferFrom(msg.sender, this, srcQty), "Error pulling tokens"); // Set the spender's token allowance to tokenQty require(srcToken.approve(kyber, srcQty), "Error approve transfer tokens"); // Swap the ERC20 token to ERC20 uint destAmount = kyber.swapTokenToToken(srcToken, srcQty, destToken, 0); // Send the swapped tokens to the destination address require(destToken.transfer(destAddress, destAmount), "Error sending tokens"); return destAmount; } function withdrawTokens( Token _token, address _to, uint256 _amount ) external onlyOwner returns (bool) { emit WithdrawTokens(_token, _to, _amount); return _token.transfer(_to, _amount); } function withdrawEther( address _to, uint256 _amount ) external onlyOwner { emit WithdrawEth(_to, _amount); _to.transfer(_amount); } function setConverter( KyberNetworkProxy _converter ) public onlyOwner returns (bool) { kyber = _converter; } function getConverter() public view returns (address) { return address(kyber); } function() external payable {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":true,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"srcQty","type":"uint256"}],"name":"getReturn","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getConverter","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_kyber","type":"address"}],"name":"setKyber","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"withdrawEther","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"withdrawTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"srcQty","type":"uint256"},{"name":"minReturn","type":"uint256"}],"name":"convert","outputs":[{"name":"destAmount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"isAvailable","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"}],"name":"transferTo","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"ETH_ADDRESS","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_converter","type":"address"}],"name":"setConverter","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_kyber","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"srcToken","type":"address"},{"indexed":false,"name":"destToken","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_token","type":"address"},{"indexed":false,"name":"_to","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"WithdrawTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_to","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"WithdrawEth","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_kyber","type":"address"}],"name":"SetKyber","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_owner","type":"address"}],"name":"SetOwner","type":"event"}]
Contract Creation Code
608060405234801561001057600080fd5b5060405160208061143e833981016040818152915160008054600160a060020a03191633908117909155825291517f167d3e9c1016ab80e58802ca9da10ce5c6a0f4debc46a2e7a2cd9e56899a4fb59181900360200190a160018054600160a060020a038316600160a060020a0319909116811790915560408051918252517fedfa4fa43841270381832dde87509ff058494f5d1085fd217d0ed07aa19e1b539181900360200190a150611375806100c96000396000f3006080604052600436106100955763ffffffff60e060020a6000350416631e1401f881146100975780632261b07f146100d3578063328a7e9714610104578063522f6815146101395780635e35359e1461015d57806375892cf1146101875780638da5cb5b146101a75780638ee0522a146101bc578063a03fa7e3146101e6578063a734f06e14610207578063b19337a41461021c575b005b3480156100a357600080fd5b506100c1600160a060020a036004358116906024351660443561023d565b60408051918252519081900360200190f35b3480156100df57600080fd5b506100e86102ef565b60408051600160a060020a039092168252519081900360200190f35b34801561011057600080fd5b50610125600160a060020a03600435166102fe565b604080519115158252519081900360200190f35b34801561014557600080fd5b50610095600160a060020a03600435166024356103b5565b34801561016957600080fd5b50610125600160a060020a0360043581169060243516604435610484565b6100c1600160a060020a03600435811690602435166044356064356105b6565b3480156101b357600080fd5b506100e8610831565b3480156101c857600080fd5b50610125600160a060020a0360043581169060243516604435610840565b3480156101f257600080fd5b50610125600160a060020a036004351661094c565b34801561021357600080fd5b506100e8610a6b565b34801561022857600080fd5b50610125600160a060020a0360043516610a83565b600154604080517f809a9e55000000000000000000000000000000000000000000000000000000008152600160a060020a03808716600483015280861660248301526044820185905282516000948894889487949092169263809a9e5592606480820193929182900301818787803b1580156102b857600080fd5b505af11580156102cc573d6000803e3d6000fd5b505050506040513d60408110156102e257600080fd5b5051979650505050505050565b600154600160a060020a031690565b60008054600160a060020a0316331461034f576040805160e560020a62461bcd02815260206004820152601b602482015260008051602061132a833981519152604482015290519081900360640190fd5b60018054600160a060020a03841673ffffffffffffffffffffffffffffffffffffffff19909116811790915560408051918252517fedfa4fa43841270381832dde87509ff058494f5d1085fd217d0ed07aa19e1b539181900360200190a1506001919050565b600054600160a060020a03163314610405576040805160e560020a62461bcd02815260206004820152601b602482015260008051602061132a833981519152604482015290519081900360640190fd5b60408051600160a060020a03841681526020810183905281517fccbd99ba6da8f29b2a4f65e474e3c3973564d356c162c08d45f3dc7f0cb5b3aa929181900390910190a1604051600160a060020a0383169082156108fc029083906000818181858888f1935050505015801561047f573d6000803e3d6000fd5b505050565b60008054600160a060020a031633146104d5576040805160e560020a62461bcd02815260206004820152601b602482015260008051602061132a833981519152604482015290519081900360640190fd5b60408051600160a060020a0380871682528516602082015280820184905290517f70082d08c003c5341f2401bec1c2ae1dbcdc29ae17e9cc5633fa617caa8acd4c9181900360600190a183600160a060020a031663a9059cbb84846040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b15801561058257600080fd5b505af1158015610596573d6000803e3d6000fd5b505050506040513d60208110156105ac57600080fd5b5051949350505050565b60008484600160a060020a03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480156106035750600160a060020a03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b156106705734851461065f576040805160e560020a62461bcd02815260206004820152600f60248201527f455448206e6f7420656e6f756768740000000000000000000000000000000000604482015290519081900360640190fd5b61066a828633610b05565b50610783565b600160a060020a03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015906106b95750600160a060020a03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b1561071f573415610714576040805160e560020a62461bcd02815260206004820152601060248201527f455448206e6f7420726571756972656400000000000000000000000000000000604482015290519081900360640190fd5b61066a828683610ca0565b3415610775576040805160e560020a62461bcd02815260206004820152601060248201527f455448206e6f7420726571756972656400000000000000000000000000000000604482015290519081900360640190fd5b61078182868333610fa7565b505b8383116107da576040805160e560020a62461bcd02815260206004820152601560248201527f52657475726e20616d6f756e7420746f6f206c6f770000000000000000000000604482015290519081900360640190fd5b60408051600160a060020a03848116825283166020820152808201859052905133917fffebebfb273923089a3ed6bac0fd4686ac740307859becadeb82f998e30db614919081900360600190a25050949350505050565b600054600160a060020a031681565b600154604080517f3de39c110000000000000000000000000000000000000000000000000000000081529051600092600160a060020a0316918291633de39c119160048082019260209290919082900301818887803b1580156108a257600080fd5b505af11580156108b6573d6000803e3d6000fd5b505050506040513d60208110156108cc57600080fd5b50513a11801590610943575080600160a060020a031663238dafe06040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561091657600080fd5b505af115801561092a573d6000803e3d6000fd5b505050506040513d602081101561094057600080fd5b50515b95945050505050565b60008054600160a060020a0316331461099d576040805160e560020a62461bcd02815260206004820152601b602482015260008051602061132a833981519152604482015290519081900360640190fd5b600160a060020a03821615156109fd576040805160e560020a62461bcd02815260206004820152601d60248201527f43616e2774207472616e7366657220746f206164647265737320307830000000604482015290519081900360640190fd5b60408051600160a060020a038416815290517f167d3e9c1016ab80e58802ca9da10ce5c6a0f4debc46a2e7a2cd9e56899a4fb59181900360200190a15060008054600160a060020a03831673ffffffffffffffffffffffffffffffffffffffff199091161790556001919050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60008054600160a060020a03163314610ad4576040805160e560020a62461bcd02815260206004820152601b602482015260008051602061132a833981519152604482015290519081900360640190fd5b6001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03939093169290921790915590565b600154604080517f7a2a0456000000000000000000000000000000000000000000000000000000008152600160a060020a038681166004830152600060248301819052925192938493911691637a2a045691879160448082019260209290919082900301818588803b158015610b7a57600080fd5b505af1158015610b8e573d6000803e3d6000fd5b50505050506040513d6020811015610ba557600080fd5b5051604080517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a0386811660048301526024820184905291519293509087169163a9059cbb916044808201926020929091908290030181600087803b158015610c1657600080fd5b505af1158015610c2a573d6000803e3d6000fd5b505050506040513d6020811015610c4057600080fd5b50511515610c98576040805160e560020a62461bcd02815260206004820152601460248201527f4572726f722073656e64696e6720746f6b656e73000000000000000000000000604482015290519081900360640190fd5b949350505050565b604080517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810184905290516000918291600160a060020a038716916323b872dd91606480830192602092919082900301818787803b158015610d1257600080fd5b505af1158015610d26573d6000803e3d6000fd5b505050506040513d6020811015610d3c57600080fd5b50511515610d94576040805160e560020a62461bcd02815260206004820152601460248201527f4572726f722070756c6c696e6720746f6b656e73000000000000000000000000604482015290519081900360640190fd5b600154604080517f095ea7b3000000000000000000000000000000000000000000000000000000008152600160a060020a0392831660048201526024810187905290519187169163095ea7b3916044808201926020929091908290030181600087803b158015610e0357600080fd5b505af1158015610e17573d6000803e3d6000fd5b505050506040513d6020811015610e2d57600080fd5b50511515610e85576040805160e560020a62461bcd02815260206004820152601460248201527f4572726f722070756c6c696e6720746f6b656e73000000000000000000000000604482015290519081900360640190fd5b600154604080517f3bba21dc000000000000000000000000000000000000000000000000000000008152600160a060020a038881166004830152602482018890526000604483018190529251931692633bba21dc92606480840193602093929083900390910190829087803b158015610efd57600080fd5b505af1158015610f11573d6000803e3d6000fd5b505050506040513d6020811015610f2757600080fd5b5051604051909150600160a060020a0384169082156108fc029083906000818181858888f193505050501515610c98576040805160e560020a62461bcd02815260206004820152601160248201527f4572726f722073656e64696e6720455448000000000000000000000000000000604482015290519081900360640190fd5b604080517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810185905290516000918291600160a060020a038816916323b872dd91606480830192602092919082900301818787803b15801561101957600080fd5b505af115801561102d573d6000803e3d6000fd5b505050506040513d602081101561104357600080fd5b5051151561109b576040805160e560020a62461bcd02815260206004820152601460248201527f4572726f722070756c6c696e6720746f6b656e73000000000000000000000000604482015290519081900360640190fd5b600154604080517f095ea7b3000000000000000000000000000000000000000000000000000000008152600160a060020a0392831660048201526024810188905290519188169163095ea7b3916044808201926020929091908290030181600087803b15801561110a57600080fd5b505af115801561111e573d6000803e3d6000fd5b505050506040513d602081101561113457600080fd5b5051151561118c576040805160e560020a62461bcd02815260206004820152601d60248201527f4572726f7220617070726f7665207472616e7366657220746f6b656e73000000604482015290519081900360640190fd5b600154604080517f7409e2eb000000000000000000000000000000000000000000000000000000008152600160a060020a0389811660048301526024820189905287811660448301526000606483018190529251931692637409e2eb92608480840193602093929083900390910190829087803b15801561120c57600080fd5b505af1158015611220573d6000803e3d6000fd5b505050506040513d602081101561123657600080fd5b5051604080517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a0386811660048301526024820184905291519293509086169163a9059cbb916044808201926020929091908290030181600087803b1580156112a757600080fd5b505af11580156112bb573d6000803e3d6000fd5b505050506040513d60208110156112d157600080fd5b50511515610943576040805160e560020a62461bcd02815260206004820152601460248201527f4572726f722073656e64696e6720746f6b656e73000000000000000000000000604482015290519081900360640190fd006d73672e73656e646572206973206e6f7420746865206f776e65720000000000a165627a7a7230582003dbd8e30aa5925964bc0c274ea4b635559cd96f6f81c9e25949dfe4779c6b450029000000000000000000000000818e6fecd516ecc3849daf6845e3ec868087b755
Deployed Bytecode
0x6080604052600436106100955763ffffffff60e060020a6000350416631e1401f881146100975780632261b07f146100d3578063328a7e9714610104578063522f6815146101395780635e35359e1461015d57806375892cf1146101875780638da5cb5b146101a75780638ee0522a146101bc578063a03fa7e3146101e6578063a734f06e14610207578063b19337a41461021c575b005b3480156100a357600080fd5b506100c1600160a060020a036004358116906024351660443561023d565b60408051918252519081900360200190f35b3480156100df57600080fd5b506100e86102ef565b60408051600160a060020a039092168252519081900360200190f35b34801561011057600080fd5b50610125600160a060020a03600435166102fe565b604080519115158252519081900360200190f35b34801561014557600080fd5b50610095600160a060020a03600435166024356103b5565b34801561016957600080fd5b50610125600160a060020a0360043581169060243516604435610484565b6100c1600160a060020a03600435811690602435166044356064356105b6565b3480156101b357600080fd5b506100e8610831565b3480156101c857600080fd5b50610125600160a060020a0360043581169060243516604435610840565b3480156101f257600080fd5b50610125600160a060020a036004351661094c565b34801561021357600080fd5b506100e8610a6b565b34801561022857600080fd5b50610125600160a060020a0360043516610a83565b600154604080517f809a9e55000000000000000000000000000000000000000000000000000000008152600160a060020a03808716600483015280861660248301526044820185905282516000948894889487949092169263809a9e5592606480820193929182900301818787803b1580156102b857600080fd5b505af11580156102cc573d6000803e3d6000fd5b505050506040513d60408110156102e257600080fd5b5051979650505050505050565b600154600160a060020a031690565b60008054600160a060020a0316331461034f576040805160e560020a62461bcd02815260206004820152601b602482015260008051602061132a833981519152604482015290519081900360640190fd5b60018054600160a060020a03841673ffffffffffffffffffffffffffffffffffffffff19909116811790915560408051918252517fedfa4fa43841270381832dde87509ff058494f5d1085fd217d0ed07aa19e1b539181900360200190a1506001919050565b600054600160a060020a03163314610405576040805160e560020a62461bcd02815260206004820152601b602482015260008051602061132a833981519152604482015290519081900360640190fd5b60408051600160a060020a03841681526020810183905281517fccbd99ba6da8f29b2a4f65e474e3c3973564d356c162c08d45f3dc7f0cb5b3aa929181900390910190a1604051600160a060020a0383169082156108fc029083906000818181858888f1935050505015801561047f573d6000803e3d6000fd5b505050565b60008054600160a060020a031633146104d5576040805160e560020a62461bcd02815260206004820152601b602482015260008051602061132a833981519152604482015290519081900360640190fd5b60408051600160a060020a0380871682528516602082015280820184905290517f70082d08c003c5341f2401bec1c2ae1dbcdc29ae17e9cc5633fa617caa8acd4c9181900360600190a183600160a060020a031663a9059cbb84846040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b15801561058257600080fd5b505af1158015610596573d6000803e3d6000fd5b505050506040513d60208110156105ac57600080fd5b5051949350505050565b60008484600160a060020a03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480156106035750600160a060020a03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b156106705734851461065f576040805160e560020a62461bcd02815260206004820152600f60248201527f455448206e6f7420656e6f756768740000000000000000000000000000000000604482015290519081900360640190fd5b61066a828633610b05565b50610783565b600160a060020a03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015906106b95750600160a060020a03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b1561071f573415610714576040805160e560020a62461bcd02815260206004820152601060248201527f455448206e6f7420726571756972656400000000000000000000000000000000604482015290519081900360640190fd5b61066a828683610ca0565b3415610775576040805160e560020a62461bcd02815260206004820152601060248201527f455448206e6f7420726571756972656400000000000000000000000000000000604482015290519081900360640190fd5b61078182868333610fa7565b505b8383116107da576040805160e560020a62461bcd02815260206004820152601560248201527f52657475726e20616d6f756e7420746f6f206c6f770000000000000000000000604482015290519081900360640190fd5b60408051600160a060020a03848116825283166020820152808201859052905133917fffebebfb273923089a3ed6bac0fd4686ac740307859becadeb82f998e30db614919081900360600190a25050949350505050565b600054600160a060020a031681565b600154604080517f3de39c110000000000000000000000000000000000000000000000000000000081529051600092600160a060020a0316918291633de39c119160048082019260209290919082900301818887803b1580156108a257600080fd5b505af11580156108b6573d6000803e3d6000fd5b505050506040513d60208110156108cc57600080fd5b50513a11801590610943575080600160a060020a031663238dafe06040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561091657600080fd5b505af115801561092a573d6000803e3d6000fd5b505050506040513d602081101561094057600080fd5b50515b95945050505050565b60008054600160a060020a0316331461099d576040805160e560020a62461bcd02815260206004820152601b602482015260008051602061132a833981519152604482015290519081900360640190fd5b600160a060020a03821615156109fd576040805160e560020a62461bcd02815260206004820152601d60248201527f43616e2774207472616e7366657220746f206164647265737320307830000000604482015290519081900360640190fd5b60408051600160a060020a038416815290517f167d3e9c1016ab80e58802ca9da10ce5c6a0f4debc46a2e7a2cd9e56899a4fb59181900360200190a15060008054600160a060020a03831673ffffffffffffffffffffffffffffffffffffffff199091161790556001919050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60008054600160a060020a03163314610ad4576040805160e560020a62461bcd02815260206004820152601b602482015260008051602061132a833981519152604482015290519081900360640190fd5b6001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03939093169290921790915590565b600154604080517f7a2a0456000000000000000000000000000000000000000000000000000000008152600160a060020a038681166004830152600060248301819052925192938493911691637a2a045691879160448082019260209290919082900301818588803b158015610b7a57600080fd5b505af1158015610b8e573d6000803e3d6000fd5b50505050506040513d6020811015610ba557600080fd5b5051604080517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a0386811660048301526024820184905291519293509087169163a9059cbb916044808201926020929091908290030181600087803b158015610c1657600080fd5b505af1158015610c2a573d6000803e3d6000fd5b505050506040513d6020811015610c4057600080fd5b50511515610c98576040805160e560020a62461bcd02815260206004820152601460248201527f4572726f722073656e64696e6720746f6b656e73000000000000000000000000604482015290519081900360640190fd5b949350505050565b604080517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810184905290516000918291600160a060020a038716916323b872dd91606480830192602092919082900301818787803b158015610d1257600080fd5b505af1158015610d26573d6000803e3d6000fd5b505050506040513d6020811015610d3c57600080fd5b50511515610d94576040805160e560020a62461bcd02815260206004820152601460248201527f4572726f722070756c6c696e6720746f6b656e73000000000000000000000000604482015290519081900360640190fd5b600154604080517f095ea7b3000000000000000000000000000000000000000000000000000000008152600160a060020a0392831660048201526024810187905290519187169163095ea7b3916044808201926020929091908290030181600087803b158015610e0357600080fd5b505af1158015610e17573d6000803e3d6000fd5b505050506040513d6020811015610e2d57600080fd5b50511515610e85576040805160e560020a62461bcd02815260206004820152601460248201527f4572726f722070756c6c696e6720746f6b656e73000000000000000000000000604482015290519081900360640190fd5b600154604080517f3bba21dc000000000000000000000000000000000000000000000000000000008152600160a060020a038881166004830152602482018890526000604483018190529251931692633bba21dc92606480840193602093929083900390910190829087803b158015610efd57600080fd5b505af1158015610f11573d6000803e3d6000fd5b505050506040513d6020811015610f2757600080fd5b5051604051909150600160a060020a0384169082156108fc029083906000818181858888f193505050501515610c98576040805160e560020a62461bcd02815260206004820152601160248201527f4572726f722073656e64696e6720455448000000000000000000000000000000604482015290519081900360640190fd5b604080517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810185905290516000918291600160a060020a038816916323b872dd91606480830192602092919082900301818787803b15801561101957600080fd5b505af115801561102d573d6000803e3d6000fd5b505050506040513d602081101561104357600080fd5b5051151561109b576040805160e560020a62461bcd02815260206004820152601460248201527f4572726f722070756c6c696e6720746f6b656e73000000000000000000000000604482015290519081900360640190fd5b600154604080517f095ea7b3000000000000000000000000000000000000000000000000000000008152600160a060020a0392831660048201526024810188905290519188169163095ea7b3916044808201926020929091908290030181600087803b15801561110a57600080fd5b505af115801561111e573d6000803e3d6000fd5b505050506040513d602081101561113457600080fd5b5051151561118c576040805160e560020a62461bcd02815260206004820152601d60248201527f4572726f7220617070726f7665207472616e7366657220746f6b656e73000000604482015290519081900360640190fd5b600154604080517f7409e2eb000000000000000000000000000000000000000000000000000000008152600160a060020a0389811660048301526024820189905287811660448301526000606483018190529251931692637409e2eb92608480840193602093929083900390910190829087803b15801561120c57600080fd5b505af1158015611220573d6000803e3d6000fd5b505050506040513d602081101561123657600080fd5b5051604080517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a0386811660048301526024820184905291519293509086169163a9059cbb916044808201926020929091908290030181600087803b1580156112a757600080fd5b505af11580156112bb573d6000803e3d6000fd5b505050506040513d60208110156112d157600080fd5b50511515610943576040805160e560020a62461bcd02815260206004820152601460248201527f4572726f722073656e64696e6720746f6b656e73000000000000000000000000604482015290519081900360640190fd006d73672e73656e646572206973206e6f7420746865206f776e65720000000000a165627a7a7230582003dbd8e30aa5925964bc0c274ea4b635559cd96f6f81c9e25949dfe4779c6b450029
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000818e6fecd516ecc3849daf6845e3ec868087b755
-----Decoded View---------------
Arg [0] : _kyber (address): 0x818E6FECD516Ecc3849DAf6845e3EC868087B755
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000818e6fecd516ecc3849daf6845e3ec868087b755
Swarm Source
bzzr://03dbd8e30aa5925964bc0c274ea4b635559cd96f6f81c9e25949dfe4779c6b45
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 29 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.