Transaction Hash:
Block:
10285597 at Jun-17-2020 09:14:50 PM +UTC
Transaction Fee:
0.011425779 ETH
$21.10
Gas Used:
423,177 Gas / 27 Gwei
Emitted Events:
20 |
BandToken.Transfer( from=[Sender] 0xa14710e6a47007116b889794b2b22482d1ec76ad, to=KyberNetwork, value=1078047427636864622705 )
|
21 |
BandToken.Approval( owner=[Sender] 0xa14710e6a47007116b889794b2b22482d1ec76ad, spender=[Receiver] KyberNetworkProxy, value=57896044618658097711785492504343953926634992332820282018650744576319700197263 )
|
22 |
BandToken.Transfer( from=KyberNetwork, to=KyberReserve, value=1078047427636864622705 )
|
23 |
BandToken.Approval( owner=KyberNetwork, spender=KyberReserve, value=57896044618658097711785492504343953926634992332820280817469388237321956952250 )
|
24 |
KyberNetwork.EtherReceival( sender=KyberReserve, amount=5638204898064034402 )
|
25 |
KyberReserve.TradeExecute( origin=KyberNetwork, src=BandToken, srcAmount=1078047427636864622705, destToken=0xEeeeeEee...eeeeeEEeE, destAmount=5638204898064034402, destAddress=KyberNetwork )
|
26 |
FeeBurner.AssignFeeToWallet( reserve=KyberReserve, wallet=0xF1AA99C6...E35Cc504d, walletFee=1333662890827762704 )
|
27 |
FeeBurner.AssignBurnFees( reserve=KyberReserve, burnFee=1333662890827762705 )
|
28 |
KyberNetwork.KyberTrade( trader=[Sender] 0xa14710e6a47007116b889794b2b22482d1ec76ad, src=BandToken, dest=0xEeeeeEee...eeeeeEEeE, srcAmount=1078047427636864622705, dstAmount=5638204898064034402, destAddress=[Sender] 0xa14710e6a47007116b889794b2b22482d1ec76ad, ethWeiValue=5638204898064034402, reserve1=KyberReserve, reserve2=0x00000000...000000000, hint=0x5045524D )
|
29 |
KyberNetworkProxy.ExecuteTrade( trader=[Sender] 0xa14710e6a47007116b889794b2b22482d1ec76ad, src=BandToken, dest=0xEeeeeEee...eeeeeEEeE, actualSrcAmount=1078047427636864622705, actualDestAmount=5638204898064034402 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x5c594600...37E8598ED | |||||
0x65bF64Ff...77ced86Cd | (Kyber: Contract) | ||||
0x8007aa43...E5fF626d1 | (Kyber: Fee Burner) | ||||
0xA14710E6...2D1Ec76Ad |
0.103678097 Eth
Nonce: 3
|
5.730457216064034402 Eth
Nonce: 4
| 5.626779119064034402 | ||
0xb06Cf173...53D8E4f90 | (Kyber: Reserve BAND) | 86.166688332253118955 Eth | 80.528483434189084553 Eth | 5.638204898064034402 | |
0xBA11D00c...A186d7f55 | |||||
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 1,526.851362598759384206 Eth | 1,526.862788377759384206 Eth | 0.011425779 |
Execution Trace
KyberNetworkProxy.tradeWithHint( src=0xBA11D00c5f74255f56a5E366F4F77f5A186d7f55, srcAmount=1078047427636864622705, dest=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, destAddress=0xA14710E6a47007116b889794b2B22482D1Ec76Ad, maxDestAmount=57896044618658097711785492504343953926634992332820282019728792003956564819968, minConversionRate=5073115162577374, walletId=0xF1AA99C69715F423086008eB9D06Dc1E35Cc504d, hint=0x5045524D ) => ( 5638204898064034402 )
-
BandToken.balanceOf( owner=0xA14710E6a47007116b889794b2B22482D1Ec76Ad ) => ( 1078047427636864622705 )
-
BandToken.transferFrom( from=0xA14710E6a47007116b889794b2B22482D1Ec76Ad, to=0x65bF64Ff5f51272f729BDcD7AcFB00677ced86Cd, value=1078047427636864622705 ) => ( True )
KyberNetwork.tradeWithHint( trader=0xA14710E6a47007116b889794b2B22482D1Ec76Ad, src=0xBA11D00c5f74255f56a5E366F4F77f5A186d7f55, srcAmount=1078047427636864622705, dest=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, destAddress=0xA14710E6a47007116b889794b2B22482D1Ec76Ad, maxDestAmount=57896044618658097711785492504343953926634992332820282019728792003956564819968, minConversionRate=5073115162577374, walletId=0xF1AA99C69715F423086008eB9D06Dc1E35Cc504d, hint=0x5045524D ) => ( 5638204898064034402 )
-
BandToken.balanceOf( owner=0x65bF64Ff5f51272f729BDcD7AcFB00677ced86Cd ) => ( 1078047427636864631353 )
KyberReserve.getConversionRate( src=0xBA11D00c5f74255f56a5E366F4F77f5A186d7f55, dest=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, srcQty=1078047427636864622705, blockNumber=10285597 ) => ( 5230015631523067 )
-
LiquidityConversionRates.getRate( conversionToken=0xBA11D00c5f74255f56a5E366F4F77f5A186d7f55, currentBlockNumber=10285597, buy=False, qtyInSrcWei=1078047427636864622705 ) => ( 5230015631523067 )
-
KyberUniswapReserve.getConversionRate( src=0xBA11D00c5f74255f56a5E366F4F77f5A186d7f55, dest=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, srcQty=1078047427636864622705, blockNumber=10285597 ) => ( 4510799327771562 )
Vyper_contract.getTokenToEthInputPrice( tokens_sold=1078047427636864622705 ) => ( out=4862855611890231484 )
Vyper_contract.getTokenToEthInputPrice( tokens_sold=1078047427636864622705 ) => ( out=4862855611890231484 )
-
BandToken.balanceOf( owner=0x88616Cf228FFb3fB8ba336592A79A53De53D05eF ) => ( 5778184528778478810244 )
-
Vyper_contract.getEthToTokenInputPrice( eth_sold=4862855611890231484 ) => ( out=781345242876851318536 )
Vyper_contract.getEthToTokenInputPrice( eth_sold=4862855611890231484 ) => ( out=781345242876851318536 )
-
BandToken.balanceOf( owner=0x88616Cf228FFb3fB8ba336592A79A53De53D05eF ) => ( 5778184528778478810244 )
-
KyberReserve.trade( srcToken=0xBA11D00c5f74255f56a5E366F4F77f5A186d7f55, srcAmount=1078047427636864622705, destToken=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, destAddress=0x65bF64Ff5f51272f729BDcD7AcFB00677ced86Cd, conversionRate=5230015631523067, validate=True ) => ( True )
-
LiquidityConversionRates.recordImbalance( conversionToken=0xBA11D00c5f74255f56a5E366F4F77f5A186d7f55, buyAmountInTwei=-1078047427636864622705, rateUpdateBlock=0, currentBlock=10285597 )
-
BandToken.transferFrom( from=0x65bF64Ff5f51272f729BDcD7AcFB00677ced86Cd, to=0xb06Cf173DA7E297aa6268139c7Cb67C53D8E4f90, value=1078047427636864622705 ) => ( True )
- ETH 5.638204898064034402
KyberNetwork.CALL( )
-
- ETH 5.638204898064034402
0xa14710e6a47007116b889794b2b22482d1ec76ad.CALL( )
-
FeeBurner.handleFees( tradeWeiAmount=5638204898064034402, reserve=0xb06Cf173DA7E297aa6268139c7Cb67C53D8E4f90, wallet=0xF1AA99C69715F423086008eB9D06Dc1E35Cc504d ) => ( True )
-
-
BandToken.balanceOf( owner=0xA14710E6a47007116b889794b2B22482D1Ec76Ad ) => ( 0 )
tradeWithHint[KyberNetworkProxy (ln:462)]
getBalance[KyberNetworkProxy (ln:480)]
getBalance[KyberNetworkProxy (ln:481)]
transferFrom[KyberNetworkProxy (ln:486)]
value[KyberNetworkProxy (ln:489)]
calculateTradeOutcome[KyberNetworkProxy (ln:501)]
getBalance[KyberNetworkProxy (ln:568)]
getBalance[KyberNetworkProxy (ln:569)]
calcRateFromQty[KyberNetworkProxy (ln:578)]
getDecimalsSafe[KyberNetworkProxy (ln:581)]
getDecimalsSafe[KyberNetworkProxy (ln:582)]
ExecuteTrade[KyberNetworkProxy (ln:513)]
File 1 of 9: KyberNetworkProxy
File 2 of 9: KyberNetwork
File 3 of 9: BandToken
File 4 of 9: KyberReserve
File 5 of 9: FeeBurner
File 6 of 9: LiquidityConversionRates
File 7 of 9: KyberUniswapReserve
File 8 of 9: Vyper_contract
File 9 of 9: Vyper_contract
pragma solidity 0.4.18; // File: contracts/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/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/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/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/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/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/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; function PermissionGroups() 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)); 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)); TransferAdminPending(newAdmin); 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); 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); 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; OperatorAdded(operator, false); break; } } } } // File: contracts/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)); TokenWithdraw(token, amount, sendTo); } event EtherWithdraw(uint amount, address sendTo); /** * @dev Withdraw Ethers */ function withdrawEther(uint amount, address sendTo) external onlyAdmin { sendTo.transfer(amount); EtherWithdraw(amount, sendTo); } } // File: contracts/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 2 of 9: KyberNetwork
{"ERC20Interface.sol":{"content":"pragma solidity 0.4.18;\n\n\n// https://github.com/ethereum/EIPs/issues/20\ninterface ERC20 {\n function totalSupply() public view returns (uint supply);\n function balanceOf(address _owner) public view returns (uint balance);\n function transfer(address _to, uint _value) public returns (bool success);\n function transferFrom(address _from, address _to, uint _value) public returns (bool success);\n function approve(address _spender, uint _value) public returns (bool success);\n function allowance(address _owner, address _spender) public view returns (uint remaining);\n function decimals() public view returns(uint digits);\n event Approval(address indexed _owner, address indexed _spender, uint _value);\n}\n"},"ExpectedRateInterface.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./ERC20Interface.sol\";\n\n\ninterface ExpectedRateInterface {\n function getExpectedRate(ERC20 src, ERC20 dest, uint srcQty, bool usePermissionless) public view\n returns (uint expectedRate, uint slippageRate);\n}\n"},"FeeBurnerInterface.sol":{"content":"pragma solidity 0.4.18;\n\n\ninterface FeeBurnerInterface {\n function handleFees (uint tradeWeiAmount, address reserve, address wallet) public returns(bool);\n function setReserveData(address reserve, uint feesInBps, address kncWallet) public;\n}\n"},"KyberNetwork.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./ERC20Interface.sol\";\nimport \"./KyberReserveInterface.sol\";\nimport \"./KyberNetworkInterface.sol\";\nimport \"./Withdrawable.sol\";\nimport \"./Utils3.sol\";\nimport \"./WhiteListInterface.sol\";\nimport \"./ExpectedRateInterface.sol\";\nimport \"./FeeBurnerInterface.sol\";\n\n\n/**\n * @title Helps contracts guard against reentrancy attacks.\n */\ncontract ReentrancyGuard {\n\n /// @dev counter to allow mutex lock with only one SSTORE operation\n uint256 private guardCounter = 1;\n\n /**\n * @dev Prevents a function from calling itself, directly or indirectly.\n * Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n guardCounter += 1;\n uint256 localCounter = guardCounter;\n _;\n require(localCounter == guardCounter);\n }\n}\n\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// @title Kyber Network main contract\ncontract KyberNetwork is Withdrawable, Utils3, KyberNetworkInterface, ReentrancyGuard {\n\n bytes public constant PERM_HINT = \"PERM\";\n uint public constant PERM_HINT_GET_RATE = 1 \u003c\u003c 255; // for get rate. bit mask hint.\n\n uint public negligibleRateDiff = 10; // basic rate steps will be in 0.01%\n KyberReserveInterface[] public reserves;\n mapping(address=\u003eReserveType) public reserveType;\n WhiteListInterface public whiteListContract;\n ExpectedRateInterface public expectedRateContract;\n FeeBurnerInterface public feeBurnerContract;\n address public kyberNetworkProxyContract;\n uint public maxGasPriceValue = 50 * 1000 * 1000 * 1000; // 50 gwei\n bool public isEnabled = false; // network is enabled\n mapping(bytes32=\u003euint) public infoFields; // this is only a UI field for external app.\n\n mapping(address=\u003eaddress[]) public reservesPerTokenSrc; //reserves supporting token to eth\n mapping(address=\u003eaddress[]) public reservesPerTokenDest;//reserves support eth to token\n\n enum ReserveType {NONE, PERMISSIONED, PERMISSIONLESS}\n bytes internal constant EMPTY_HINT = \"\";\n\n function KyberNetwork(address _admin) public {\n require(_admin != address(0));\n admin = _admin;\n }\n\n event EtherReceival(address indexed sender, uint amount);\n\n /* solhint-disable no-complex-fallback */\n function() public payable {\n EtherReceival(msg.sender, msg.value);\n }\n /* solhint-enable no-complex-fallback */\n\n struct TradeInput {\n address trader;\n ERC20 src;\n uint srcAmount;\n ERC20 dest;\n address destAddress;\n uint maxDestAmount;\n uint minConversionRate;\n address walletId;\n bytes hint;\n }\n\n function tradeWithHint(\n address trader,\n ERC20 src,\n uint srcAmount,\n ERC20 dest,\n address destAddress,\n uint maxDestAmount,\n uint minConversionRate,\n address walletId,\n bytes hint\n )\n public\n nonReentrant\n payable\n returns(uint)\n {\n require(msg.sender == kyberNetworkProxyContract);\n require((hint.length == 0) || (hint.length == 4));\n\n TradeInput memory tradeInput;\n\n tradeInput.trader = trader;\n tradeInput.src = src;\n tradeInput.srcAmount = srcAmount;\n tradeInput.dest = dest;\n tradeInput.destAddress = destAddress;\n tradeInput.maxDestAmount = maxDestAmount;\n tradeInput.minConversionRate = minConversionRate;\n tradeInput.walletId = walletId;\n tradeInput.hint = hint;\n\n return trade(tradeInput);\n }\n\n event AddReserveToNetwork(KyberReserveInterface indexed reserve, bool add, bool isPermissionless);\n\n /// @notice can be called only by operator\n /// @dev add or deletes a reserve to/from the network.\n /// @param reserve The reserve address.\n /// @param isPermissionless is the new reserve from permissionless type.\n function addReserve(KyberReserveInterface reserve, bool isPermissionless) public onlyOperator\n returns(bool)\n {\n require(reserveType[reserve] == ReserveType.NONE);\n reserves.push(reserve);\n\n reserveType[reserve] = isPermissionless ? ReserveType.PERMISSIONLESS : ReserveType.PERMISSIONED;\n\n AddReserveToNetwork(reserve, true, isPermissionless);\n\n return true;\n }\n\n event RemoveReserveFromNetwork(KyberReserveInterface reserve);\n\n /// @notice can be called only by operator\n /// @dev removes a reserve from Kyber network.\n /// @param reserve The reserve address.\n /// @param index in reserve array.\n function removeReserve(KyberReserveInterface reserve, uint index) public onlyOperator\n returns(bool)\n {\n\n require(reserveType[reserve] != ReserveType.NONE);\n require(reserves[index] == reserve);\n\n reserveType[reserve] = ReserveType.NONE;\n reserves[index] = reserves[reserves.length - 1];\n reserves.length--;\n\n RemoveReserveFromNetwork(reserve);\n\n return true;\n }\n\n event ListReservePairs(address indexed reserve, ERC20 src, ERC20 dest, bool add);\n\n /// @notice can be called only by operator\n /// @dev allow or prevent a specific reserve to trade a pair of tokens\n /// @param reserve The reserve address.\n /// @param token token address\n /// @param ethToToken will it support ether to token trade\n /// @param tokenToEth will it support token to ether trade\n /// @param add If true then list this pair, otherwise unlist it.\n function listPairForReserve(address reserve, ERC20 token, bool ethToToken, bool tokenToEth, bool add)\n public\n onlyOperator\n returns(bool)\n {\n require(reserveType[reserve] != ReserveType.NONE);\n\n if (ethToToken) {\n listPairs(reserve, token, false, add);\n\n ListReservePairs(reserve, ETH_TOKEN_ADDRESS, token, add);\n }\n\n if (tokenToEth) {\n listPairs(reserve, token, true, add);\n\n if (add) {\n require(token.approve(reserve, 2**255)); // approve infinity\n } else {\n require(token.approve(reserve, 0));\n }\n\n ListReservePairs(reserve, token, ETH_TOKEN_ADDRESS, add);\n }\n\n setDecimals(token);\n\n return true;\n }\n\n event WhiteListContractSet(WhiteListInterface newContract, WhiteListInterface currentContract);\n\n ///@param whiteList can be empty\n function setWhiteList(WhiteListInterface whiteList) public onlyAdmin {\n WhiteListContractSet(whiteList, whiteListContract);\n whiteListContract = whiteList;\n }\n\n event ExpectedRateContractSet(ExpectedRateInterface newContract, ExpectedRateInterface currentContract);\n\n function setExpectedRate(ExpectedRateInterface expectedRate) public onlyAdmin {\n require(expectedRate != address(0));\n\n ExpectedRateContractSet(expectedRate, expectedRateContract);\n expectedRateContract = expectedRate;\n }\n\n event FeeBurnerContractSet(FeeBurnerInterface newContract, FeeBurnerInterface currentContract);\n\n function setFeeBurner(FeeBurnerInterface feeBurner) public onlyAdmin {\n require(feeBurner != address(0));\n\n FeeBurnerContractSet(feeBurner, feeBurnerContract);\n feeBurnerContract = feeBurner;\n }\n\n event KyberNetwrokParamsSet(uint maxGasPrice, uint negligibleRateDiff);\n\n function setParams(\n uint _maxGasPrice,\n uint _negligibleRateDiff\n )\n public\n onlyAdmin\n {\n require(_negligibleRateDiff \u003c= 100 * 100); // at most 100%\n\n maxGasPriceValue = _maxGasPrice;\n negligibleRateDiff = _negligibleRateDiff;\n KyberNetwrokParamsSet(maxGasPriceValue, negligibleRateDiff);\n }\n\n event KyberNetworkSetEnable(bool isEnabled);\n\n function setEnable(bool _enable) public onlyAdmin {\n if (_enable) {\n require(feeBurnerContract != address(0));\n require(expectedRateContract != address(0));\n require(kyberNetworkProxyContract != address(0));\n }\n isEnabled = _enable;\n\n KyberNetworkSetEnable(isEnabled);\n }\n\n function setInfo(bytes32 field, uint value) public onlyOperator {\n infoFields[field] = value;\n }\n\n event KyberProxySet(address proxy, address sender);\n\n function setKyberProxy(address networkProxy) public onlyAdmin {\n require(networkProxy != address(0));\n kyberNetworkProxyContract = networkProxy;\n KyberProxySet(kyberNetworkProxyContract, msg.sender);\n }\n\n /// @dev returns number of reserves\n /// @return number of reserves\n function getNumReserves() public view returns(uint) {\n return reserves.length;\n }\n\n /// @notice should be called off chain\n /// @dev get an array of all reserves\n /// @return An array of all reserves\n function getReserves() public view returns(KyberReserveInterface[]) {\n return reserves;\n }\n\n function maxGasPrice() public view returns(uint) {\n return maxGasPriceValue;\n }\n\n function getExpectedRate(ERC20 src, ERC20 dest, uint srcQty)\n public view\n returns(uint expectedRate, uint slippageRate)\n {\n require(expectedRateContract != address(0));\n if (src == dest) return (0,0);\n bool includePermissionless = true;\n\n if (srcQty \u0026 PERM_HINT_GET_RATE \u003e 0) {\n includePermissionless = false;\n srcQty = srcQty \u0026 ~PERM_HINT_GET_RATE;\n }\n\n return expectedRateContract.getExpectedRate(src, dest, srcQty, includePermissionless);\n }\n\n function getExpectedRateOnlyPermission(ERC20 src, ERC20 dest, uint srcQty)\n public view\n returns(uint expectedRate, uint slippageRate)\n {\n require(expectedRateContract != address(0));\n if (src == dest) return (0,0);\n return expectedRateContract.getExpectedRate(src, dest, srcQty, false);\n }\n\n function getUserCapInWei(address user) public view returns(uint) {\n if (whiteListContract == address(0)) return (2 ** 255);\n return whiteListContract.getUserCapInWei(user);\n }\n\n function getUserCapInTokenWei(address user, ERC20 token) public view returns(uint) {\n //future feature\n user;\n token;\n require(false);\n }\n\n struct BestRateResult {\n uint rate;\n address reserve1;\n address reserve2;\n uint weiAmount;\n uint rateSrcToEth;\n uint rateEthToDest;\n uint destAmount;\n }\n\n /// @notice use token address ETH_TOKEN_ADDRESS for ether\n /// @dev best conversion rate for a pair of tokens, if number of reserves have small differences. randomize\n /// @param src Src token\n /// @param dest Destination token\n /// @return obsolete - used to return best reserve index. not relevant anymore for this API.\n function findBestRate(ERC20 src, ERC20 dest, uint srcAmount) public view returns(uint obsolete, uint rate) {\n BestRateResult memory result = findBestRateTokenToToken(src, dest, srcAmount, EMPTY_HINT);\n return(0, result.rate);\n }\n\n function findBestRateOnlyPermission(ERC20 src, ERC20 dest, uint srcAmount)\n public\n view\n returns(uint obsolete, uint rate)\n {\n BestRateResult memory result = findBestRateTokenToToken(src, dest, srcAmount, PERM_HINT);\n return(0, result.rate);\n }\n\n function enabled() public view returns(bool) {\n return isEnabled;\n }\n\n function info(bytes32 field) public view returns(uint) {\n return infoFields[field];\n }\n\n /* solhint-disable code-complexity */\n // Regarding complexity. Below code follows the required algorithm for choosing a reserve.\n // It has been tested, reviewed and found to be clear enough.\n //@dev this function always src or dest are ether. can\u0027t do token to token\n function searchBestRate(ERC20 src, ERC20 dest, uint srcAmount, bool usePermissionless)\n public\n view\n returns(address, uint)\n {\n uint bestRate = 0;\n uint bestReserve = 0;\n uint numRelevantReserves = 0;\n\n //return 1 for ether to ether\n if (src == dest) return (reserves[bestReserve], PRECISION);\n\n address[] memory reserveArr;\n\n reserveArr = src == ETH_TOKEN_ADDRESS ? reservesPerTokenDest[dest] : reservesPerTokenSrc[src];\n\n if (reserveArr.length == 0) return (reserves[bestReserve], bestRate);\n\n uint[] memory rates = new uint[](reserveArr.length);\n uint[] memory reserveCandidates = new uint[](reserveArr.length);\n\n for (uint i = 0; i \u003c reserveArr.length; i++) {\n //list all reserves that have this token.\n if (!usePermissionless \u0026\u0026 reserveType[reserveArr[i]] == ReserveType.PERMISSIONLESS) {\n continue;\n }\n\n rates[i] = (KyberReserveInterface(reserveArr[i])).getConversionRate(src, dest, srcAmount, block.number);\n\n if (rates[i] \u003e bestRate) {\n //best rate is highest rate\n bestRate = rates[i];\n }\n }\n\n if (bestRate \u003e 0) {\n uint smallestRelevantRate = (bestRate * 10000) / (10000 + negligibleRateDiff);\n\n for (i = 0; i \u003c reserveArr.length; i++) {\n if (rates[i] \u003e= smallestRelevantRate) {\n reserveCandidates[numRelevantReserves++] = i;\n }\n }\n\n if (numRelevantReserves \u003e 1) {\n //when encountering small rate diff from bestRate. draw from relevant reserves\n bestReserve = reserveCandidates[uint(block.blockhash(block.number-1)) % numRelevantReserves];\n } else {\n bestReserve = reserveCandidates[0];\n }\n\n bestRate = rates[bestReserve];\n }\n\n return (reserveArr[bestReserve], bestRate);\n }\n /* solhint-enable code-complexity */\n\n function getReservesRates(ERC20 token, uint optionalAmount) public view\n returns(address[] buyReserves, uint[] buyRates, address[] sellReserves, uint[] sellRates)\n {\n uint amount = optionalAmount \u003e 0 ? optionalAmount : 1000;\n ERC20 ETH = ETH_TOKEN_ADDRESS;\n\n buyReserves = reservesPerTokenDest[token];\n buyRates = new uint[](buyReserves.length);\n\n for (uint i = 0; i \u003c buyReserves.length; i++) {\n buyRates[i] = (KyberReserveInterface(buyReserves[i])).getConversionRate(ETH, token, amount, block.number);\n }\n\n sellReserves = reservesPerTokenSrc[token];\n sellRates = new uint[](sellReserves.length);\n\n for (i = 0; i \u003c sellReserves.length; i++) {\n sellRates[i] = (KyberReserveInterface(sellReserves[i])).getConversionRate(token, ETH, amount, block.number);\n }\n }\n\n function findBestRateTokenToToken(ERC20 src, ERC20 dest, uint srcAmount, bytes hint) internal view\n returns(BestRateResult result)\n {\n //by default we use permission less reserves\n bool usePermissionless = true;\n\n // if hint in first 4 bytes == \u0027PERM\u0027 only permissioned reserves will be used.\n if ((hint.length \u003e= 4) \u0026\u0026 (keccak256(hint[0], hint[1], hint[2], hint[3]) == keccak256(PERM_HINT))) {\n usePermissionless = false;\n }\n\n uint srcDecimals = getDecimals(src);\n uint destDecimals = getDecimals(dest);\n\n (result.reserve1, result.rateSrcToEth) =\n searchBestRate(src, ETH_TOKEN_ADDRESS, srcAmount, usePermissionless);\n\n result.weiAmount = calcDestAmountWithDecimals(srcDecimals, ETH_DECIMALS, srcAmount, result.rateSrcToEth);\n //if weiAmount is zero, return zero rate to avoid revert in ETH -\u003e token call\n if (result.weiAmount == 0) {\n result.rate = 0;\n return;\n }\n \n (result.reserve2, result.rateEthToDest) =\n searchBestRate(ETH_TOKEN_ADDRESS, dest, result.weiAmount, usePermissionless);\n\n result.destAmount = calcDestAmountWithDecimals(ETH_DECIMALS, destDecimals, result.weiAmount, result.rateEthToDest);\n\n result.rate = calcRateFromQty(srcAmount, result.destAmount, srcDecimals, destDecimals);\n }\n\n function listPairs(address reserve, ERC20 token, bool isTokenToEth, bool add) internal {\n uint i;\n address[] storage reserveArr = reservesPerTokenDest[token];\n\n if (isTokenToEth) {\n reserveArr = reservesPerTokenSrc[token];\n }\n\n for (i = 0; i \u003c reserveArr.length; i++) {\n if (reserve == reserveArr[i]) {\n if (add) {\n break; //already added\n } else {\n //remove\n reserveArr[i] = reserveArr[reserveArr.length - 1];\n reserveArr.length--;\n break;\n }\n }\n }\n\n if (add \u0026\u0026 i == reserveArr.length) {\n //if reserve wasn\u0027t found add it\n reserveArr.push(reserve);\n }\n }\n\n event KyberTrade(address indexed trader, ERC20 src, ERC20 dest, uint srcAmount, uint dstAmount,\n address destAddress, uint ethWeiValue, address reserve1, address reserve2, bytes hint);\n\n /* solhint-disable function-max-lines */\n // Most of the lines here are functions calls spread over multiple lines. We find this function readable enough\n /// @notice use token address ETH_TOKEN_ADDRESS for ether\n /// @dev trade api for kyber network.\n /// @param tradeInput structure of trade inputs\n function trade(TradeInput tradeInput) internal returns(uint) {\n require(isEnabled);\n require(tx.gasprice \u003c= maxGasPriceValue);\n require(validateTradeInput(tradeInput.src, tradeInput.srcAmount, tradeInput.dest, tradeInput.destAddress));\n\n BestRateResult memory rateResult =\n findBestRateTokenToToken(tradeInput.src, tradeInput.dest, tradeInput.srcAmount, tradeInput.hint);\n\n require(rateResult.rate \u003e 0);\n require(rateResult.rate \u003c MAX_RATE);\n require(rateResult.rate \u003e= tradeInput.minConversionRate);\n\n uint actualDestAmount;\n uint weiAmount;\n uint actualSrcAmount;\n\n (actualSrcAmount, weiAmount, actualDestAmount) = calcActualAmounts(tradeInput.src,\n tradeInput.dest,\n tradeInput.srcAmount,\n tradeInput.maxDestAmount,\n rateResult);\n\n require(getUserCapInWei(tradeInput.trader) \u003e= weiAmount);\n require(handleChange(tradeInput.src, tradeInput.srcAmount, actualSrcAmount, tradeInput.trader));\n\n require(doReserveTrade( //src to ETH\n tradeInput.src,\n actualSrcAmount,\n ETH_TOKEN_ADDRESS,\n this,\n weiAmount,\n KyberReserveInterface(rateResult.reserve1),\n rateResult.rateSrcToEth,\n true));\n\n require(doReserveTrade( //Eth to dest\n ETH_TOKEN_ADDRESS,\n weiAmount,\n tradeInput.dest,\n tradeInput.destAddress,\n actualDestAmount,\n KyberReserveInterface(rateResult.reserve2),\n rateResult.rateEthToDest,\n true));\n\n if (tradeInput.src != ETH_TOKEN_ADDRESS) //\"fake\" trade. (ether to ether) - don\u0027t burn.\n require(feeBurnerContract.handleFees(weiAmount, rateResult.reserve1, tradeInput.walletId));\n if (tradeInput.dest != ETH_TOKEN_ADDRESS) //\"fake\" trade. (ether to ether) - don\u0027t burn.\n require(feeBurnerContract.handleFees(weiAmount, rateResult.reserve2, tradeInput.walletId));\n\n KyberTrade({\n trader: tradeInput.trader,\n src: tradeInput.src,\n dest: tradeInput.dest,\n srcAmount: actualSrcAmount,\n dstAmount: actualDestAmount,\n destAddress: tradeInput.destAddress,\n ethWeiValue: weiAmount,\n reserve1: (tradeInput.src == ETH_TOKEN_ADDRESS) ? address(0) : rateResult.reserve1,\n reserve2: (tradeInput.dest == ETH_TOKEN_ADDRESS) ? address(0) : rateResult.reserve2,\n hint: tradeInput.hint\n });\n\n return actualDestAmount;\n }\n /* solhint-enable function-max-lines */\n\n function calcActualAmounts (ERC20 src, ERC20 dest, uint srcAmount, uint maxDestAmount, BestRateResult rateResult)\n internal view returns(uint actualSrcAmount, uint weiAmount, uint actualDestAmount)\n {\n if (rateResult.destAmount \u003e maxDestAmount) {\n actualDestAmount = maxDestAmount;\n weiAmount = calcSrcAmount(ETH_TOKEN_ADDRESS, dest, actualDestAmount, rateResult.rateEthToDest);\n actualSrcAmount = calcSrcAmount(src, ETH_TOKEN_ADDRESS, weiAmount, rateResult.rateSrcToEth);\n require(actualSrcAmount \u003c= srcAmount);\n } else {\n actualDestAmount = rateResult.destAmount;\n actualSrcAmount = srcAmount;\n weiAmount = rateResult.weiAmount;\n }\n }\n\n /// @notice use token address ETH_TOKEN_ADDRESS for ether\n /// @dev do one trade with a reserve\n /// @param src Src token\n /// @param amount amount of src tokens\n /// @param dest Destination token\n /// @param destAddress Address to send tokens to\n /// @param reserve Reserve to use\n /// @param validate If true, additional validations are applicable\n /// @return true if trade is successful\n function doReserveTrade(\n ERC20 src,\n uint amount,\n ERC20 dest,\n address destAddress,\n uint expectedDestAmount,\n KyberReserveInterface reserve,\n uint conversionRate,\n bool validate\n )\n internal\n returns(bool)\n {\n uint callValue = 0;\n\n if (src == dest) {\n //this is for a \"fake\" trade when both src and dest are ethers.\n if (destAddress != (address(this)))\n destAddress.transfer(amount);\n return true;\n }\n\n if (src == ETH_TOKEN_ADDRESS) {\n callValue = amount;\n }\n\n // reserve sends tokens/eth to network. network sends it to destination\n require(reserve.trade.value(callValue)(src, amount, dest, this, conversionRate, validate));\n\n if (destAddress != address(this)) {\n //for token to token dest address is network. and Ether / token already here...\n if (dest == ETH_TOKEN_ADDRESS) {\n destAddress.transfer(expectedDestAmount);\n } else {\n require(dest.transfer(destAddress, expectedDestAmount));\n }\n }\n\n return true;\n }\n\n /// when user sets max dest amount we could have too many source tokens == change. so we send it back to user.\n function handleChange (ERC20 src, uint srcAmount, uint requiredSrcAmount, address trader) internal returns (bool) {\n\n if (requiredSrcAmount \u003c srcAmount) {\n //if there is \"change\" send back to trader\n if (src == ETH_TOKEN_ADDRESS) {\n trader.transfer(srcAmount - requiredSrcAmount);\n } else {\n require(src.transfer(trader, (srcAmount - requiredSrcAmount)));\n }\n }\n\n return true;\n }\n\n /// @notice use token address ETH_TOKEN_ADDRESS for ether\n /// @dev checks that user sent ether/tokens to contract before trade\n /// @param src Src token\n /// @param srcAmount amount of src tokens\n /// @return true if tradeInput is valid\n function validateTradeInput(ERC20 src, uint srcAmount, ERC20 dest, address destAddress)\n internal\n view\n returns(bool)\n {\n require(srcAmount \u003c= MAX_QTY);\n require(srcAmount != 0);\n require(destAddress != address(0));\n require(src != dest);\n\n if (src == ETH_TOKEN_ADDRESS) {\n require(msg.value == srcAmount);\n } else {\n require(msg.value == 0);\n //funds should have been moved to this contract already.\n require(src.balanceOf(this) \u003e= srcAmount);\n }\n\n return true;\n }\n}\n"},"KyberNetworkInterface.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./ERC20Interface.sol\";\n\n\n/// @title Kyber Network interface\ninterface KyberNetworkInterface {\n function maxGasPrice() public view returns(uint);\n function getUserCapInWei(address user) public view returns(uint);\n function getUserCapInTokenWei(address user, ERC20 token) public view returns(uint);\n function enabled() public view returns(bool);\n function info(bytes32 id) public view returns(uint);\n\n function getExpectedRate(ERC20 src, ERC20 dest, uint srcQty) public view\n returns (uint expectedRate, uint slippageRate);\n\n function tradeWithHint(address trader, ERC20 src, uint srcAmount, ERC20 dest, address destAddress,\n uint maxDestAmount, uint minConversionRate, address walletId, bytes hint) public payable returns(uint);\n}\n"},"KyberReserveInterface.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./ERC20Interface.sol\";\n\n/// @title Kyber Reserve contract\ninterface KyberReserveInterface {\n\n function trade(\n ERC20 srcToken,\n uint srcAmount,\n ERC20 destToken,\n address destAddress,\n uint conversionRate,\n bool validate\n )\n public\n payable\n returns(bool);\n\n function getConversionRate(ERC20 src, ERC20 dest, uint srcQty, uint blockNumber) public view returns(uint);\n}\n"},"PermissionGroups.sol":{"content":"pragma solidity 0.4.18;\n\n\ncontract PermissionGroups {\n\n address public admin;\n address public pendingAdmin;\n mapping(address=\u003ebool) internal operators;\n mapping(address=\u003ebool) internal alerters;\n address[] internal operatorsGroup;\n address[] internal alertersGroup;\n uint constant internal MAX_GROUP_SIZE = 50;\n\n function PermissionGroups() public {\n admin = msg.sender;\n }\n\n modifier onlyAdmin() {\n require(msg.sender == admin);\n _;\n }\n\n modifier onlyOperator() {\n require(operators[msg.sender]);\n _;\n }\n\n modifier onlyAlerter() {\n require(alerters[msg.sender]);\n _;\n }\n\n function getOperators () external view returns(address[]) {\n return operatorsGroup;\n }\n\n function getAlerters () external view returns(address[]) {\n return alertersGroup;\n }\n\n event TransferAdminPending(address pendingAdmin);\n\n /**\n * @dev Allows the current admin to set the pendingAdmin address.\n * @param newAdmin The address to transfer ownership to.\n */\n function transferAdmin(address newAdmin) public onlyAdmin {\n require(newAdmin != address(0));\n TransferAdminPending(pendingAdmin);\n pendingAdmin = newAdmin;\n }\n\n /**\n * @dev Allows the current admin to set the admin in one tx. Useful initial deployment.\n * @param newAdmin The address to transfer ownership to.\n */\n function transferAdminQuickly(address newAdmin) public onlyAdmin {\n require(newAdmin != address(0));\n TransferAdminPending(newAdmin);\n AdminClaimed(newAdmin, admin);\n admin = newAdmin;\n }\n\n event AdminClaimed( address newAdmin, address previousAdmin);\n\n /**\n * @dev Allows the pendingAdmin address to finalize the change admin process.\n */\n function claimAdmin() public {\n require(pendingAdmin == msg.sender);\n AdminClaimed(pendingAdmin, admin);\n admin = pendingAdmin;\n pendingAdmin = address(0);\n }\n\n event AlerterAdded (address newAlerter, bool isAdd);\n\n function addAlerter(address newAlerter) public onlyAdmin {\n require(!alerters[newAlerter]); // prevent duplicates.\n require(alertersGroup.length \u003c MAX_GROUP_SIZE);\n\n AlerterAdded(newAlerter, true);\n alerters[newAlerter] = true;\n alertersGroup.push(newAlerter);\n }\n\n function removeAlerter (address alerter) public onlyAdmin {\n require(alerters[alerter]);\n alerters[alerter] = false;\n\n for (uint i = 0; i \u003c alertersGroup.length; ++i) {\n if (alertersGroup[i] == alerter) {\n alertersGroup[i] = alertersGroup[alertersGroup.length - 1];\n alertersGroup.length--;\n AlerterAdded(alerter, false);\n break;\n }\n }\n }\n\n event OperatorAdded(address newOperator, bool isAdd);\n\n function addOperator(address newOperator) public onlyAdmin {\n require(!operators[newOperator]); // prevent duplicates.\n require(operatorsGroup.length \u003c MAX_GROUP_SIZE);\n\n OperatorAdded(newOperator, true);\n operators[newOperator] = true;\n operatorsGroup.push(newOperator);\n }\n\n function removeOperator (address operator) public onlyAdmin {\n require(operators[operator]);\n operators[operator] = false;\n\n for (uint i = 0; i \u003c operatorsGroup.length; ++i) {\n if (operatorsGroup[i] == operator) {\n operatorsGroup[i] = operatorsGroup[operatorsGroup.length - 1];\n operatorsGroup.length -= 1;\n OperatorAdded(operator, false);\n break;\n }\n }\n }\n}\n"},"Utils.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./ERC20Interface.sol\";\n\n\n/// @title Kyber constants contract\ncontract Utils {\n\n ERC20 constant internal ETH_TOKEN_ADDRESS = ERC20(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee);\n uint constant internal PRECISION = (10**18);\n uint constant internal MAX_QTY = (10**28); // 10B tokens\n uint constant internal MAX_RATE = (PRECISION * 10**6); // up to 1M tokens per ETH\n uint constant internal MAX_DECIMALS = 18;\n uint constant internal ETH_DECIMALS = 18;\n mapping(address=\u003euint) internal decimals;\n\n function setDecimals(ERC20 token) internal {\n if (token == ETH_TOKEN_ADDRESS) decimals[token] = ETH_DECIMALS;\n else decimals[token] = token.decimals();\n }\n\n function getDecimals(ERC20 token) internal view returns(uint) {\n if (token == ETH_TOKEN_ADDRESS) return ETH_DECIMALS; // save storage access\n uint tokenDecimals = decimals[token];\n // technically, there might be token with decimals 0\n // moreover, very possible that old tokens have decimals 0\n // these tokens will just have higher gas fees.\n if(tokenDecimals == 0) return token.decimals();\n\n return tokenDecimals;\n }\n\n function calcDstQty(uint srcQty, uint srcDecimals, uint dstDecimals, uint rate) internal pure returns(uint) {\n require(srcQty \u003c= MAX_QTY);\n require(rate \u003c= MAX_RATE);\n\n if (dstDecimals \u003e= srcDecimals) {\n require((dstDecimals - srcDecimals) \u003c= MAX_DECIMALS);\n return (srcQty * rate * (10**(dstDecimals - srcDecimals))) / PRECISION;\n } else {\n require((srcDecimals - dstDecimals) \u003c= MAX_DECIMALS);\n return (srcQty * rate) / (PRECISION * (10**(srcDecimals - dstDecimals)));\n }\n }\n\n function calcSrcQty(uint dstQty, uint srcDecimals, uint dstDecimals, uint rate) internal pure returns(uint) {\n require(dstQty \u003c= MAX_QTY);\n require(rate \u003c= MAX_RATE);\n \n //source quantity is rounded up. to avoid dest quantity being too low.\n uint numerator;\n uint denominator;\n if (srcDecimals \u003e= dstDecimals) {\n require((srcDecimals - dstDecimals) \u003c= MAX_DECIMALS);\n numerator = (PRECISION * dstQty * (10**(srcDecimals - dstDecimals)));\n denominator = rate;\n } else {\n require((dstDecimals - srcDecimals) \u003c= MAX_DECIMALS);\n numerator = (PRECISION * dstQty);\n denominator = (rate * (10**(dstDecimals - srcDecimals)));\n }\n return (numerator + denominator - 1) / denominator; //avoid rounding down errors\n }\n}\n"},"Utils2.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./Utils.sol\";\n\n\ncontract Utils2 is Utils {\n\n /// @dev get the balance of a user.\n /// @param token The token type\n /// @return The balance\n function getBalance(ERC20 token, address user) public view returns(uint) {\n if (token == ETH_TOKEN_ADDRESS)\n return user.balance;\n else\n return token.balanceOf(user);\n }\n\n function getDecimalsSafe(ERC20 token) internal returns(uint) {\n\n if (decimals[token] == 0) {\n setDecimals(token);\n }\n\n return decimals[token];\n }\n\n function calcDestAmount(ERC20 src, ERC20 dest, uint srcAmount, uint rate) internal view returns(uint) {\n return calcDstQty(srcAmount, getDecimals(src), getDecimals(dest), rate);\n }\n\n function calcSrcAmount(ERC20 src, ERC20 dest, uint destAmount, uint rate) internal view returns(uint) {\n return calcSrcQty(destAmount, getDecimals(src), getDecimals(dest), rate);\n }\n\n function calcRateFromQty(uint srcAmount, uint destAmount, uint srcDecimals, uint dstDecimals)\n internal pure returns(uint)\n {\n require(srcAmount \u003c= MAX_QTY);\n require(destAmount \u003c= MAX_QTY);\n\n if (dstDecimals \u003e= srcDecimals) {\n require((dstDecimals - srcDecimals) \u003c= MAX_DECIMALS);\n return (destAmount * PRECISION / ((10 ** (dstDecimals - srcDecimals)) * srcAmount));\n } else {\n require((srcDecimals - dstDecimals) \u003c= MAX_DECIMALS);\n return (destAmount * PRECISION * (10 ** (srcDecimals - dstDecimals)) / srcAmount);\n }\n }\n}\n"},"Utils3.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./Utils2.sol\";\n\n\ncontract Utils3 is Utils2 {\n\n function calcDestAmountWithDecimals(uint srcDecimals, uint destDecimals, uint srcAmount, uint rate) internal pure returns(uint) {\n return calcDstQty(srcAmount, srcDecimals, destDecimals, rate);\n }\n\n}\n"},"WhiteListInterface.sol":{"content":"pragma solidity 0.4.18;\n\n\ncontract WhiteListInterface {\n function getUserCapInWei(address user) external view returns (uint userCapWei);\n}\n"},"Withdrawable.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./ERC20Interface.sol\";\nimport \"./PermissionGroups.sol\";\n\n\n/**\n * @title Contracts that should be able to recover tokens or ethers\n * @author Ilan Doron\n * @dev This allows to recover any tokens or Ethers received in a contract.\n * This will prevent any accidental loss of tokens.\n */\ncontract Withdrawable is PermissionGroups {\n\n event TokenWithdraw(ERC20 token, uint amount, address sendTo);\n\n /**\n * @dev Withdraw all ERC20 compatible tokens\n * @param token ERC20 The address of the token contract\n */\n function withdrawToken(ERC20 token, uint amount, address sendTo) external onlyAdmin {\n require(token.transfer(sendTo, amount));\n TokenWithdraw(token, amount, sendTo);\n }\n\n event EtherWithdraw(uint amount, address sendTo);\n\n /**\n * @dev Withdraw Ethers\n */\n function withdrawEther(uint amount, address sendTo) external onlyAdmin {\n sendTo.transfer(amount);\n EtherWithdraw(amount, sendTo);\n }\n}\n"}}
File 3 of 9: BandToken
// File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.0; /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/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); } // File: openzeppelin-solidity/contracts/math/SafeMath.sol pragma solidity ^0.5.0; /** * @title SafeMath * @dev Unsigned math operations with safety checks that revert on error */ library SafeMath { /** * @dev Multiplies two unsigned integers, reverts on overflow. */ 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-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b); return c; } /** * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a); uint256 c = a - b; return c; } /** * @dev Adds two unsigned integers, reverts on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a); return c; } /** * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0); return a % b; } } // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol pragma solidity ^0.5.0; /** * @title Standard ERC20 token * * @dev Implementation of the basic standard token. * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md * Originally based on code by FirstBlood: * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol * * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for * all accounts just by listening to said events. Note that this isn't required by the specification, and other * compliant implementations may not do it. */ contract ERC20 is IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowed; uint256 private _totalSupply; /** * @dev Total number of tokens in existence */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev Gets the balance of the specified address. * @param owner The address to query the balance of. * @return An uint256 representing the amount owned by the passed address. */ function balanceOf(address owner) public view returns (uint256) { return _balances[owner]; } /** * @dev Function to check the amount of tokens that an owner allowed to a spender. * @param owner address The address which owns the funds. * @param spender address The address which will spend the funds. * @return A uint256 specifying the amount of tokens still available for the spender. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowed[owner][spender]; } /** * @dev Transfer token for a specified address * @param to The address to transfer to. * @param value The amount to be transferred. */ function transfer(address to, uint256 value) public returns (bool) { _transfer(msg.sender, to, value); return true; } /** * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. * Beware that changing an allowance with this method brings the risk that someone may use both the old * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. */ function approve(address spender, uint256 value) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = value; emit Approval(msg.sender, spender, value); return true; } /** * @dev Transfer tokens from one address to another. * Note that while this function emits an Approval event, this is not required as per the specification, * and other compliant implementations may not emit the event. * @param from address The address which you want to send tokens from * @param to address The address which you want to transfer to * @param value uint256 the amount of tokens to be transferred */ function transferFrom(address from, address to, uint256 value) public returns (bool) { _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value); _transfer(from, to, value); emit Approval(from, msg.sender, _allowed[from][msg.sender]); return true; } /** * @dev Increase the amount of tokens that an owner allowed to a spender. * approve should be called when allowed_[_spender] == 0. To increment * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * Emits an Approval event. * @param spender The address which will spend the funds. * @param addedValue The amount of tokens to increase the allowance by. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = _allowed[msg.sender][spender].add(addedValue); emit Approval(msg.sender, spender, _allowed[msg.sender][spender]); return true; } /** * @dev Decrease the amount of tokens that an owner allowed to a spender. * approve should be called when allowed_[_spender] == 0. To decrement * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * Emits an Approval event. * @param spender The address which will spend the funds. * @param subtractedValue The amount of tokens to decrease the allowance by. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = _allowed[msg.sender][spender].sub(subtractedValue); emit Approval(msg.sender, spender, _allowed[msg.sender][spender]); return true; } /** * @dev Transfer token for a specified addresses * @param from The address to transfer from. * @param to The address to transfer to. * @param value The amount to be transferred. */ function _transfer(address from, address to, uint256 value) internal { require(to != address(0)); _balances[from] = _balances[from].sub(value); _balances[to] = _balances[to].add(value); emit Transfer(from, to, value); } /** * @dev Internal function that mints an amount of the token and assigns it to * an account. This encapsulates the modification of balances such that the * proper events are emitted. * @param account The account that will receive the created tokens. * @param value The amount that will be created. */ function _mint(address account, uint256 value) internal { require(account != address(0)); _totalSupply = _totalSupply.add(value); _balances[account] = _balances[account].add(value); emit Transfer(address(0), account, value); } /** * @dev Internal function that burns an amount of the token of a given * account. * @param account The account whose tokens will be burnt. * @param value The amount that will be burnt. */ function _burn(address account, uint256 value) internal { require(account != address(0)); _totalSupply = _totalSupply.sub(value); _balances[account] = _balances[account].sub(value); emit Transfer(account, address(0), value); } /** * @dev Internal function that burns an amount of the token of a given * account, deducting from the sender's allowance for said account. Uses the * internal burn function. * Emits an Approval event (reflecting the reduced allowance). * @param account The account whose tokens will be burnt. * @param value The amount that will be burnt. */ function _burnFrom(address account, uint256 value) internal { _allowed[account][msg.sender] = _allowed[account][msg.sender].sub(value); _burn(account, value); emit Approval(account, msg.sender, _allowed[account][msg.sender]); } } // File: openzeppelin-solidity/contracts/access/Roles.sol pragma solidity ^0.5.0; /** * @title Roles * @dev Library for managing addresses assigned to a Role. */ library Roles { struct Role { mapping (address => bool) bearer; } /** * @dev give an account access to this role */ function add(Role storage role, address account) internal { require(account != address(0)); require(!has(role, account)); role.bearer[account] = true; } /** * @dev remove an account's access to this role */ function remove(Role storage role, address account) internal { require(account != address(0)); require(has(role, account)); role.bearer[account] = false; } /** * @dev check if an account has this role * @return bool */ function has(Role storage role, address account) internal view returns (bool) { require(account != address(0)); return role.bearer[account]; } } // File: openzeppelin-solidity/contracts/access/roles/MinterRole.sol pragma solidity ^0.5.0; contract MinterRole { using Roles for Roles.Role; event MinterAdded(address indexed account); event MinterRemoved(address indexed account); Roles.Role private _minters; constructor () internal { _addMinter(msg.sender); } modifier onlyMinter() { require(isMinter(msg.sender)); _; } function isMinter(address account) public view returns (bool) { return _minters.has(account); } function addMinter(address account) public onlyMinter { _addMinter(account); } function renounceMinter() public { _removeMinter(msg.sender); } function _addMinter(address account) internal { _minters.add(account); emit MinterAdded(account); } function _removeMinter(address account) internal { _minters.remove(account); emit MinterRemoved(account); } } // File: contracts/token/ERC20Interface.sol pragma solidity 0.5.9; interface ERC20Interface { // Standard ERC-20 interface. 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); // Extension of ERC-20 interface to support supply adjustment. function mint(address to, uint256 value) external returns (bool); function burn(address from, uint256 value) external returns (bool); } // File: contracts/token/ERC20Base.sol pragma solidity 0.5.9; /// "ERC20Base" is the standard ERC-20 implementation that allows its minter to mint tokens. Both BandToken and /// CommunityToken extend from ERC20Base. In addition to the standard functions, the class provides `transferAndCall` /// function, which performs a transfer and invokes the given function using the provided data. If the destination /// contract uses "ERC20Acceptor" interface, it can verify that the caller properly sends appropriate amount of tokens. contract ERC20Base is ERC20Interface, ERC20, MinterRole { string public name; string public symbol; uint8 public decimals = 18; constructor(string memory _name, string memory _symbol) public { name = _name; symbol = _symbol; } function transferAndCall(address to, uint256 value, bytes4 sig, bytes memory data) public returns (bool) { require(to != address(this)); _transfer(msg.sender, to, value); (bool success,) = to.call(abi.encodePacked(sig, uint256(msg.sender), value, data)); require(success); return true; } function mint(address to, uint256 value) public onlyMinter returns (bool) { _mint(to, value); return true; } function burn(address from, uint256 value) public onlyMinter returns (bool) { _burn(from, value); return true; } } // File: contracts/token/SnapshotToken.sol pragma solidity 0.5.9; contract SnapshotToken is ERC20Base { using SafeMath for uint256; /// IMPORTANT: votingPowers are kept as a linked list of ALL historical changes. /// - This allows the contract to figure out voting power of the address at any nonce `n`, by /// searching for the node that has the biggest nonce that is not greater than `n`. /// - For efficiency, nonce and power are packed into one uint256 integer, with the top 64 bits /// representing nonce, and the bottom 192 bits representing voting power. mapping (address => mapping(uint256 => uint256)) _votingPower; mapping (address => uint256) public votingPowerChangeCount; uint256 public votingPowerChangeNonce = 0; /// Returns user voting power at the given index, that is, as of the user's index^th voting power change function historicalVotingPowerAtIndex(address owner, uint256 index) public view returns (uint256) { require(index <= votingPowerChangeCount[owner]); return _votingPower[owner][index] & ((1 << 192) - 1); // Lower 192 bits } /// Returns user voting power at the given time. Under the hood, this performs binary search /// to look for the largest index at which the nonce is not greater than 'nonce'. /// The voting power at that index is the returning value. function historicalVotingPowerAtNonce(address owner, uint256 nonce) public view returns (uint256) { require(nonce <= votingPowerChangeNonce && nonce < (1 << 64)); uint256 start = 0; uint256 end = votingPowerChangeCount[owner]; while (start < end) { uint256 mid = start.add(end).add(1).div(2); /// Use (start+end+1)/2 to prevent infinite loop. if ((_votingPower[owner][mid] >> 192) > nonce) { /// Upper 64-bit nonce /// If midTime > nonce, this mid can't possibly be the answer. end = mid.sub(1); } else { /// Otherwise, search on the greater side, but still keep mid as a possible option. start = mid; } } return historicalVotingPowerAtIndex(owner, start); } function _transfer(address from, address to, uint256 value) internal { super._transfer(from, to, value); votingPowerChangeNonce = votingPowerChangeNonce.add(1); _changeVotingPower(from); _changeVotingPower(to); } function _mint(address account, uint256 amount) internal { super._mint(account, amount); votingPowerChangeNonce = votingPowerChangeNonce.add(1); _changeVotingPower(account); } function _burn(address account, uint256 amount) internal { super._burn(account, amount); votingPowerChangeNonce = votingPowerChangeNonce.add(1); _changeVotingPower(account); } function _changeVotingPower(address account) internal { uint256 currentIndex = votingPowerChangeCount[account]; uint256 newPower = balanceOf(account); require(newPower < (1 << 192)); require(votingPowerChangeNonce < (1 << 64)); currentIndex = currentIndex.add(1); votingPowerChangeCount[account] = currentIndex; _votingPower[account][currentIndex] = (votingPowerChangeNonce << 192) | newPower; } } // File: contracts/BandToken.sol pragma solidity 0.5.9; /// "BandToken" is the native ERC-20 token of Band Protocol. contract BandToken is ERC20Base("BandToken", "BAND"), SnapshotToken {}
File 4 of 9: KyberReserve
// File: contracts/ERC20Interface.sol pragma solidity 0.4.18; // 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/Utils.sol pragma solidity 0.4.18; /// @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/PermissionGroups.sol pragma solidity 0.4.18; 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; function PermissionGroups() 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)); 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)); TransferAdminPending(newAdmin); 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); 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); 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; OperatorAdded(operator, false); break; } } } } // File: contracts/Withdrawable.sol pragma solidity 0.4.18; /** * @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)); TokenWithdraw(token, amount, sendTo); } event EtherWithdraw(uint amount, address sendTo); /** * @dev Withdraw Ethers */ function withdrawEther(uint amount, address sendTo) external onlyAdmin { sendTo.transfer(amount); EtherWithdraw(amount, sendTo); } } // File: contracts/ConversionRatesInterface.sol pragma solidity 0.4.18; interface ConversionRatesInterface { function recordImbalance( ERC20 token, int buyAmount, uint rateUpdateBlock, uint currentBlock ) public; function getRate(ERC20 token, uint currentBlockNumber, bool buy, uint qty) public view returns(uint); } // File: contracts/SanityRatesInterface.sol pragma solidity 0.4.18; interface SanityRatesInterface { function getSanityRate(ERC20 src, ERC20 dest) public view returns(uint); } // File: contracts/KyberReserveInterface.sol pragma solidity 0.4.18; /// @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/reserves/KyberReserve.sol pragma solidity 0.4.18; /// @title Kyber Reserve contract contract KyberReserve is KyberReserveInterface, Withdrawable, Utils { address public kyberNetwork; bool public tradeEnabled; ConversionRatesInterface public conversionRatesContract; SanityRatesInterface public sanityRatesContract; mapping(bytes32=>bool) public approvedWithdrawAddresses; // sha3(token,address)=>bool mapping(address=>address) public tokenWallet; function KyberReserve(address _kyberNetwork, ConversionRatesInterface _ratesContract, address _admin) public { require(_admin != address(0)); require(_ratesContract != address(0)); require(_kyberNetwork != address(0)); kyberNetwork = _kyberNetwork; conversionRatesContract = _ratesContract; admin = _admin; tradeEnabled = true; } event DepositToken(ERC20 token, uint amount); function() public payable { DepositToken(ETH_TOKEN_ADDRESS, msg.value); } event TradeExecute( address indexed origin, address src, uint srcAmount, address destToken, uint destAmount, address destAddress ); function trade( ERC20 srcToken, uint srcAmount, ERC20 destToken, address destAddress, uint conversionRate, bool validate ) public payable returns(bool) { require(tradeEnabled); require(msg.sender == kyberNetwork); require(doTrade(srcToken, srcAmount, destToken, destAddress, conversionRate, validate)); return true; } event TradeEnabled(bool enable); function enableTrade() public onlyAdmin returns(bool) { tradeEnabled = true; TradeEnabled(true); return true; } function disableTrade() public onlyAlerter returns(bool) { tradeEnabled = false; TradeEnabled(false); return true; } event WithdrawAddressApproved(ERC20 token, address addr, bool approve); function approveWithdrawAddress(ERC20 token, address addr, bool approve) public onlyAdmin { approvedWithdrawAddresses[keccak256(token, addr)] = approve; WithdrawAddressApproved(token, addr, approve); setDecimals(token); if ((tokenWallet[token] == address(0x0)) && (token != ETH_TOKEN_ADDRESS)) { tokenWallet[token] = this; // by default require(token.approve(this, 2 ** 255)); } } event NewTokenWallet(ERC20 token, address wallet); function setTokenWallet(ERC20 token, address wallet) public onlyAdmin { require(wallet != address(0x0)); tokenWallet[token] = wallet; NewTokenWallet(token, wallet); } event WithdrawFunds(ERC20 token, uint amount, address destination); function withdraw(ERC20 token, uint amount, address destination) public onlyOperator returns(bool) { require(approvedWithdrawAddresses[keccak256(token, destination)]); if (token == ETH_TOKEN_ADDRESS) { destination.transfer(amount); } else { require(token.transferFrom(tokenWallet[token], destination, amount)); } WithdrawFunds(token, amount, destination); return true; } event SetContractAddresses(address network, address rate, address sanity); function setContracts( address _kyberNetwork, ConversionRatesInterface _conversionRates, SanityRatesInterface _sanityRates ) public onlyAdmin { require(_kyberNetwork != address(0)); require(_conversionRates != address(0)); kyberNetwork = _kyberNetwork; conversionRatesContract = _conversionRates; sanityRatesContract = _sanityRates; SetContractAddresses(kyberNetwork, conversionRatesContract, sanityRatesContract); } //////////////////////////////////////////////////////////////////////////// /// status functions /////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// function getBalance(ERC20 token) public view returns(uint) { if (token == ETH_TOKEN_ADDRESS) return this.balance; else { address wallet = tokenWallet[token]; uint balanceOfWallet = token.balanceOf(wallet); uint allowanceOfWallet = token.allowance(wallet, this); return (balanceOfWallet < allowanceOfWallet) ? balanceOfWallet : allowanceOfWallet; } } function getDestQty(ERC20 src, ERC20 dest, uint srcQty, uint rate) public view returns(uint) { uint dstDecimals = getDecimals(dest); uint srcDecimals = getDecimals(src); return calcDstQty(srcQty, srcDecimals, dstDecimals, rate); } function getSrcQty(ERC20 src, ERC20 dest, uint dstQty, uint rate) public view returns(uint) { uint dstDecimals = getDecimals(dest); uint srcDecimals = getDecimals(src); return calcSrcQty(dstQty, srcDecimals, dstDecimals, rate); } function getConversionRate(ERC20 src, ERC20 dest, uint srcQty, uint blockNumber) public view returns(uint) { ERC20 token; bool isBuy; if (!tradeEnabled) return 0; if (ETH_TOKEN_ADDRESS == src) { isBuy = true; token = dest; } else if (ETH_TOKEN_ADDRESS == dest) { isBuy = false; token = src; } else { return 0; // pair is not listed } uint rate = conversionRatesContract.getRate(token, blockNumber, isBuy, srcQty); uint destQty = getDestQty(src, dest, srcQty, rate); if (getBalance(dest) < destQty) return 0; if (sanityRatesContract != address(0)) { uint sanityRate = sanityRatesContract.getSanityRate(src, dest); if (rate > sanityRate) return 0; } return rate; } /// @dev do a trade /// @param srcToken Src token /// @param srcAmount Amount of src token /// @param destToken Destination token /// @param destAddress Destination address to send tokens to /// @param validate If true, additional validations are applicable /// @return true iff trade is successful function doTrade( ERC20 srcToken, uint srcAmount, ERC20 destToken, address destAddress, uint conversionRate, bool validate ) internal returns(bool) { // can skip validation if done at kyber network level if (validate) { require(conversionRate > 0); if (srcToken == ETH_TOKEN_ADDRESS) require(msg.value == srcAmount); else require(msg.value == 0); } uint destAmount = getDestQty(srcToken, destToken, srcAmount, conversionRate); // sanity check require(destAmount > 0); // add to imbalance ERC20 token; int tradeAmount; if (srcToken == ETH_TOKEN_ADDRESS) { tradeAmount = int(destAmount); token = destToken; } else { tradeAmount = -1 * int(srcAmount); token = srcToken; } conversionRatesContract.recordImbalance( token, tradeAmount, 0, block.number ); // collect src tokens if (srcToken != ETH_TOKEN_ADDRESS) { require(srcToken.transferFrom(msg.sender, tokenWallet[srcToken], srcAmount)); } // send dest tokens if (destToken == ETH_TOKEN_ADDRESS) { destAddress.transfer(destAmount); } else { require(destToken.transferFrom(tokenWallet[destToken], destAddress, destAmount)); } TradeExecute(msg.sender, srcToken, srcAmount, destToken, destAmount, destAddress); return true; } }
File 5 of 9: FeeBurner
{"ERC20Interface.sol":{"content":"pragma solidity 0.4.18;\n\n\n// https://github.com/ethereum/EIPs/issues/20\ninterface ERC20 {\n function totalSupply() public view returns (uint supply);\n function balanceOf(address _owner) public view returns (uint balance);\n function transfer(address _to, uint _value) public returns (bool success);\n function transferFrom(address _from, address _to, uint _value) public returns (bool success);\n function approve(address _spender, uint _value) public returns (bool success);\n function allowance(address _owner, address _spender) public view returns (uint remaining);\n function decimals() public view returns(uint digits);\n event Approval(address indexed _owner, address indexed _spender, uint _value);\n}\n"},"FeeBurner.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./FeeBurnerInterface.sol\";\nimport \"./Withdrawable.sol\";\nimport \"./Utils3.sol\";\nimport \"./KyberNetworkInterface.sol\";\n\n\ninterface BurnableToken {\n function transferFrom(address _from, address _to, uint _value) public returns (bool);\n function burnFrom(address _from, uint256 _value) public returns (bool);\n}\n\n\ncontract FeeBurner is Withdrawable, FeeBurnerInterface, Utils3 {\n\n mapping(address=\u003euint) public reserveFeesInBps;\n mapping(address=\u003eaddress) public reserveKNCWallet; //wallet holding knc per reserve. from here burn and send fees.\n mapping(address=\u003euint) public walletFeesInBps; // wallet that is the source of tx is entitled so some fees.\n mapping(address=\u003euint) public reserveFeeToBurn;\n mapping(address=\u003euint) public feePayedPerReserve; // track burned fees and sent wallet fees per reserve.\n mapping(address=\u003emapping(address=\u003euint)) public reserveFeeToWallet;\n address public taxWallet;\n uint public taxFeeBps = 0; // burned fees are taxed. % out of burned fees.\n\n BurnableToken public knc;\n KyberNetworkInterface public kyberNetwork;\n uint public kncPerEthRatePrecision = 600 * PRECISION; //--\u003e 1 ether = 600 knc tokens\n\n function FeeBurner(\n address _admin,\n BurnableToken _kncToken,\n KyberNetworkInterface _kyberNetwork,\n uint _initialKncToEthRatePrecision\n )\n public\n {\n require(_admin != address(0));\n require(_kncToken != address(0));\n require(_kyberNetwork != address(0));\n require(_initialKncToEthRatePrecision != 0);\n\n kyberNetwork = _kyberNetwork;\n admin = _admin;\n knc = _kncToken;\n kncPerEthRatePrecision = _initialKncToEthRatePrecision;\n }\n\n event ReserveDataSet(address reserve, uint feeInBps, address kncWallet);\n\n function setReserveData(address reserve, uint feesInBps, address kncWallet) public onlyOperator {\n require(feesInBps \u003c 100); // make sure it is always \u003c 1%\n require(kncWallet != address(0));\n reserveFeesInBps[reserve] = feesInBps;\n reserveKNCWallet[reserve] = kncWallet;\n ReserveDataSet(reserve, feesInBps, kncWallet);\n }\n\n event WalletFeesSet(address wallet, uint feesInBps);\n\n function setWalletFees(address wallet, uint feesInBps) public onlyAdmin {\n require(feesInBps \u003c 10000); // under 100%\n walletFeesInBps[wallet] = feesInBps;\n WalletFeesSet(wallet, feesInBps);\n }\n\n event TaxFeesSet(uint feesInBps);\n\n function setTaxInBps(uint _taxFeeBps) public onlyAdmin {\n require(_taxFeeBps \u003c 10000); // under 100%\n taxFeeBps = _taxFeeBps;\n TaxFeesSet(_taxFeeBps);\n }\n\n event TaxWalletSet(address taxWallet);\n\n function setTaxWallet(address _taxWallet) public onlyAdmin {\n require(_taxWallet != address(0));\n taxWallet = _taxWallet;\n TaxWalletSet(_taxWallet);\n }\n\n event KNCRateSet(uint ethToKncRatePrecision, uint kyberEthKnc, uint kyberKncEth, address updater);\n\n function setKNCRate() public {\n //query kyber for knc rate sell and buy\n uint kyberEthKncRate;\n uint kyberKncEthRate;\n (kyberEthKncRate, ) = kyberNetwork.getExpectedRate(ETH_TOKEN_ADDRESS, ERC20(knc), (10 ** 18));\n (kyberKncEthRate, ) = kyberNetwork.getExpectedRate(ERC20(knc), ETH_TOKEN_ADDRESS, (10 ** 18));\n\n //check \"reasonable\" spread == diff not too big. rate wasn\u0027t tampered.\n require(kyberEthKncRate * kyberKncEthRate \u003c PRECISION ** 2 * 2);\n require(kyberEthKncRate * kyberKncEthRate \u003e PRECISION ** 2 / 2);\n\n require(kyberEthKncRate \u003c= MAX_RATE);\n kncPerEthRatePrecision = kyberEthKncRate;\n KNCRateSet(kncPerEthRatePrecision, kyberEthKncRate, kyberKncEthRate, msg.sender);\n }\n\n event AssignFeeToWallet(address reserve, address wallet, uint walletFee);\n event AssignBurnFees(address reserve, uint burnFee);\n\n function handleFees(uint tradeWeiAmount, address reserve, address wallet) public returns(bool) {\n require(msg.sender == address(kyberNetwork));\n require(tradeWeiAmount \u003c= MAX_QTY);\n\n // MAX_DECIMALS = 18 = KNC_DECIMALS, use this value instead of calling getDecimals() to save gas\n uint kncAmount = calcDestAmountWithDecimals(ETH_DECIMALS, MAX_DECIMALS, tradeWeiAmount, kncPerEthRatePrecision);\n uint fee = kncAmount * reserveFeesInBps[reserve] / 10000;\n\n uint walletFee = fee * walletFeesInBps[wallet] / 10000;\n require(fee \u003e= walletFee);\n uint feeToBurn = fee - walletFee;\n\n if (walletFee \u003e 0) {\n reserveFeeToWallet[reserve][wallet] += walletFee;\n AssignFeeToWallet(reserve, wallet, walletFee);\n }\n\n if (feeToBurn \u003e 0) {\n AssignBurnFees(reserve, feeToBurn);\n reserveFeeToBurn[reserve] += feeToBurn;\n }\n\n return true;\n }\n\n event BurnAssignedFees(address indexed reserve, address sender, uint quantity);\n\n event SendTaxFee(address indexed reserve, address sender, address taxWallet, uint quantity);\n\n // this function is callable by anyone\n function burnReserveFees(address reserve) public {\n uint burnAmount = reserveFeeToBurn[reserve];\n uint taxToSend = 0;\n require(burnAmount \u003e 2);\n reserveFeeToBurn[reserve] = 1; // leave 1 twei to avoid spikes in gas fee\n if (taxWallet != address(0) \u0026\u0026 taxFeeBps != 0) {\n taxToSend = (burnAmount - 1) * taxFeeBps / 10000;\n require(burnAmount - 1 \u003e taxToSend);\n burnAmount -= taxToSend;\n if (taxToSend \u003e 0) {\n require(knc.transferFrom(reserveKNCWallet[reserve], taxWallet, taxToSend));\n SendTaxFee(reserve, msg.sender, taxWallet, taxToSend);\n }\n }\n require(knc.burnFrom(reserveKNCWallet[reserve], burnAmount - 1));\n\n //update reserve \"payments\" so far\n feePayedPerReserve[reserve] += (taxToSend + burnAmount - 1);\n\n BurnAssignedFees(reserve, msg.sender, (burnAmount - 1));\n }\n\n event SendWalletFees(address indexed wallet, address reserve, address sender);\n\n // this function is callable by anyone\n function sendFeeToWallet(address wallet, address reserve) public {\n uint feeAmount = reserveFeeToWallet[reserve][wallet];\n require(feeAmount \u003e 1);\n reserveFeeToWallet[reserve][wallet] = 1; // leave 1 twei to avoid spikes in gas fee\n require(knc.transferFrom(reserveKNCWallet[reserve], wallet, feeAmount - 1));\n\n feePayedPerReserve[reserve] += (feeAmount - 1);\n SendWalletFees(wallet, reserve, msg.sender);\n }\n}\n"},"FeeBurnerInterface.sol":{"content":"pragma solidity 0.4.18;\n\n\ninterface FeeBurnerInterface {\n function handleFees (uint tradeWeiAmount, address reserve, address wallet) public returns(bool);\n function setReserveData(address reserve, uint feesInBps, address kncWallet) public;\n}\n"},"KyberNetworkInterface.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./ERC20Interface.sol\";\n\n\n/// @title Kyber Network interface\ninterface KyberNetworkInterface {\n function maxGasPrice() public view returns(uint);\n function getUserCapInWei(address user) public view returns(uint);\n function getUserCapInTokenWei(address user, ERC20 token) public view returns(uint);\n function enabled() public view returns(bool);\n function info(bytes32 id) public view returns(uint);\n\n function getExpectedRate(ERC20 src, ERC20 dest, uint srcQty) public view\n returns (uint expectedRate, uint slippageRate);\n\n function tradeWithHint(address trader, ERC20 src, uint srcAmount, ERC20 dest, address destAddress,\n uint maxDestAmount, uint minConversionRate, address walletId, bytes hint) public payable returns(uint);\n}\n"},"PermissionGroups.sol":{"content":"pragma solidity 0.4.18;\n\n\ncontract PermissionGroups {\n\n address public admin;\n address public pendingAdmin;\n mapping(address=\u003ebool) internal operators;\n mapping(address=\u003ebool) internal alerters;\n address[] internal operatorsGroup;\n address[] internal alertersGroup;\n uint constant internal MAX_GROUP_SIZE = 50;\n\n function PermissionGroups() public {\n admin = msg.sender;\n }\n\n modifier onlyAdmin() {\n require(msg.sender == admin);\n _;\n }\n\n modifier onlyOperator() {\n require(operators[msg.sender]);\n _;\n }\n\n modifier onlyAlerter() {\n require(alerters[msg.sender]);\n _;\n }\n\n function getOperators () external view returns(address[]) {\n return operatorsGroup;\n }\n\n function getAlerters () external view returns(address[]) {\n return alertersGroup;\n }\n\n event TransferAdminPending(address pendingAdmin);\n\n /**\n * @dev Allows the current admin to set the pendingAdmin address.\n * @param newAdmin The address to transfer ownership to.\n */\n function transferAdmin(address newAdmin) public onlyAdmin {\n require(newAdmin != address(0));\n TransferAdminPending(pendingAdmin);\n pendingAdmin = newAdmin;\n }\n\n /**\n * @dev Allows the current admin to set the admin in one tx. Useful initial deployment.\n * @param newAdmin The address to transfer ownership to.\n */\n function transferAdminQuickly(address newAdmin) public onlyAdmin {\n require(newAdmin != address(0));\n TransferAdminPending(newAdmin);\n AdminClaimed(newAdmin, admin);\n admin = newAdmin;\n }\n\n event AdminClaimed( address newAdmin, address previousAdmin);\n\n /**\n * @dev Allows the pendingAdmin address to finalize the change admin process.\n */\n function claimAdmin() public {\n require(pendingAdmin == msg.sender);\n AdminClaimed(pendingAdmin, admin);\n admin = pendingAdmin;\n pendingAdmin = address(0);\n }\n\n event AlerterAdded (address newAlerter, bool isAdd);\n\n function addAlerter(address newAlerter) public onlyAdmin {\n require(!alerters[newAlerter]); // prevent duplicates.\n require(alertersGroup.length \u003c MAX_GROUP_SIZE);\n\n AlerterAdded(newAlerter, true);\n alerters[newAlerter] = true;\n alertersGroup.push(newAlerter);\n }\n\n function removeAlerter (address alerter) public onlyAdmin {\n require(alerters[alerter]);\n alerters[alerter] = false;\n\n for (uint i = 0; i \u003c alertersGroup.length; ++i) {\n if (alertersGroup[i] == alerter) {\n alertersGroup[i] = alertersGroup[alertersGroup.length - 1];\n alertersGroup.length--;\n AlerterAdded(alerter, false);\n break;\n }\n }\n }\n\n event OperatorAdded(address newOperator, bool isAdd);\n\n function addOperator(address newOperator) public onlyAdmin {\n require(!operators[newOperator]); // prevent duplicates.\n require(operatorsGroup.length \u003c MAX_GROUP_SIZE);\n\n OperatorAdded(newOperator, true);\n operators[newOperator] = true;\n operatorsGroup.push(newOperator);\n }\n\n function removeOperator (address operator) public onlyAdmin {\n require(operators[operator]);\n operators[operator] = false;\n\n for (uint i = 0; i \u003c operatorsGroup.length; ++i) {\n if (operatorsGroup[i] == operator) {\n operatorsGroup[i] = operatorsGroup[operatorsGroup.length - 1];\n operatorsGroup.length -= 1;\n OperatorAdded(operator, false);\n break;\n }\n }\n }\n}\n"},"Utils.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./ERC20Interface.sol\";\n\n\n/// @title Kyber constants contract\ncontract Utils {\n\n ERC20 constant internal ETH_TOKEN_ADDRESS = ERC20(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee);\n uint constant internal PRECISION = (10**18);\n uint constant internal MAX_QTY = (10**28); // 10B tokens\n uint constant internal MAX_RATE = (PRECISION * 10**6); // up to 1M tokens per ETH\n uint constant internal MAX_DECIMALS = 18;\n uint constant internal ETH_DECIMALS = 18;\n mapping(address=\u003euint) internal decimals;\n\n function setDecimals(ERC20 token) internal {\n if (token == ETH_TOKEN_ADDRESS) decimals[token] = ETH_DECIMALS;\n else decimals[token] = token.decimals();\n }\n\n function getDecimals(ERC20 token) internal view returns(uint) {\n if (token == ETH_TOKEN_ADDRESS) return ETH_DECIMALS; // save storage access\n uint tokenDecimals = decimals[token];\n // technically, there might be token with decimals 0\n // moreover, very possible that old tokens have decimals 0\n // these tokens will just have higher gas fees.\n if(tokenDecimals == 0) return token.decimals();\n\n return tokenDecimals;\n }\n\n function calcDstQty(uint srcQty, uint srcDecimals, uint dstDecimals, uint rate) internal pure returns(uint) {\n require(srcQty \u003c= MAX_QTY);\n require(rate \u003c= MAX_RATE);\n\n if (dstDecimals \u003e= srcDecimals) {\n require((dstDecimals - srcDecimals) \u003c= MAX_DECIMALS);\n return (srcQty * rate * (10**(dstDecimals - srcDecimals))) / PRECISION;\n } else {\n require((srcDecimals - dstDecimals) \u003c= MAX_DECIMALS);\n return (srcQty * rate) / (PRECISION * (10**(srcDecimals - dstDecimals)));\n }\n }\n\n function calcSrcQty(uint dstQty, uint srcDecimals, uint dstDecimals, uint rate) internal pure returns(uint) {\n require(dstQty \u003c= MAX_QTY);\n require(rate \u003c= MAX_RATE);\n \n //source quantity is rounded up. to avoid dest quantity being too low.\n uint numerator;\n uint denominator;\n if (srcDecimals \u003e= dstDecimals) {\n require((srcDecimals - dstDecimals) \u003c= MAX_DECIMALS);\n numerator = (PRECISION * dstQty * (10**(srcDecimals - dstDecimals)));\n denominator = rate;\n } else {\n require((dstDecimals - srcDecimals) \u003c= MAX_DECIMALS);\n numerator = (PRECISION * dstQty);\n denominator = (rate * (10**(dstDecimals - srcDecimals)));\n }\n return (numerator + denominator - 1) / denominator; //avoid rounding down errors\n }\n}\n"},"Utils2.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./Utils.sol\";\n\n\ncontract Utils2 is Utils {\n\n /// @dev get the balance of a user.\n /// @param token The token type\n /// @return The balance\n function getBalance(ERC20 token, address user) public view returns(uint) {\n if (token == ETH_TOKEN_ADDRESS)\n return user.balance;\n else\n return token.balanceOf(user);\n }\n\n function getDecimalsSafe(ERC20 token) internal returns(uint) {\n\n if (decimals[token] == 0) {\n setDecimals(token);\n }\n\n return decimals[token];\n }\n\n function calcDestAmount(ERC20 src, ERC20 dest, uint srcAmount, uint rate) internal view returns(uint) {\n return calcDstQty(srcAmount, getDecimals(src), getDecimals(dest), rate);\n }\n\n function calcSrcAmount(ERC20 src, ERC20 dest, uint destAmount, uint rate) internal view returns(uint) {\n return calcSrcQty(destAmount, getDecimals(src), getDecimals(dest), rate);\n }\n\n function calcRateFromQty(uint srcAmount, uint destAmount, uint srcDecimals, uint dstDecimals)\n internal pure returns(uint)\n {\n require(srcAmount \u003c= MAX_QTY);\n require(destAmount \u003c= MAX_QTY);\n\n if (dstDecimals \u003e= srcDecimals) {\n require((dstDecimals - srcDecimals) \u003c= MAX_DECIMALS);\n return (destAmount * PRECISION / ((10 ** (dstDecimals - srcDecimals)) * srcAmount));\n } else {\n require((srcDecimals - dstDecimals) \u003c= MAX_DECIMALS);\n return (destAmount * PRECISION * (10 ** (srcDecimals - dstDecimals)) / srcAmount);\n }\n }\n}\n"},"Utils3.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./Utils2.sol\";\n\n\ncontract Utils3 is Utils2 {\n\n function calcDestAmountWithDecimals(uint srcDecimals, uint destDecimals, uint srcAmount, uint rate) internal pure returns(uint) {\n return calcDstQty(srcAmount, srcDecimals, destDecimals, rate);\n }\n\n}\n"},"Withdrawable.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./ERC20Interface.sol\";\nimport \"./PermissionGroups.sol\";\n\n\n/**\n * @title Contracts that should be able to recover tokens or ethers\n * @author Ilan Doron\n * @dev This allows to recover any tokens or Ethers received in a contract.\n * This will prevent any accidental loss of tokens.\n */\ncontract Withdrawable is PermissionGroups {\n\n event TokenWithdraw(ERC20 token, uint amount, address sendTo);\n\n /**\n * @dev Withdraw all ERC20 compatible tokens\n * @param token ERC20 The address of the token contract\n */\n function withdrawToken(ERC20 token, uint amount, address sendTo) external onlyAdmin {\n require(token.transfer(sendTo, amount));\n TokenWithdraw(token, amount, sendTo);\n }\n\n event EtherWithdraw(uint amount, address sendTo);\n\n /**\n * @dev Withdraw Ethers\n */\n function withdrawEther(uint amount, address sendTo) external onlyAdmin {\n sendTo.transfer(amount);\n EtherWithdraw(amount, sendTo);\n }\n}\n"}}
File 6 of 9: LiquidityConversionRates
{"ConversionRatesInterface.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./ERC20Interface.sol\";\n\n\ninterface ConversionRatesInterface {\n\n function recordImbalance(\n ERC20 token,\n int buyAmount,\n uint rateUpdateBlock,\n uint currentBlock\n )\n public;\n\n function getRate(ERC20 token, uint currentBlockNumber, bool buy, uint qty) public view returns(uint);\n}\n"},"ERC20Interface.sol":{"content":"pragma solidity 0.4.18;\n\n\n// https://github.com/ethereum/EIPs/issues/20\ninterface ERC20 {\n function totalSupply() public view returns (uint supply);\n function balanceOf(address _owner) public view returns (uint balance);\n function transfer(address _to, uint _value) public returns (bool success);\n function transferFrom(address _from, address _to, uint _value) public returns (bool success);\n function approve(address _spender, uint _value) public returns (bool success);\n function allowance(address _owner, address _spender) public view returns (uint remaining);\n function decimals() public view returns(uint digits);\n event Approval(address indexed _owner, address indexed _spender, uint _value);\n}\n"},"LiquidityConversionRates.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"../../ConversionRatesInterface.sol\";\nimport \"../../Withdrawable.sol\";\nimport \"../../Utils.sol\";\nimport \"./LiquidityFormula.sol\";\n\n\ncontract LiquidityConversionRates is ConversionRatesInterface, LiquidityFormula, Withdrawable, Utils {\n\n uint constant FORMULA_PRECISION_BITS = 40;\n\n ERC20 public token;\n address public reserveContract;\n\n uint public numFpBits;\n uint public formulaPrecision;\n\n uint public rInFp;\n uint public pMinInFp;\n\n uint public maxEthCapBuyInFp;\n uint public maxEthCapSellInFp;\n uint public maxQtyInFp;\n\n uint public feeInBps;\n uint public collectedFeesInTwei = 0;\n\n uint public maxBuyRateInPrecision;\n uint public minBuyRateInPrecision;\n uint public maxSellRateInPrecision;\n uint public minSellRateInPrecision;\n\n function LiquidityConversionRates(address _admin, ERC20 _token) public {\n transferAdminQuickly(_admin);\n token = _token;\n setDecimals(token);\n require(getDecimals(token) \u003c= MAX_DECIMALS);\n }\n\n event ReserveAddressSet(address reserve);\n\n function setReserveAddress(address reserve) public onlyAdmin {\n reserveContract = reserve;\n ReserveAddressSet(reserve);\n }\n\n event LiquidityParamsSet(\n uint rInFp,\n uint pMinInFp,\n uint numFpBits,\n uint maxCapBuyInFp,\n uint maxEthCapSellInFp,\n uint feeInBps,\n uint formulaPrecision,\n uint maxQtyInFp,\n uint maxBuyRateInPrecision,\n uint minBuyRateInPrecision,\n uint maxSellRateInPrecision,\n uint minSellRateInPrecision\n );\n\n function setLiquidityParams(\n uint _rInFp,\n uint _pMinInFp,\n uint _numFpBits,\n uint _maxCapBuyInWei,\n uint _maxCapSellInWei,\n uint _feeInBps,\n uint _maxTokenToEthRateInPrecision,\n uint _minTokenToEthRateInPrecision\n ) public onlyAdmin {\n require(_numFpBits == FORMULA_PRECISION_BITS); // only used config, but keep in API\n formulaPrecision = uint(1)\u003c\u003c_numFpBits; // require(formulaPrecision \u003c= MAX_QTY)\n require(_feeInBps \u003c 10000);\n require(_minTokenToEthRateInPrecision \u003c _maxTokenToEthRateInPrecision);\n require(_minTokenToEthRateInPrecision \u003e 0);\n require(_rInFp \u003e 0);\n require(_pMinInFp \u003e 0);\n\n rInFp = _rInFp;\n pMinInFp = _pMinInFp;\n maxQtyInFp = fromWeiToFp(MAX_QTY);\n numFpBits = _numFpBits;\n maxEthCapBuyInFp = fromWeiToFp(_maxCapBuyInWei);\n maxEthCapSellInFp = fromWeiToFp(_maxCapSellInWei);\n feeInBps = _feeInBps;\n maxBuyRateInPrecision = PRECISION * PRECISION / _minTokenToEthRateInPrecision;\n minBuyRateInPrecision = PRECISION * PRECISION / _maxTokenToEthRateInPrecision;\n maxSellRateInPrecision = _maxTokenToEthRateInPrecision;\n minSellRateInPrecision = _minTokenToEthRateInPrecision;\n\n LiquidityParamsSet(\n rInFp,\n pMinInFp,\n numFpBits,\n maxEthCapBuyInFp,\n maxEthCapSellInFp,\n feeInBps,\n formulaPrecision,\n maxQtyInFp,\n maxBuyRateInPrecision,\n minBuyRateInPrecision,\n maxSellRateInPrecision,\n minSellRateInPrecision\n );\n }\n\n function recordImbalance(\n ERC20 conversionToken,\n int buyAmountInTwei,\n uint rateUpdateBlock,\n uint currentBlock\n )\n public\n {\n conversionToken;\n rateUpdateBlock;\n currentBlock;\n\n require(msg.sender == reserveContract);\n if (buyAmountInTwei \u003e 0) {\n // Buy case\n collectedFeesInTwei += calcCollectedFee(abs(buyAmountInTwei));\n } else {\n // Sell case\n collectedFeesInTwei += abs(buyAmountInTwei) * feeInBps / 10000;\n }\n }\n\n event CollectedFeesReset(uint resetFeesInTwei);\n\n function resetCollectedFees() public onlyAdmin {\n uint resetFeesInTwei = collectedFeesInTwei;\n collectedFeesInTwei = 0;\n\n CollectedFeesReset(resetFeesInTwei);\n }\n\n function getRate(\n ERC20 conversionToken,\n uint currentBlockNumber,\n bool buy,\n uint qtyInSrcWei\n ) public view returns(uint) {\n\n currentBlockNumber;\n\n require(qtyInSrcWei \u003c= MAX_QTY);\n uint eInFp = fromWeiToFp(reserveContract.balance);\n uint rateInPrecision = getRateWithE(conversionToken, buy, qtyInSrcWei, eInFp);\n require(rateInPrecision \u003c= MAX_RATE);\n return rateInPrecision;\n }\n\n function getRateWithE(ERC20 conversionToken, bool buy, uint qtyInSrcWei, uint eInFp) public view returns(uint) {\n uint deltaEInFp;\n uint sellInputTokenQtyInFp;\n uint deltaTInFp;\n uint rateInPrecision;\n\n require(qtyInSrcWei \u003c= MAX_QTY);\n require(eInFp \u003c= maxQtyInFp);\n if (conversionToken != token) return 0;\n\n if (buy) {\n // ETH goes in, token goes out\n deltaEInFp = fromWeiToFp(qtyInSrcWei);\n if (deltaEInFp \u003e maxEthCapBuyInFp) return 0;\n\n if (deltaEInFp == 0) {\n rateInPrecision = buyRateZeroQuantity(eInFp);\n } else {\n rateInPrecision = buyRate(eInFp, deltaEInFp);\n }\n } else {\n sellInputTokenQtyInFp = fromTweiToFp(qtyInSrcWei);\n deltaTInFp = valueAfterReducingFee(sellInputTokenQtyInFp);\n if (deltaTInFp == 0) {\n rateInPrecision = sellRateZeroQuantity(eInFp);\n deltaEInFp = 0;\n } else {\n (rateInPrecision, deltaEInFp) = sellRate(eInFp, sellInputTokenQtyInFp, deltaTInFp);\n }\n\n if (deltaEInFp \u003e maxEthCapSellInFp) return 0;\n }\n\n rateInPrecision = rateAfterValidation(rateInPrecision, buy);\n return rateInPrecision;\n }\n\n function rateAfterValidation(uint rateInPrecision, bool buy) public view returns(uint) {\n uint minAllowRateInPrecision;\n uint maxAllowedRateInPrecision;\n\n if (buy) {\n minAllowRateInPrecision = minBuyRateInPrecision;\n maxAllowedRateInPrecision = maxBuyRateInPrecision;\n } else {\n minAllowRateInPrecision = minSellRateInPrecision;\n maxAllowedRateInPrecision = maxSellRateInPrecision;\n }\n\n if ((rateInPrecision \u003e maxAllowedRateInPrecision) || (rateInPrecision \u003c minAllowRateInPrecision)) {\n return 0;\n } else if (rateInPrecision \u003e MAX_RATE) {\n return 0;\n } else {\n return rateInPrecision;\n }\n }\n\n function buyRate(uint eInFp, uint deltaEInFp) public view returns(uint) {\n uint deltaTInFp = deltaTFunc(rInFp, pMinInFp, eInFp, deltaEInFp, formulaPrecision);\n require(deltaTInFp \u003c= maxQtyInFp);\n deltaTInFp = valueAfterReducingFee(deltaTInFp);\n return deltaTInFp * PRECISION / deltaEInFp;\n }\n\n function buyRateZeroQuantity(uint eInFp) public view returns(uint) {\n uint ratePreReductionInPrecision = formulaPrecision * PRECISION / pE(rInFp, pMinInFp, eInFp, formulaPrecision);\n return valueAfterReducingFee(ratePreReductionInPrecision);\n }\n\n function sellRate(\n uint eInFp,\n uint sellInputTokenQtyInFp,\n uint deltaTInFp\n ) public view returns(uint rateInPrecision, uint deltaEInFp) {\n deltaEInFp = deltaEFunc(rInFp, pMinInFp, eInFp, deltaTInFp, formulaPrecision, numFpBits);\n require(deltaEInFp \u003c= maxQtyInFp);\n rateInPrecision = deltaEInFp * PRECISION / sellInputTokenQtyInFp;\n }\n\n function sellRateZeroQuantity(uint eInFp) public view returns(uint) {\n uint ratePreReductionInPrecision = pE(rInFp, pMinInFp, eInFp, formulaPrecision) * PRECISION / formulaPrecision;\n return valueAfterReducingFee(ratePreReductionInPrecision);\n }\n\n function fromTweiToFp(uint qtyInTwei) public view returns(uint) {\n require(qtyInTwei \u003c= MAX_QTY);\n return qtyInTwei * formulaPrecision / (10 ** getDecimals(token));\n }\n\n function fromWeiToFp(uint qtyInwei) public view returns(uint) {\n require(qtyInwei \u003c= MAX_QTY);\n return qtyInwei * formulaPrecision / (10 ** ETH_DECIMALS);\n }\n\n function valueAfterReducingFee(uint val) public view returns(uint) {\n require(val \u003c= BIG_NUMBER);\n return ((10000 - feeInBps) * val) / 10000;\n }\n\n function calcCollectedFee(uint val) public view returns(uint) {\n require(val \u003c= MAX_QTY);\n return val * feeInBps / (10000 - feeInBps);\n }\n\n function abs(int val) public pure returns(uint) {\n if (val \u003c 0) {\n return uint(val * (-1));\n } else {\n return uint(val);\n }\n }\n}\n"},"LiquidityFormula.sol":{"content":"pragma solidity 0.4.18;\n\n\ncontract UtilMath {\n uint public constant BIG_NUMBER = (uint(1)\u003c\u003cuint(200));\n\n function checkMultOverflow(uint x, uint y) public pure returns(bool) {\n if (y == 0) return false;\n return (((x*y) / y) != x);\n }\n\n function compactFraction(uint p, uint q, uint precision) public pure returns (uint, uint) {\n if (q \u003c precision * precision) return (p, q);\n return compactFraction(p/precision, q/precision, precision);\n }\n\n /* solhint-disable code-complexity */\n function exp(uint p, uint q, uint precision) public pure returns (uint) {\n uint n = 0;\n uint nFact = 1;\n uint currentP = 1;\n uint currentQ = 1;\n\n uint sum = 0;\n uint prevSum = 0;\n\n while (true) {\n if (checkMultOverflow(currentP, precision)) return sum;\n if (checkMultOverflow(currentQ, nFact)) return sum;\n\n sum += (currentP * precision) / (currentQ * nFact);\n\n if (sum == prevSum) return sum;\n prevSum = sum;\n\n n++;\n\n if (checkMultOverflow(currentP, p)) return sum;\n if (checkMultOverflow(currentQ, q)) return sum;\n if (checkMultOverflow(nFact, n)) return sum;\n\n currentP *= p;\n currentQ *= q;\n nFact *= n;\n\n (currentP, currentQ) = compactFraction(currentP, currentQ, precision);\n }\n }\n /* solhint-enable code-complexity */\n\n function countLeadingZeros(uint p, uint q) public pure returns (uint) {\n uint denomator = (uint(1)\u003c\u003c255);\n for (int i = 255; i \u003e= 0; i--) {\n if ((q*denomator)/denomator != q) {\n // overflow\n denomator = denomator/2;\n continue;\n }\n if (p/(q*denomator) \u003e 0) return uint(i);\n denomator = denomator/2;\n }\n\n return uint(-1);\n }\n\n // log2 for a number that it in [1,2)\n function log2ForSmallNumber(uint x, uint numPrecisionBits) public pure returns (uint) {\n uint res = 0;\n uint one = (uint(1)\u003c\u003cnumPrecisionBits);\n uint two = 2 * one;\n uint addition = one;\n\n require((x \u003e= one) \u0026\u0026 (x \u003c= two));\n require(numPrecisionBits \u003c 125);\n\n for (uint i = numPrecisionBits; i \u003e 0; i--) {\n x = (x*x) / one;\n addition = addition/2;\n if (x \u003e= two) {\n x = x/2;\n res += addition;\n }\n }\n\n return res;\n }\n\n function logBase2 (uint p, uint q, uint numPrecisionBits) public pure returns (uint) {\n uint n = 0;\n uint precision = (uint(1)\u003c\u003cnumPrecisionBits);\n\n if (p \u003e q) {\n n = countLeadingZeros(p, q);\n }\n\n require(!checkMultOverflow(p, precision));\n require(!checkMultOverflow(n, precision));\n require(!checkMultOverflow(uint(1)\u003c\u003cn, q));\n\n uint y = p * precision / (q * (uint(1)\u003c\u003cn));\n uint log2Small = log2ForSmallNumber(y, numPrecisionBits);\n\n require(n*precision \u003c= BIG_NUMBER);\n require(log2Small \u003c= BIG_NUMBER);\n\n return n * precision + log2Small;\n }\n\n function ln(uint p, uint q, uint numPrecisionBits) public pure returns (uint) {\n uint ln2Numerator = 6931471805599453094172;\n uint ln2Denomerator = 10000000000000000000000;\n\n uint log2x = logBase2(p, q, numPrecisionBits);\n\n require(!checkMultOverflow(ln2Numerator, log2x));\n\n return ln2Numerator * log2x / ln2Denomerator;\n }\n}\n\n\ncontract LiquidityFormula is UtilMath {\n function pE(uint r, uint pMIn, uint e, uint precision) public pure returns (uint) {\n require(!checkMultOverflow(r, e));\n uint expRE = exp(r*e, precision*precision, precision);\n require(!checkMultOverflow(expRE, pMIn));\n return pMIn*expRE / precision;\n }\n\n function deltaTFunc(uint r, uint pMIn, uint e, uint deltaE, uint precision) public pure returns (uint) {\n uint pe = pE(r, pMIn, e, precision);\n uint rpe = r * pe;\n\n require(!checkMultOverflow(r, deltaE));\n uint erdeltaE = exp(r*deltaE, precision*precision, precision);\n\n require(erdeltaE \u003e= precision);\n require(!checkMultOverflow(erdeltaE - precision, precision));\n require(!checkMultOverflow((erdeltaE - precision)*precision, precision));\n require(!checkMultOverflow((erdeltaE - precision)*precision*precision, precision));\n require(!checkMultOverflow(rpe, erdeltaE));\n require(!checkMultOverflow(r, pe));\n\n return (erdeltaE - precision) * precision * precision * precision / (rpe*erdeltaE);\n }\n\n function deltaEFunc(uint r, uint pMIn, uint e, uint deltaT, uint precision, uint numPrecisionBits)\n public pure\n returns (uint)\n {\n uint pe = pE(r, pMIn, e, precision);\n uint rpe = r * pe;\n\n require(!checkMultOverflow(rpe, deltaT));\n require(precision * precision + rpe * deltaT/precision \u003e precision * precision);\n uint lnPart = ln(precision*precision + rpe*deltaT/precision, precision*precision, numPrecisionBits);\n\n require(!checkMultOverflow(r, pe));\n require(!checkMultOverflow(precision, precision));\n require(!checkMultOverflow(rpe, deltaT));\n require(!checkMultOverflow(lnPart, precision));\n\n return lnPart * precision / r;\n }\n}\n"},"PermissionGroups.sol":{"content":"pragma solidity 0.4.18;\n\n\ncontract PermissionGroups {\n\n address public admin;\n address public pendingAdmin;\n mapping(address=\u003ebool) internal operators;\n mapping(address=\u003ebool) internal alerters;\n address[] internal operatorsGroup;\n address[] internal alertersGroup;\n uint constant internal MAX_GROUP_SIZE = 50;\n\n function PermissionGroups() public {\n admin = msg.sender;\n }\n\n modifier onlyAdmin() {\n require(msg.sender == admin);\n _;\n }\n\n modifier onlyOperator() {\n require(operators[msg.sender]);\n _;\n }\n\n modifier onlyAlerter() {\n require(alerters[msg.sender]);\n _;\n }\n\n function getOperators () external view returns(address[]) {\n return operatorsGroup;\n }\n\n function getAlerters () external view returns(address[]) {\n return alertersGroup;\n }\n\n event TransferAdminPending(address pendingAdmin);\n\n /**\n * @dev Allows the current admin to set the pendingAdmin address.\n * @param newAdmin The address to transfer ownership to.\n */\n function transferAdmin(address newAdmin) public onlyAdmin {\n require(newAdmin != address(0));\n TransferAdminPending(pendingAdmin);\n pendingAdmin = newAdmin;\n }\n\n /**\n * @dev Allows the current admin to set the admin in one tx. Useful initial deployment.\n * @param newAdmin The address to transfer ownership to.\n */\n function transferAdminQuickly(address newAdmin) public onlyAdmin {\n require(newAdmin != address(0));\n TransferAdminPending(newAdmin);\n AdminClaimed(newAdmin, admin);\n admin = newAdmin;\n }\n\n event AdminClaimed( address newAdmin, address previousAdmin);\n\n /**\n * @dev Allows the pendingAdmin address to finalize the change admin process.\n */\n function claimAdmin() public {\n require(pendingAdmin == msg.sender);\n AdminClaimed(pendingAdmin, admin);\n admin = pendingAdmin;\n pendingAdmin = address(0);\n }\n\n event AlerterAdded (address newAlerter, bool isAdd);\n\n function addAlerter(address newAlerter) public onlyAdmin {\n require(!alerters[newAlerter]); // prevent duplicates.\n require(alertersGroup.length \u003c MAX_GROUP_SIZE);\n\n AlerterAdded(newAlerter, true);\n alerters[newAlerter] = true;\n alertersGroup.push(newAlerter);\n }\n\n function removeAlerter (address alerter) public onlyAdmin {\n require(alerters[alerter]);\n alerters[alerter] = false;\n\n for (uint i = 0; i \u003c alertersGroup.length; ++i) {\n if (alertersGroup[i] == alerter) {\n alertersGroup[i] = alertersGroup[alertersGroup.length - 1];\n alertersGroup.length--;\n AlerterAdded(alerter, false);\n break;\n }\n }\n }\n\n event OperatorAdded(address newOperator, bool isAdd);\n\n function addOperator(address newOperator) public onlyAdmin {\n require(!operators[newOperator]); // prevent duplicates.\n require(operatorsGroup.length \u003c MAX_GROUP_SIZE);\n\n OperatorAdded(newOperator, true);\n operators[newOperator] = true;\n operatorsGroup.push(newOperator);\n }\n\n function removeOperator (address operator) public onlyAdmin {\n require(operators[operator]);\n operators[operator] = false;\n\n for (uint i = 0; i \u003c operatorsGroup.length; ++i) {\n if (operatorsGroup[i] == operator) {\n operatorsGroup[i] = operatorsGroup[operatorsGroup.length - 1];\n operatorsGroup.length -= 1;\n OperatorAdded(operator, false);\n break;\n }\n }\n }\n}\n"},"Utils.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./ERC20Interface.sol\";\n\n\n/// @title Kyber constants contract\ncontract Utils {\n\n ERC20 constant internal ETH_TOKEN_ADDRESS = ERC20(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee);\n uint constant internal PRECISION = (10**18);\n uint constant internal MAX_QTY = (10**28); // 10B tokens\n uint constant internal MAX_RATE = (PRECISION * 10**6); // up to 1M tokens per ETH\n uint constant internal MAX_DECIMALS = 18;\n uint constant internal ETH_DECIMALS = 18;\n mapping(address=\u003euint) internal decimals;\n\n function setDecimals(ERC20 token) internal {\n if (token == ETH_TOKEN_ADDRESS) decimals[token] = ETH_DECIMALS;\n else decimals[token] = token.decimals();\n }\n\n function getDecimals(ERC20 token) internal view returns(uint) {\n if (token == ETH_TOKEN_ADDRESS) return ETH_DECIMALS; // save storage access\n uint tokenDecimals = decimals[token];\n // technically, there might be token with decimals 0\n // moreover, very possible that old tokens have decimals 0\n // these tokens will just have higher gas fees.\n if(tokenDecimals == 0) return token.decimals();\n\n return tokenDecimals;\n }\n\n function calcDstQty(uint srcQty, uint srcDecimals, uint dstDecimals, uint rate) internal pure returns(uint) {\n require(srcQty \u003c= MAX_QTY);\n require(rate \u003c= MAX_RATE);\n\n if (dstDecimals \u003e= srcDecimals) {\n require((dstDecimals - srcDecimals) \u003c= MAX_DECIMALS);\n return (srcQty * rate * (10**(dstDecimals - srcDecimals))) / PRECISION;\n } else {\n require((srcDecimals - dstDecimals) \u003c= MAX_DECIMALS);\n return (srcQty * rate) / (PRECISION * (10**(srcDecimals - dstDecimals)));\n }\n }\n\n function calcSrcQty(uint dstQty, uint srcDecimals, uint dstDecimals, uint rate) internal pure returns(uint) {\n require(dstQty \u003c= MAX_QTY);\n require(rate \u003c= MAX_RATE);\n \n //source quantity is rounded up. to avoid dest quantity being too low.\n uint numerator;\n uint denominator;\n if (srcDecimals \u003e= dstDecimals) {\n require((srcDecimals - dstDecimals) \u003c= MAX_DECIMALS);\n numerator = (PRECISION * dstQty * (10**(srcDecimals - dstDecimals)));\n denominator = rate;\n } else {\n require((dstDecimals - srcDecimals) \u003c= MAX_DECIMALS);\n numerator = (PRECISION * dstQty);\n denominator = (rate * (10**(dstDecimals - srcDecimals)));\n }\n return (numerator + denominator - 1) / denominator; //avoid rounding down errors\n }\n}\n"},"Withdrawable.sol":{"content":"pragma solidity 0.4.18;\n\n\nimport \"./ERC20Interface.sol\";\nimport \"./PermissionGroups.sol\";\n\n\n/**\n * @title Contracts that should be able to recover tokens or ethers\n * @author Ilan Doron\n * @dev This allows to recover any tokens or Ethers received in a contract.\n * This will prevent any accidental loss of tokens.\n */\ncontract Withdrawable is PermissionGroups {\n\n event TokenWithdraw(ERC20 token, uint amount, address sendTo);\n\n /**\n * @dev Withdraw all ERC20 compatible tokens\n * @param token ERC20 The address of the token contract\n */\n function withdrawToken(ERC20 token, uint amount, address sendTo) external onlyAdmin {\n require(token.transfer(sendTo, amount));\n TokenWithdraw(token, amount, sendTo);\n }\n\n event EtherWithdraw(uint amount, address sendTo);\n\n /**\n * @dev Withdraw Ethers\n */\n function withdrawEther(uint amount, address sendTo) external onlyAdmin {\n sendTo.transfer(amount);\n EtherWithdraw(amount, sendTo);\n }\n}\n"}}
File 7 of 9: KyberUniswapReserve
// File: contracts/ERC20Interface.sol pragma solidity 0.4.18; // 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/PermissionGroups.sol pragma solidity 0.4.18; 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; function PermissionGroups() 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)); 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)); TransferAdminPending(newAdmin); 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); 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); 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; OperatorAdded(operator, false); break; } } } } // File: contracts/Withdrawable.sol pragma solidity 0.4.18; /** * @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)); TokenWithdraw(token, amount, sendTo); } event EtherWithdraw(uint amount, address sendTo); /** * @dev Withdraw Ethers */ function withdrawEther(uint amount, address sendTo) external onlyAdmin { sendTo.transfer(amount); EtherWithdraw(amount, sendTo); } } // File: contracts/KyberReserveInterface.sol pragma solidity 0.4.18; /// @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/Utils.sol pragma solidity 0.4.18; /// @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/Utils2.sol pragma solidity 0.4.18; 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/reserves/bridgeReserves/uniswap/KyberUniswapReserve.sol pragma solidity 0.4.18; interface UniswapExchange { function ethToTokenSwapInput( uint256 min_tokens, uint256 deadline ) external payable returns (uint256 tokens_bought); function tokenToEthSwapInput( uint256 tokens_sold, uint256 min_eth, uint256 deadline ) external returns (uint256 eth_bought); function getEthToTokenInputPrice( uint256 eth_sold ) external view returns (uint256 tokens_bought); function getTokenToEthInputPrice( uint256 tokens_sold ) external view returns (uint256 eth_bought); } interface UniswapFactory { function getExchange(address token) external view returns (address exchange); } /* * A reserve that connects to Uniswap. * * This reserve makes use of an internal inventory for locally filling orders * using the reserve's inventory when certain conditions are met. * Conditions are: * - After trading the inventory will remain within defined limits. * - Uniswap prices do not display internal arbitrage. * - Uniswap ask and bid prices meet minimum spread requirements. * * An additional premium may be added to the converted price for optional * promotions. */ contract KyberUniswapReserve is KyberReserveInterface, Withdrawable, Utils2 { // Parts per 10000 uint public constant DEFAULT_FEE_BPS = 25; UniswapFactory public uniswapFactory; address public kyberNetwork; uint public feeBps = DEFAULT_FEE_BPS; // Uniswap exchange contract for every listed token // token -> exchange mapping (address => address) public tokenExchange; // Internal inventory balance limits // token -> limit mapping (address => uint) public internalInventoryMin; mapping (address => uint) public internalInventoryMax; // Minimum spread in BPS required for using internal inventory // token -> limit mapping (address => uint) public internalActivationMinSpreadBps; // Premium BPS added to internal price (making it better). // token -> limit mapping (address => uint) public internalPricePremiumBps; bool public tradeEnabled = true; /** Constructor */ function KyberUniswapReserve( UniswapFactory _uniswapFactory, address _admin, address _kyberNetwork ) public { require(address(_uniswapFactory) != 0); require(_admin != 0); require(_kyberNetwork != 0); uniswapFactory = _uniswapFactory; admin = _admin; kyberNetwork = _kyberNetwork; } function() public payable { // anyone can deposit ether } /** Returns dest quantity / source quantity. Last bit of the rate indicates whether to use internal inventory: 0 - use uniswap 1 - use internal inventory */ function getConversionRate( ERC20 src, ERC20 dest, uint srcQty, uint blockNumber ) public view returns(uint) { // This makes the UNUSED warning go away. blockNumber; if (!isValidTokens(src, dest)) return 0; if (!tradeEnabled) return 0; if (srcQty == 0) return 0; ERC20 token; if (src == ETH_TOKEN_ADDRESS) { token = dest; } else if (dest == ETH_TOKEN_ADDRESS) { token = src; } else { // Should never arrive here - isValidTokens requires one side to be ETH revert(); } uint convertedQuantity; uint rateSrcDest; uint rateDestSrc; (convertedQuantity, rateSrcDest) = calcUniswapConversion(src, dest, srcQty); if (convertedQuantity == 0) return 0; (, rateDestSrc) = calcUniswapConversion(dest, src, convertedQuantity); uint quantityWithPremium = addPremium(token, convertedQuantity); bool useInternalInventory = shouldUseInternalInventory( src, /* srcToken */ srcQty, /* srcAmount */ dest, /* destToken */ quantityWithPremium, /* destAmount */ rateSrcDest, /* rateSrcDest */ rateDestSrc /* rateDestSrc */ ); uint rate; if (useInternalInventory) { // If using internal inventory add premium to converted quantity rate = calcRateFromQty( srcQty, /* srcAmount */ quantityWithPremium, /* destAmount */ getDecimals(src), /* srcDecimals */ getDecimals(dest) /* dstDecimals */ ); } else { // Use rate calculated from uniswap quantities after fees rate = rateSrcDest; } return applyInternalInventoryHintToRate(rate, useInternalInventory); } function applyInternalInventoryHintToRate( uint rate, bool useInternalInventory ) internal pure returns(uint) { return rate % 2 == (useInternalInventory ? 1 : 0) ? rate : rate - 1; } event TradeExecute( address indexed sender, address src, uint srcAmount, address destToken, uint destAmount, address destAddress, bool useInternalInventory ); /** conversionRate: expected conversion rate should be >= this value. */ function trade( ERC20 srcToken, uint srcAmount, ERC20 destToken, address destAddress, uint conversionRate, bool validate ) public payable returns(bool) { require(tradeEnabled); require(msg.sender == kyberNetwork); require(isValidTokens(srcToken, destToken)); if (validate) { require(conversionRate > 0); if (srcToken == ETH_TOKEN_ADDRESS) require(msg.value == srcAmount); else require(msg.value == 0); } // Making sure srcAmount has been transfered to the reserve. // If srcToken is ETH the value has already been transfered by calling // the function. if (srcToken != ETH_TOKEN_ADDRESS) require(srcToken.transferFrom(msg.sender, address(this), srcAmount)); uint expectedDestAmount = calcDestAmount( srcToken, /* src */ destToken, /* dest */ srcAmount, /* srcAmount */ conversionRate /* rate */ ); bool useInternalInventory = conversionRate % 2 == 1; uint destAmount; UniswapExchange exchange; if (srcToken == ETH_TOKEN_ADDRESS) { if (!useInternalInventory) { // Deduct fees (in ETH) before converting uint quantity = deductFee(srcAmount); exchange = UniswapExchange(tokenExchange[address(destToken)]); destAmount = exchange.ethToTokenSwapInput.value(quantity)( 1, /* min_tokens: uniswap requires it to be > 0 */ 2 ** 255 /* deadline */ ); require(destAmount >= expectedDestAmount); } // Transfer user-expected dest amount require(destToken.transfer(destAddress, expectedDestAmount)); } else { if (!useInternalInventory) { exchange = UniswapExchange(tokenExchange[address(srcToken)]); destAmount = exchange.tokenToEthSwapInput( srcAmount, 1, /* min_eth: uniswap requires it to be > 0 */ 2 ** 255 /* deadline */ ); // Deduct fees (in ETH) after converting destAmount = deductFee(destAmount); require(destAmount >= expectedDestAmount); } // Transfer user-expected dest amount destAddress.transfer(expectedDestAmount); } TradeExecute( msg.sender, /* sender */ srcToken, /* src */ srcAmount, /* srcAmount */ destToken, /* destToken */ expectedDestAmount, /* destAmount */ destAddress, /* destAddress */ useInternalInventory /* useInternalInventory */ ); return true; } event FeeUpdated( uint bps ); function setFee( uint bps ) public onlyAdmin { require(bps <= 10000); feeBps = bps; FeeUpdated(bps); } event InternalActivationConfigUpdated( ERC20 token, uint minSpreadBps, uint premiumBps ); function setInternalActivationConfig( ERC20 token, uint minSpreadBps, uint premiumBps ) public onlyAdmin { require(tokenExchange[address(token)] != address(0)); require(minSpreadBps <= 1000); // min spread <= 10% require(premiumBps <= 500); // premium <= 5% internalActivationMinSpreadBps[address(token)] = minSpreadBps; internalPricePremiumBps[address(token)] = premiumBps; InternalActivationConfigUpdated(token, minSpreadBps, premiumBps); } event InternalInventoryLimitsUpdated( ERC20 token, uint minBalance, uint maxBalance ); function setInternalInventoryLimits( ERC20 token, uint minBalance, uint maxBalance ) public onlyOperator { require(tokenExchange[address(token)] != address(0)); internalInventoryMin[address(token)] = minBalance; internalInventoryMax[address(token)] = maxBalance; InternalInventoryLimitsUpdated(token, minBalance, maxBalance); } event TokenListed( ERC20 token, UniswapExchange exchange ); function listToken(ERC20 token) public onlyAdmin { require(address(token) != 0); UniswapExchange uniswapExchange = UniswapExchange( uniswapFactory.getExchange(token) ); tokenExchange[address(token)] = address(uniswapExchange); setDecimals(token); require(token.approve(uniswapExchange, 2 ** 255)); // internal inventory disabled by default internalInventoryMin[address(token)] = 2 ** 255; internalInventoryMax[address(token)] = 0; internalActivationMinSpreadBps[address(token)] = 0; internalPricePremiumBps[address(token)] = 0; TokenListed(token, uniswapExchange); } event TokenDelisted(ERC20 token); function delistToken(ERC20 token) public onlyAdmin { require(tokenExchange[address(token)] != address(0)); delete tokenExchange[address(token)]; delete internalInventoryMin[address(token)]; delete internalInventoryMax[address(token)]; delete internalActivationMinSpreadBps[address(token)]; delete internalPricePremiumBps[address(token)]; TokenDelisted(token); } function isValidTokens( ERC20 src, ERC20 dest ) public view returns(bool) { return ( ( src == ETH_TOKEN_ADDRESS && tokenExchange[address(dest)] != address(0) ) || ( tokenExchange[address(src)] != address(0) && dest == ETH_TOKEN_ADDRESS ) ); } event TradeEnabled( bool enable ); function enableTrade() public onlyAdmin returns(bool) { tradeEnabled = true; TradeEnabled(true); return true; } function disableTrade() public onlyAlerter returns(bool) { tradeEnabled = false; TradeEnabled(false); return true; } event KyberNetworkSet( address kyberNetwork ); function setKyberNetwork( address _kyberNetwork ) public onlyAdmin { require(_kyberNetwork != 0); kyberNetwork = _kyberNetwork; KyberNetworkSet(kyberNetwork); } /* * Uses amounts and rates to check if the reserve's internal inventory can * be used directly. * * rateEthToToken and rateTokenToEth are in kyber rate format meaning * rate as numerator and 1e18 as denominator. */ function shouldUseInternalInventory( ERC20 srcToken, uint srcAmount, ERC20 destToken, uint destAmount, uint rateSrcDest, uint rateDestSrc ) public view returns(bool) { require(srcAmount < MAX_QTY); require(destAmount < MAX_QTY); // Check for internal inventory balance limitations ERC20 token; if (srcToken == ETH_TOKEN_ADDRESS) { token = destToken; uint tokenBalance = token.balanceOf(this); if ( tokenBalance < destAmount || tokenBalance - destAmount < internalInventoryMin[token] ) { return false; } } else { token = srcToken; if (this.balance < destAmount) return false; if (token.balanceOf(this) + srcAmount > internalInventoryMax[token]) { return false; } } uint normalizedDestSrc = 10 ** 36 / rateDestSrc; // Check for arbitrage if (rateSrcDest > normalizedDestSrc) return false; uint activationSpread = internalActivationMinSpreadBps[token]; uint spread = uint(calculateSpreadBps(normalizedDestSrc, rateSrcDest)); return spread >= activationSpread; } /* * Spread calculation is (ask - bid) / ((ask + bid) / 2). * We multiply by 10000 to get result in BPS. * * Note: if askRate > bidRate result will be negative indicating * internal arbitrage. */ function calculateSpreadBps( uint _askRate, uint _bidRate ) public pure returns(int) { int askRate = int(_askRate); int bidRate = int(_bidRate); return 10000 * 2 * (askRate - bidRate) / (askRate + bidRate); } function deductFee( uint amount ) public view returns(uint) { return amount * (10000 - feeBps) / 10000; } function addPremium( ERC20 token, uint amount ) public view returns(uint) { require(amount <= MAX_QTY); return amount * (10000 + internalPricePremiumBps[token]) / 10000; } function calcUniswapConversion( ERC20 src, ERC20 dest, uint srcQty ) internal view returns(uint destQty, uint rate) { UniswapExchange exchange; if (src == ETH_TOKEN_ADDRESS) { exchange = UniswapExchange(tokenExchange[address(dest)]); uint amountLessFee = deductFee(srcQty); if (amountLessFee == 0) return (0, 0); destQty = exchange.getEthToTokenInputPrice( amountLessFee ); } else { exchange = UniswapExchange(tokenExchange[address(src)]); destQty = deductFee( exchange.getTokenToEthInputPrice(srcQty) ); } rate = calcRateFromQty( srcQty, /* srcAmount */ destQty, /* destAmount */ getDecimals(src), /* srcDecimals */ getDecimals(dest) /* dstDecimals */ ); } }
File 8 of 9: Vyper_contract
# @title Uniswap Exchange Interface V1 # @notice Source code found at https://github.com/uniswap # @notice Use at your own risk contract Factory(): def getExchange(token_addr: address) -> address: constant contract Exchange(): def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei): constant def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: modifying def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei): modifying TokenPurchase: event({buyer: indexed(address), eth_sold: indexed(uint256(wei)), tokens_bought: indexed(uint256)}) EthPurchase: event({buyer: indexed(address), tokens_sold: indexed(uint256), eth_bought: indexed(uint256(wei))}) AddLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)}) RemoveLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)}) Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256}) Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256}) name: public(bytes32) # Uniswap V1 symbol: public(bytes32) # UNI-V1 decimals: public(uint256) # 18 totalSupply: public(uint256) # total number of UNI in existence balances: uint256[address] # UNI balance of an address allowances: (uint256[address])[address] # UNI allowance of one address on another token: address(ERC20) # address of the ERC20 token traded on this contract factory: Factory # interface for the factory that created this contract # @dev This function acts as a contract constructor which is not currently supported in contracts deployed # using create_with_code_of(). It is called once by the factory during contract creation. @public def setup(token_addr: address): assert (self.factory == ZERO_ADDRESS and self.token == ZERO_ADDRESS) and token_addr != ZERO_ADDRESS self.factory = msg.sender self.token = token_addr self.name = 0x556e697377617020563100000000000000000000000000000000000000000000 self.symbol = 0x554e492d56310000000000000000000000000000000000000000000000000000 self.decimals = 18 # @notice Deposit ETH and Tokens (self.token) at current ratio to mint UNI tokens. # @dev min_liquidity does nothing when total UNI supply is 0. # @param min_liquidity Minimum number of UNI sender will mint if total UNI supply is greater than 0. # @param max_tokens 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. @public @payable def addLiquidity(min_liquidity: uint256, max_tokens: uint256, deadline: timestamp) -> uint256: assert deadline > block.timestamp and (max_tokens > 0 and msg.value > 0) total_liquidity: uint256 = self.totalSupply if total_liquidity > 0: assert min_liquidity > 0 eth_reserve: uint256(wei) = self.balance - msg.value token_reserve: uint256 = self.token.balanceOf(self) token_amount: uint256 = msg.value * token_reserve / eth_reserve + 1 liquidity_minted: uint256 = msg.value * total_liquidity / eth_reserve assert max_tokens >= token_amount and liquidity_minted >= min_liquidity self.balances[msg.sender] += liquidity_minted self.totalSupply = total_liquidity + liquidity_minted assert self.token.transferFrom(msg.sender, self, token_amount) log.AddLiquidity(msg.sender, msg.value, token_amount) log.Transfer(ZERO_ADDRESS, msg.sender, liquidity_minted) return liquidity_minted else: assert (self.factory != ZERO_ADDRESS and self.token != ZERO_ADDRESS) and msg.value >= 1000000000 assert self.factory.getExchange(self.token) == self token_amount: uint256 = max_tokens initial_liquidity: uint256 = as_unitless_number(self.balance) self.totalSupply = initial_liquidity self.balances[msg.sender] = initial_liquidity assert self.token.transferFrom(msg.sender, self, token_amount) log.AddLiquidity(msg.sender, msg.value, token_amount) log.Transfer(ZERO_ADDRESS, msg.sender, initial_liquidity) return initial_liquidity # @dev Burn UNI tokens to withdraw ETH and Tokens at current ratio. # @param amount Amount of UNI burned. # @param min_eth Minimum ETH withdrawn. # @param min_tokens Minimum Tokens withdrawn. # @param deadline Time after which this transaction can no longer be executed. # @return The amount of ETH and Tokens withdrawn. @public def removeLiquidity(amount: uint256, min_eth: uint256(wei), min_tokens: uint256, deadline: timestamp) -> (uint256(wei), uint256): assert (amount > 0 and deadline > block.timestamp) and (min_eth > 0 and min_tokens > 0) total_liquidity: uint256 = self.totalSupply assert total_liquidity > 0 token_reserve: uint256 = self.token.balanceOf(self) eth_amount: uint256(wei) = amount * self.balance / total_liquidity token_amount: uint256 = amount * token_reserve / total_liquidity assert eth_amount >= min_eth and token_amount >= min_tokens self.balances[msg.sender] -= amount self.totalSupply = total_liquidity - amount send(msg.sender, eth_amount) assert self.token.transfer(msg.sender, token_amount) log.RemoveLiquidity(msg.sender, eth_amount, token_amount) log.Transfer(msg.sender, ZERO_ADDRESS, amount) return eth_amount, token_amount # @dev Pricing function for converting between ETH and Tokens. # @param input_amount Amount of ETH or Tokens being sold. # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves. # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves. # @return Amount of ETH or Tokens bought. @private @constant def getInputPrice(input_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256: assert input_reserve > 0 and output_reserve > 0 input_amount_with_fee: uint256 = input_amount * 997 numerator: uint256 = input_amount_with_fee * output_reserve denominator: uint256 = (input_reserve * 1000) + input_amount_with_fee return numerator / denominator # @dev Pricing function for converting between ETH and Tokens. # @param output_amount Amount of ETH or Tokens being bought. # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves. # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves. # @return Amount of ETH or Tokens sold. @private @constant def getOutputPrice(output_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256: assert input_reserve > 0 and output_reserve > 0 numerator: uint256 = input_reserve * output_amount * 1000 denominator: uint256 = (output_reserve - output_amount) * 997 return numerator / denominator + 1 @private def ethToTokenInput(eth_sold: uint256(wei), min_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256: assert deadline >= block.timestamp and (eth_sold > 0 and min_tokens > 0) token_reserve: uint256 = self.token.balanceOf(self) tokens_bought: uint256 = self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance - eth_sold), token_reserve) assert tokens_bought >= min_tokens assert self.token.transfer(recipient, tokens_bought) log.TokenPurchase(buyer, eth_sold, tokens_bought) return tokens_bought # @notice Convert ETH to Tokens. # @dev User specifies exact input (msg.value). # @dev User cannot specify minimum output or deadline. @public @payable def __default__(): self.ethToTokenInput(msg.value, 1, block.timestamp, msg.sender, msg.sender) # @notice Convert ETH to Tokens. # @dev User specifies exact input (msg.value) and minimum output. # @param min_tokens Minimum Tokens bought. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of Tokens bought. @public @payable def ethToTokenSwapInput(min_tokens: uint256, deadline: timestamp) -> uint256: return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, msg.sender) # @notice Convert ETH to Tokens and transfers Tokens to recipient. # @dev User specifies exact input (msg.value) and minimum output # @param min_tokens 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. @public @payable def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: assert recipient != self and recipient != ZERO_ADDRESS return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, recipient) @private def ethToTokenOutput(tokens_bought: uint256, max_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei): assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth > 0) token_reserve: uint256 = self.token.balanceOf(self) eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance - max_eth), token_reserve) # Throws if eth_sold > max_eth eth_refund: uint256(wei) = max_eth - as_wei_value(eth_sold, 'wei') if eth_refund > 0: send(buyer, eth_refund) assert self.token.transfer(recipient, tokens_bought) log.TokenPurchase(buyer, as_wei_value(eth_sold, 'wei'), tokens_bought) return as_wei_value(eth_sold, 'wei') # @notice Convert ETH to Tokens. # @dev User specifies maximum input (msg.value) and exact output. # @param tokens_bought Amount of tokens bought. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of ETH sold. @public @payable def ethToTokenSwapOutput(tokens_bought: uint256, deadline: timestamp) -> uint256(wei): return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, msg.sender) # @notice Convert ETH to Tokens and transfers Tokens to recipient. # @dev User specifies maximum input (msg.value) and exact output. # @param tokens_bought 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. @public @payable def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei): assert recipient != self and recipient != ZERO_ADDRESS return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, recipient) @private def tokenToEthInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei): assert deadline >= block.timestamp and (tokens_sold > 0 and min_eth > 0) token_reserve: uint256 = self.token.balanceOf(self) eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance)) wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei') assert wei_bought >= min_eth send(recipient, wei_bought) assert self.token.transferFrom(buyer, self, tokens_sold) log.EthPurchase(buyer, tokens_sold, wei_bought) return wei_bought # @notice Convert Tokens to ETH. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_eth Minimum ETH purchased. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of ETH bought. @public def tokenToEthSwapInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp) -> uint256(wei): return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, msg.sender) # @notice Convert Tokens to ETH and transfers ETH to recipient. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_eth 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. @public def tokenToEthTransferInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, recipient: address) -> uint256(wei): assert recipient != self and recipient != ZERO_ADDRESS return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, recipient) @private def tokenToEthOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256: assert deadline >= block.timestamp and eth_bought > 0 token_reserve: uint256 = self.token.balanceOf(self) tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance)) # tokens sold is always > 0 assert max_tokens >= tokens_sold send(recipient, eth_bought) assert self.token.transferFrom(buyer, self, tokens_sold) log.EthPurchase(buyer, tokens_sold, eth_bought) return tokens_sold # @notice Convert Tokens to ETH. # @dev User specifies maximum input and exact output. # @param eth_bought Amount of ETH purchased. # @param max_tokens Maximum Tokens sold. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of Tokens sold. @public def tokenToEthSwapOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp) -> uint256: return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, msg.sender) # @notice Convert Tokens to ETH and transfers ETH to recipient. # @dev User specifies maximum input and exact output. # @param eth_bought Amount of ETH purchased. # @param max_tokens 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. @public def tokenToEthTransferOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: assert recipient != self and recipient != ZERO_ADDRESS return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, recipient) @private def tokenToTokenInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256: assert (deadline >= block.timestamp and tokens_sold > 0) and (min_tokens_bought > 0 and min_eth_bought > 0) assert exchange_addr != self and exchange_addr != ZERO_ADDRESS token_reserve: uint256 = self.token.balanceOf(self) eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance)) wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei') assert wei_bought >= min_eth_bought assert self.token.transferFrom(buyer, self, tokens_sold) tokens_bought: uint256 = Exchange(exchange_addr).ethToTokenTransferInput(min_tokens_bought, deadline, recipient, value=wei_bought) log.EthPurchase(buyer, tokens_sold, wei_bought) return tokens_bought # @notice Convert Tokens (self.token) to Tokens (token_addr). # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought Minimum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (token_addr) bought. @public def tokenToTokenSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers # Tokens (token_addr) to recipient. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought 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 token_addr The address of the token being purchased. # @return Amount of Tokens (token_addr) bought. @public def tokenToTokenTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr) @private def tokenToTokenOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256: assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth_sold > 0) assert exchange_addr != self and exchange_addr != ZERO_ADDRESS eth_bought: uint256(wei) = Exchange(exchange_addr).getEthToTokenOutputPrice(tokens_bought) token_reserve: uint256 = self.token.balanceOf(self) tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance)) # tokens sold is always > 0 assert max_tokens_sold >= tokens_sold and max_eth_sold >= eth_bought assert self.token.transferFrom(buyer, self, tokens_sold) eth_sold: uint256(wei) = Exchange(exchange_addr).ethToTokenTransferOutput(tokens_bought, deadline, recipient, value=eth_bought) log.EthPurchase(buyer, tokens_sold, eth_bought) return tokens_sold # @notice Convert Tokens (self.token) to Tokens (token_addr). # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold Maximum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToTokenSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers # Tokens (token_addr) to recipient. # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold 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 token_addr The address of the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToTokenTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token). # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought Minimum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param exchange_addr The address of the exchange for the token being purchased. # @return Amount of Tokens (exchange_addr.token) bought. @public def tokenToExchangeSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256: return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers # Tokens (exchange_addr.token) to recipient. # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought 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 exchange_addr The address of the exchange for the token being purchased. # @return Amount of Tokens (exchange_addr.token) bought. @public def tokenToExchangeTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256: assert recipient != self return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token). # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold Maximum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param exchange_addr The address of the exchange for the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToExchangeSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256: return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers # Tokens (exchange_addr.token) to recipient. # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold 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 token_addr The address of the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToExchangeTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256: assert recipient != self return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr) # @notice Public price function for ETH to Token trades with an exact input. # @param eth_sold Amount of ETH sold. # @return Amount of Tokens that can be bought with input ETH. @public @constant def getEthToTokenInputPrice(eth_sold: uint256(wei)) -> uint256: assert eth_sold > 0 token_reserve: uint256 = self.token.balanceOf(self) return self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance), token_reserve) # @notice Public price function for ETH to Token trades with an exact output. # @param tokens_bought Amount of Tokens bought. # @return Amount of ETH needed to buy output Tokens. @public @constant def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei): assert tokens_bought > 0 token_reserve: uint256 = self.token.balanceOf(self) eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance), token_reserve) return as_wei_value(eth_sold, 'wei') # @notice Public price function for Token to ETH trades with an exact input. # @param tokens_sold Amount of Tokens sold. # @return Amount of ETH that can be bought with input Tokens. @public @constant def getTokenToEthInputPrice(tokens_sold: uint256) -> uint256(wei): assert tokens_sold > 0 token_reserve: uint256 = self.token.balanceOf(self) eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance)) return as_wei_value(eth_bought, 'wei') # @notice Public price function for Token to ETH trades with an exact output. # @param eth_bought Amount of output ETH. # @return Amount of Tokens needed to buy output ETH. @public @constant def getTokenToEthOutputPrice(eth_bought: uint256(wei)) -> uint256: assert eth_bought > 0 token_reserve: uint256 = self.token.balanceOf(self) return self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance)) # @return Address of Token that is sold on this exchange. @public @constant def tokenAddress() -> address: return self.token # @return Address of factory that created this exchange. @public @constant def factoryAddress() -> address(Factory): return self.factory # ERC20 compatibility for exchange liquidity modified from # https://github.com/ethereum/vyper/blob/master/examples/tokens/ERC20.vy @public @constant def balanceOf(_owner : address) -> uint256: return self.balances[_owner] @public def transfer(_to : address, _value : uint256) -> bool: self.balances[msg.sender] -= _value self.balances[_to] += _value log.Transfer(msg.sender, _to, _value) return True @public def transferFrom(_from : address, _to : address, _value : uint256) -> bool: self.balances[_from] -= _value self.balances[_to] += _value self.allowances[_from][msg.sender] -= _value log.Transfer(_from, _to, _value) return True @public def approve(_spender : address, _value : uint256) -> bool: self.allowances[msg.sender][_spender] = _value log.Approval(msg.sender, _spender, _value) return True @public @constant def allowance(_owner : address, _spender : address) -> uint256: return self.allowances[_owner][_spender]
File 9 of 9: Vyper_contract
# @title Uniswap Exchange Interface V1 # @notice Source code found at https://github.com/uniswap # @notice Use at your own risk contract Factory(): def getExchange(token_addr: address) -> address: constant contract Exchange(): def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei): constant def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: modifying def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei): modifying TokenPurchase: event({buyer: indexed(address), eth_sold: indexed(uint256(wei)), tokens_bought: indexed(uint256)}) EthPurchase: event({buyer: indexed(address), tokens_sold: indexed(uint256), eth_bought: indexed(uint256(wei))}) AddLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)}) RemoveLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)}) Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256}) Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256}) name: public(bytes32) # Uniswap V1 symbol: public(bytes32) # UNI-V1 decimals: public(uint256) # 18 totalSupply: public(uint256) # total number of UNI in existence balances: uint256[address] # UNI balance of an address allowances: (uint256[address])[address] # UNI allowance of one address on another token: address(ERC20) # address of the ERC20 token traded on this contract factory: Factory # interface for the factory that created this contract # @dev This function acts as a contract constructor which is not currently supported in contracts deployed # using create_with_code_of(). It is called once by the factory during contract creation. @public def setup(token_addr: address): assert (self.factory == ZERO_ADDRESS and self.token == ZERO_ADDRESS) and token_addr != ZERO_ADDRESS self.factory = msg.sender self.token = token_addr self.name = 0x556e697377617020563100000000000000000000000000000000000000000000 self.symbol = 0x554e492d56310000000000000000000000000000000000000000000000000000 self.decimals = 18 # @notice Deposit ETH and Tokens (self.token) at current ratio to mint UNI tokens. # @dev min_liquidity does nothing when total UNI supply is 0. # @param min_liquidity Minimum number of UNI sender will mint if total UNI supply is greater than 0. # @param max_tokens 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. @public @payable def addLiquidity(min_liquidity: uint256, max_tokens: uint256, deadline: timestamp) -> uint256: assert deadline > block.timestamp and (max_tokens > 0 and msg.value > 0) total_liquidity: uint256 = self.totalSupply if total_liquidity > 0: assert min_liquidity > 0 eth_reserve: uint256(wei) = self.balance - msg.value token_reserve: uint256 = self.token.balanceOf(self) token_amount: uint256 = msg.value * token_reserve / eth_reserve + 1 liquidity_minted: uint256 = msg.value * total_liquidity / eth_reserve assert max_tokens >= token_amount and liquidity_minted >= min_liquidity self.balances[msg.sender] += liquidity_minted self.totalSupply = total_liquidity + liquidity_minted assert self.token.transferFrom(msg.sender, self, token_amount) log.AddLiquidity(msg.sender, msg.value, token_amount) log.Transfer(ZERO_ADDRESS, msg.sender, liquidity_minted) return liquidity_minted else: assert (self.factory != ZERO_ADDRESS and self.token != ZERO_ADDRESS) and msg.value >= 1000000000 assert self.factory.getExchange(self.token) == self token_amount: uint256 = max_tokens initial_liquidity: uint256 = as_unitless_number(self.balance) self.totalSupply = initial_liquidity self.balances[msg.sender] = initial_liquidity assert self.token.transferFrom(msg.sender, self, token_amount) log.AddLiquidity(msg.sender, msg.value, token_amount) log.Transfer(ZERO_ADDRESS, msg.sender, initial_liquidity) return initial_liquidity # @dev Burn UNI tokens to withdraw ETH and Tokens at current ratio. # @param amount Amount of UNI burned. # @param min_eth Minimum ETH withdrawn. # @param min_tokens Minimum Tokens withdrawn. # @param deadline Time after which this transaction can no longer be executed. # @return The amount of ETH and Tokens withdrawn. @public def removeLiquidity(amount: uint256, min_eth: uint256(wei), min_tokens: uint256, deadline: timestamp) -> (uint256(wei), uint256): assert (amount > 0 and deadline > block.timestamp) and (min_eth > 0 and min_tokens > 0) total_liquidity: uint256 = self.totalSupply assert total_liquidity > 0 token_reserve: uint256 = self.token.balanceOf(self) eth_amount: uint256(wei) = amount * self.balance / total_liquidity token_amount: uint256 = amount * token_reserve / total_liquidity assert eth_amount >= min_eth and token_amount >= min_tokens self.balances[msg.sender] -= amount self.totalSupply = total_liquidity - amount send(msg.sender, eth_amount) assert self.token.transfer(msg.sender, token_amount) log.RemoveLiquidity(msg.sender, eth_amount, token_amount) log.Transfer(msg.sender, ZERO_ADDRESS, amount) return eth_amount, token_amount # @dev Pricing function for converting between ETH and Tokens. # @param input_amount Amount of ETH or Tokens being sold. # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves. # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves. # @return Amount of ETH or Tokens bought. @private @constant def getInputPrice(input_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256: assert input_reserve > 0 and output_reserve > 0 input_amount_with_fee: uint256 = input_amount * 997 numerator: uint256 = input_amount_with_fee * output_reserve denominator: uint256 = (input_reserve * 1000) + input_amount_with_fee return numerator / denominator # @dev Pricing function for converting between ETH and Tokens. # @param output_amount Amount of ETH or Tokens being bought. # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves. # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves. # @return Amount of ETH or Tokens sold. @private @constant def getOutputPrice(output_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256: assert input_reserve > 0 and output_reserve > 0 numerator: uint256 = input_reserve * output_amount * 1000 denominator: uint256 = (output_reserve - output_amount) * 997 return numerator / denominator + 1 @private def ethToTokenInput(eth_sold: uint256(wei), min_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256: assert deadline >= block.timestamp and (eth_sold > 0 and min_tokens > 0) token_reserve: uint256 = self.token.balanceOf(self) tokens_bought: uint256 = self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance - eth_sold), token_reserve) assert tokens_bought >= min_tokens assert self.token.transfer(recipient, tokens_bought) log.TokenPurchase(buyer, eth_sold, tokens_bought) return tokens_bought # @notice Convert ETH to Tokens. # @dev User specifies exact input (msg.value). # @dev User cannot specify minimum output or deadline. @public @payable def __default__(): self.ethToTokenInput(msg.value, 1, block.timestamp, msg.sender, msg.sender) # @notice Convert ETH to Tokens. # @dev User specifies exact input (msg.value) and minimum output. # @param min_tokens Minimum Tokens bought. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of Tokens bought. @public @payable def ethToTokenSwapInput(min_tokens: uint256, deadline: timestamp) -> uint256: return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, msg.sender) # @notice Convert ETH to Tokens and transfers Tokens to recipient. # @dev User specifies exact input (msg.value) and minimum output # @param min_tokens 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. @public @payable def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: assert recipient != self and recipient != ZERO_ADDRESS return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, recipient) @private def ethToTokenOutput(tokens_bought: uint256, max_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei): assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth > 0) token_reserve: uint256 = self.token.balanceOf(self) eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance - max_eth), token_reserve) # Throws if eth_sold > max_eth eth_refund: uint256(wei) = max_eth - as_wei_value(eth_sold, 'wei') if eth_refund > 0: send(buyer, eth_refund) assert self.token.transfer(recipient, tokens_bought) log.TokenPurchase(buyer, as_wei_value(eth_sold, 'wei'), tokens_bought) return as_wei_value(eth_sold, 'wei') # @notice Convert ETH to Tokens. # @dev User specifies maximum input (msg.value) and exact output. # @param tokens_bought Amount of tokens bought. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of ETH sold. @public @payable def ethToTokenSwapOutput(tokens_bought: uint256, deadline: timestamp) -> uint256(wei): return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, msg.sender) # @notice Convert ETH to Tokens and transfers Tokens to recipient. # @dev User specifies maximum input (msg.value) and exact output. # @param tokens_bought 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. @public @payable def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei): assert recipient != self and recipient != ZERO_ADDRESS return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, recipient) @private def tokenToEthInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei): assert deadline >= block.timestamp and (tokens_sold > 0 and min_eth > 0) token_reserve: uint256 = self.token.balanceOf(self) eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance)) wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei') assert wei_bought >= min_eth send(recipient, wei_bought) assert self.token.transferFrom(buyer, self, tokens_sold) log.EthPurchase(buyer, tokens_sold, wei_bought) return wei_bought # @notice Convert Tokens to ETH. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_eth Minimum ETH purchased. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of ETH bought. @public def tokenToEthSwapInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp) -> uint256(wei): return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, msg.sender) # @notice Convert Tokens to ETH and transfers ETH to recipient. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_eth 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. @public def tokenToEthTransferInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, recipient: address) -> uint256(wei): assert recipient != self and recipient != ZERO_ADDRESS return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, recipient) @private def tokenToEthOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256: assert deadline >= block.timestamp and eth_bought > 0 token_reserve: uint256 = self.token.balanceOf(self) tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance)) # tokens sold is always > 0 assert max_tokens >= tokens_sold send(recipient, eth_bought) assert self.token.transferFrom(buyer, self, tokens_sold) log.EthPurchase(buyer, tokens_sold, eth_bought) return tokens_sold # @notice Convert Tokens to ETH. # @dev User specifies maximum input and exact output. # @param eth_bought Amount of ETH purchased. # @param max_tokens Maximum Tokens sold. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of Tokens sold. @public def tokenToEthSwapOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp) -> uint256: return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, msg.sender) # @notice Convert Tokens to ETH and transfers ETH to recipient. # @dev User specifies maximum input and exact output. # @param eth_bought Amount of ETH purchased. # @param max_tokens 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. @public def tokenToEthTransferOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: assert recipient != self and recipient != ZERO_ADDRESS return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, recipient) @private def tokenToTokenInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256: assert (deadline >= block.timestamp and tokens_sold > 0) and (min_tokens_bought > 0 and min_eth_bought > 0) assert exchange_addr != self and exchange_addr != ZERO_ADDRESS token_reserve: uint256 = self.token.balanceOf(self) eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance)) wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei') assert wei_bought >= min_eth_bought assert self.token.transferFrom(buyer, self, tokens_sold) tokens_bought: uint256 = Exchange(exchange_addr).ethToTokenTransferInput(min_tokens_bought, deadline, recipient, value=wei_bought) log.EthPurchase(buyer, tokens_sold, wei_bought) return tokens_bought # @notice Convert Tokens (self.token) to Tokens (token_addr). # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought Minimum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (token_addr) bought. @public def tokenToTokenSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers # Tokens (token_addr) to recipient. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought 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 token_addr The address of the token being purchased. # @return Amount of Tokens (token_addr) bought. @public def tokenToTokenTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr) @private def tokenToTokenOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256: assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth_sold > 0) assert exchange_addr != self and exchange_addr != ZERO_ADDRESS eth_bought: uint256(wei) = Exchange(exchange_addr).getEthToTokenOutputPrice(tokens_bought) token_reserve: uint256 = self.token.balanceOf(self) tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance)) # tokens sold is always > 0 assert max_tokens_sold >= tokens_sold and max_eth_sold >= eth_bought assert self.token.transferFrom(buyer, self, tokens_sold) eth_sold: uint256(wei) = Exchange(exchange_addr).ethToTokenTransferOutput(tokens_bought, deadline, recipient, value=eth_bought) log.EthPurchase(buyer, tokens_sold, eth_bought) return tokens_sold # @notice Convert Tokens (self.token) to Tokens (token_addr). # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold Maximum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToTokenSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers # Tokens (token_addr) to recipient. # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold 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 token_addr The address of the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToTokenTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token). # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought Minimum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param exchange_addr The address of the exchange for the token being purchased. # @return Amount of Tokens (exchange_addr.token) bought. @public def tokenToExchangeSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256: return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers # Tokens (exchange_addr.token) to recipient. # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought 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 exchange_addr The address of the exchange for the token being purchased. # @return Amount of Tokens (exchange_addr.token) bought. @public def tokenToExchangeTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256: assert recipient != self return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token). # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold Maximum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param exchange_addr The address of the exchange for the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToExchangeSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256: return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers # Tokens (exchange_addr.token) to recipient. # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold 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 token_addr The address of the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToExchangeTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256: assert recipient != self return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr) # @notice Public price function for ETH to Token trades with an exact input. # @param eth_sold Amount of ETH sold. # @return Amount of Tokens that can be bought with input ETH. @public @constant def getEthToTokenInputPrice(eth_sold: uint256(wei)) -> uint256: assert eth_sold > 0 token_reserve: uint256 = self.token.balanceOf(self) return self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance), token_reserve) # @notice Public price function for ETH to Token trades with an exact output. # @param tokens_bought Amount of Tokens bought. # @return Amount of ETH needed to buy output Tokens. @public @constant def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei): assert tokens_bought > 0 token_reserve: uint256 = self.token.balanceOf(self) eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance), token_reserve) return as_wei_value(eth_sold, 'wei') # @notice Public price function for Token to ETH trades with an exact input. # @param tokens_sold Amount of Tokens sold. # @return Amount of ETH that can be bought with input Tokens. @public @constant def getTokenToEthInputPrice(tokens_sold: uint256) -> uint256(wei): assert tokens_sold > 0 token_reserve: uint256 = self.token.balanceOf(self) eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance)) return as_wei_value(eth_bought, 'wei') # @notice Public price function for Token to ETH trades with an exact output. # @param eth_bought Amount of output ETH. # @return Amount of Tokens needed to buy output ETH. @public @constant def getTokenToEthOutputPrice(eth_bought: uint256(wei)) -> uint256: assert eth_bought > 0 token_reserve: uint256 = self.token.balanceOf(self) return self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance)) # @return Address of Token that is sold on this exchange. @public @constant def tokenAddress() -> address: return self.token # @return Address of factory that created this exchange. @public @constant def factoryAddress() -> address(Factory): return self.factory # ERC20 compatibility for exchange liquidity modified from # https://github.com/ethereum/vyper/blob/master/examples/tokens/ERC20.vy @public @constant def balanceOf(_owner : address) -> uint256: return self.balances[_owner] @public def transfer(_to : address, _value : uint256) -> bool: self.balances[msg.sender] -= _value self.balances[_to] += _value log.Transfer(msg.sender, _to, _value) return True @public def transferFrom(_from : address, _to : address, _value : uint256) -> bool: self.balances[_from] -= _value self.balances[_to] += _value self.allowances[_from][msg.sender] -= _value log.Transfer(_from, _to, _value) return True @public def approve(_spender : address, _value : uint256) -> bool: self.allowances[msg.sender][_spender] = _value log.Approval(msg.sender, _spender, _value) return True @public @constant def allowance(_owner : address, _spender : address) -> uint256: return self.allowances[_owner][_spender]