ETH Price: $2,077.41 (+1.98%)

Transaction Decoder

Block:
10801207 at Sep-05-2020 11:48:33 AM +UTC
Transaction Fee:
0.042553236 ETH $88.40
Gas Used:
135,736 Gas / 313.5 Gwei

Account State Difference:

  Address   Before After State Difference Code
(Spark Pool)
161.723188344336913866 Eth161.765741580336913866 Eth0.042553236
0xFE8Dc0b9...077569C27
0.8501186252468 Eth
Nonce: 1390
0.8075653892468 Eth
Nonce: 1391
0.042553236

Execution Trace

MEV Bot: 0x860...F66.c89e4361( )
  • 0xfc90fac785b6cd79a83351ef80922bb484431e8d.689c49c0( )
    • UniswapV2Pair.STATICCALL( )
    • UniswapV2Pair.STATICCALL( )
    • BPool.getBalance( token=0x45f24BaEef268BB6d63AEe5129015d69702BCDfa ) => ( 63976164020338547560730 )
    • BPool.getDenormalizedWeight( token=0x45f24BaEef268BB6d63AEe5129015d69702BCDfa ) => ( 1000000000000000000 )
    • BPool.getBalance( token=0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599 ) => ( 307030774967 )
    • BPool.getDenormalizedWeight( token=0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599 ) => ( 24500000000000000000 )
    • BPool.CALL( )
    • BPool.calcOutGivenIn( tokenBalanceIn=63976164020338547560730, tokenWeightIn=1000000000000000000, tokenBalanceOut=307030774967, tokenWeightOut=24500000000000000000, tokenAmountIn=369614684256218365532, swapFee=20000000000000000 ) => ( tokenAmountOut=70745093 )
    • KyberReserve.getConversionRate( src=0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, dest=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, srcQty=70603602, blockNumber=10801207 ) => ( 28570473893886323745 )
      • ConversionRates.getRate( token=0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, currentBlockNumber=10801207, buy=False, qty=70603602 ) => ( 28570473893886323745 )
      • WBTC.CALL( )
      • WBTC.STATICCALL( )
        File 1 of 5: UniswapV2Pair
        // File: contracts/interfaces/IUniswapV2Pair.sol
        
        pragma solidity >=0.5.0;
        
        interface IUniswapV2Pair {
            event Approval(address indexed owner, address indexed spender, uint value);
            event Transfer(address indexed from, address indexed to, uint value);
        
            function name() external pure returns (string memory);
            function symbol() external pure returns (string memory);
            function decimals() external pure returns (uint8);
            function totalSupply() external view returns (uint);
            function balanceOf(address owner) external view returns (uint);
            function allowance(address owner, address spender) external view returns (uint);
        
            function approve(address spender, uint value) external returns (bool);
            function transfer(address to, uint value) external returns (bool);
            function transferFrom(address from, address to, uint value) external returns (bool);
        
            function DOMAIN_SEPARATOR() external view returns (bytes32);
            function PERMIT_TYPEHASH() external pure returns (bytes32);
            function nonces(address owner) external view returns (uint);
        
            function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
        
            event Mint(address indexed sender, uint amount0, uint amount1);
            event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
            event Swap(
                address indexed sender,
                uint amount0In,
                uint amount1In,
                uint amount0Out,
                uint amount1Out,
                address indexed to
            );
            event Sync(uint112 reserve0, uint112 reserve1);
        
            function MINIMUM_LIQUIDITY() external pure returns (uint);
            function factory() external view returns (address);
            function token0() external view returns (address);
            function token1() external view returns (address);
            function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
            function price0CumulativeLast() external view returns (uint);
            function price1CumulativeLast() external view returns (uint);
            function kLast() external view returns (uint);
        
            function mint(address to) external returns (uint liquidity);
            function burn(address to) external returns (uint amount0, uint amount1);
            function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
            function skim(address to) external;
            function sync() external;
        
            function initialize(address, address) external;
        }
        
        // File: contracts/interfaces/IUniswapV2ERC20.sol
        
        pragma solidity >=0.5.0;
        
        interface IUniswapV2ERC20 {
            event Approval(address indexed owner, address indexed spender, uint value);
            event Transfer(address indexed from, address indexed to, uint value);
        
            function name() external pure returns (string memory);
            function symbol() external pure returns (string memory);
            function decimals() external pure returns (uint8);
            function totalSupply() external view returns (uint);
            function balanceOf(address owner) external view returns (uint);
            function allowance(address owner, address spender) external view returns (uint);
        
            function approve(address spender, uint value) external returns (bool);
            function transfer(address to, uint value) external returns (bool);
            function transferFrom(address from, address to, uint value) external returns (bool);
        
            function DOMAIN_SEPARATOR() external view returns (bytes32);
            function PERMIT_TYPEHASH() external pure returns (bytes32);
            function nonces(address owner) external view returns (uint);
        
            function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
        }
        
        // File: contracts/libraries/SafeMath.sol
        
        pragma solidity =0.5.16;
        
        // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
        
        library SafeMath {
            function add(uint x, uint y) internal pure returns (uint z) {
                require((z = x + y) >= x, 'ds-math-add-overflow');
            }
        
            function sub(uint x, uint y) internal pure returns (uint z) {
                require((z = x - y) <= x, 'ds-math-sub-underflow');
            }
        
            function mul(uint x, uint y) internal pure returns (uint z) {
                require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
            }
        }
        
        // File: contracts/UniswapV2ERC20.sol
        
        pragma solidity =0.5.16;
        
        
        
        contract UniswapV2ERC20 is IUniswapV2ERC20 {
            using SafeMath for uint;
        
            string public constant name = 'Uniswap V2';
            string public constant symbol = 'UNI-V2';
            uint8 public constant decimals = 18;
            uint  public totalSupply;
            mapping(address => uint) public balanceOf;
            mapping(address => mapping(address => uint)) public allowance;
        
            bytes32 public DOMAIN_SEPARATOR;
            // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
            bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
            mapping(address => uint) public nonces;
        
            event Approval(address indexed owner, address indexed spender, uint value);
            event Transfer(address indexed from, address indexed to, uint value);
        
            constructor() public {
                uint chainId;
                assembly {
                    chainId := chainid
                }
                DOMAIN_SEPARATOR = keccak256(
                    abi.encode(
                        keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
                        keccak256(bytes(name)),
                        keccak256(bytes('1')),
                        chainId,
                        address(this)
                    )
                );
            }
        
            function _mint(address to, uint value) internal {
                totalSupply = totalSupply.add(value);
                balanceOf[to] = balanceOf[to].add(value);
                emit Transfer(address(0), to, value);
            }
        
            function _burn(address from, uint value) internal {
                balanceOf[from] = balanceOf[from].sub(value);
                totalSupply = totalSupply.sub(value);
                emit Transfer(from, address(0), value);
            }
        
            function _approve(address owner, address spender, uint value) private {
                allowance[owner][spender] = value;
                emit Approval(owner, spender, value);
            }
        
            function _transfer(address from, address to, uint value) private {
                balanceOf[from] = balanceOf[from].sub(value);
                balanceOf[to] = balanceOf[to].add(value);
                emit Transfer(from, to, value);
            }
        
            function approve(address spender, uint value) external returns (bool) {
                _approve(msg.sender, spender, value);
                return true;
            }
        
            function transfer(address to, uint value) external returns (bool) {
                _transfer(msg.sender, to, value);
                return true;
            }
        
            function transferFrom(address from, address to, uint value) external returns (bool) {
                if (allowance[from][msg.sender] != uint(-1)) {
                    allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
                }
                _transfer(from, to, value);
                return true;
            }
        
            function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
                require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
                bytes32 digest = keccak256(
                    abi.encodePacked(
                        '\x19\x01',
                        DOMAIN_SEPARATOR,
                        keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                    )
                );
                address recoveredAddress = ecrecover(digest, v, r, s);
                require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
                _approve(owner, spender, value);
            }
        }
        
        // File: contracts/libraries/Math.sol
        
        pragma solidity =0.5.16;
        
        // a library for performing various math operations
        
        library Math {
            function min(uint x, uint y) internal pure returns (uint z) {
                z = x < y ? x : y;
            }
        
            // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
            function sqrt(uint y) internal pure returns (uint z) {
                if (y > 3) {
                    z = y;
                    uint x = y / 2 + 1;
                    while (x < z) {
                        z = x;
                        x = (y / x + x) / 2;
                    }
                } else if (y != 0) {
                    z = 1;
                }
            }
        }
        
        // File: contracts/libraries/UQ112x112.sol
        
        pragma solidity =0.5.16;
        
        // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))
        
        // range: [0, 2**112 - 1]
        // resolution: 1 / 2**112
        
        library UQ112x112 {
            uint224 constant Q112 = 2**112;
        
            // encode a uint112 as a UQ112x112
            function encode(uint112 y) internal pure returns (uint224 z) {
                z = uint224(y) * Q112; // never overflows
            }
        
            // divide a UQ112x112 by a uint112, returning a UQ112x112
            function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
                z = x / uint224(y);
            }
        }
        
        // File: contracts/interfaces/IERC20.sol
        
        pragma solidity >=0.5.0;
        
        interface IERC20 {
            event Approval(address indexed owner, address indexed spender, uint value);
            event Transfer(address indexed from, address indexed to, uint value);
        
            function name() external view returns (string memory);
            function symbol() external view returns (string memory);
            function decimals() external view returns (uint8);
            function totalSupply() external view returns (uint);
            function balanceOf(address owner) external view returns (uint);
            function allowance(address owner, address spender) external view returns (uint);
        
            function approve(address spender, uint value) external returns (bool);
            function transfer(address to, uint value) external returns (bool);
            function transferFrom(address from, address to, uint value) external returns (bool);
        }
        
        // File: contracts/interfaces/IUniswapV2Factory.sol
        
        pragma solidity >=0.5.0;
        
        interface IUniswapV2Factory {
            event PairCreated(address indexed token0, address indexed token1, address pair, uint);
        
            function feeTo() external view returns (address);
            function feeToSetter() external view returns (address);
        
            function getPair(address tokenA, address tokenB) external view returns (address pair);
            function allPairs(uint) external view returns (address pair);
            function allPairsLength() external view returns (uint);
        
            function createPair(address tokenA, address tokenB) external returns (address pair);
        
            function setFeeTo(address) external;
            function setFeeToSetter(address) external;
        }
        
        // File: contracts/interfaces/IUniswapV2Callee.sol
        
        pragma solidity >=0.5.0;
        
        interface IUniswapV2Callee {
            function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external;
        }
        
        // File: contracts/UniswapV2Pair.sol
        
        pragma solidity =0.5.16;
        
        
        
        
        
        
        
        
        contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 {
            using SafeMath  for uint;
            using UQ112x112 for uint224;
        
            uint public constant MINIMUM_LIQUIDITY = 10**3;
            bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
        
            address public factory;
            address public token0;
            address public token1;
        
            uint112 private reserve0;           // uses single storage slot, accessible via getReserves
            uint112 private reserve1;           // uses single storage slot, accessible via getReserves
            uint32  private blockTimestampLast; // uses single storage slot, accessible via getReserves
        
            uint public price0CumulativeLast;
            uint public price1CumulativeLast;
            uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
        
            uint private unlocked = 1;
            modifier lock() {
                require(unlocked == 1, 'UniswapV2: LOCKED');
                unlocked = 0;
                _;
                unlocked = 1;
            }
        
            function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
                _reserve0 = reserve0;
                _reserve1 = reserve1;
                _blockTimestampLast = blockTimestampLast;
            }
        
            function _safeTransfer(address token, address to, uint value) private {
                (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
                require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED');
            }
        
            event Mint(address indexed sender, uint amount0, uint amount1);
            event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
            event Swap(
                address indexed sender,
                uint amount0In,
                uint amount1In,
                uint amount0Out,
                uint amount1Out,
                address indexed to
            );
            event Sync(uint112 reserve0, uint112 reserve1);
        
            constructor() public {
                factory = msg.sender;
            }
        
            // called once by the factory at time of deployment
            function initialize(address _token0, address _token1) external {
                require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check
                token0 = _token0;
                token1 = _token1;
            }
        
            // update reserves and, on the first call per block, price accumulators
            function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private {
                require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW');
                uint32 blockTimestamp = uint32(block.timestamp % 2**32);
                uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
                if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
                    // * never overflows, and + overflow is desired
                    price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
                    price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
                }
                reserve0 = uint112(balance0);
                reserve1 = uint112(balance1);
                blockTimestampLast = blockTimestamp;
                emit Sync(reserve0, reserve1);
            }
        
            // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)
            function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
                address feeTo = IUniswapV2Factory(factory).feeTo();
                feeOn = feeTo != address(0);
                uint _kLast = kLast; // gas savings
                if (feeOn) {
                    if (_kLast != 0) {
                        uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1));
                        uint rootKLast = Math.sqrt(_kLast);
                        if (rootK > rootKLast) {
                            uint numerator = totalSupply.mul(rootK.sub(rootKLast));
                            uint denominator = rootK.mul(5).add(rootKLast);
                            uint liquidity = numerator / denominator;
                            if (liquidity > 0) _mint(feeTo, liquidity);
                        }
                    }
                } else if (_kLast != 0) {
                    kLast = 0;
                }
            }
        
            // this low-level function should be called from a contract which performs important safety checks
            function mint(address to) external lock returns (uint liquidity) {
                (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
                uint balance0 = IERC20(token0).balanceOf(address(this));
                uint balance1 = IERC20(token1).balanceOf(address(this));
                uint amount0 = balance0.sub(_reserve0);
                uint amount1 = balance1.sub(_reserve1);
        
                bool feeOn = _mintFee(_reserve0, _reserve1);
                uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
                if (_totalSupply == 0) {
                    liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
                   _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
                } else {
                    liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
                }
                require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED');
                _mint(to, liquidity);
        
                _update(balance0, balance1, _reserve0, _reserve1);
                if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
                emit Mint(msg.sender, amount0, amount1);
            }
        
            // this low-level function should be called from a contract which performs important safety checks
            function burn(address to) external lock returns (uint amount0, uint amount1) {
                (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
                address _token0 = token0;                                // gas savings
                address _token1 = token1;                                // gas savings
                uint balance0 = IERC20(_token0).balanceOf(address(this));
                uint balance1 = IERC20(_token1).balanceOf(address(this));
                uint liquidity = balanceOf[address(this)];
        
                bool feeOn = _mintFee(_reserve0, _reserve1);
                uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
                amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
                amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
                require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED');
                _burn(address(this), liquidity);
                _safeTransfer(_token0, to, amount0);
                _safeTransfer(_token1, to, amount1);
                balance0 = IERC20(_token0).balanceOf(address(this));
                balance1 = IERC20(_token1).balanceOf(address(this));
        
                _update(balance0, balance1, _reserve0, _reserve1);
                if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
                emit Burn(msg.sender, amount0, amount1, to);
            }
        
            // this low-level function should be called from a contract which performs important safety checks
            function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
                require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT');
                (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
                require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY');
        
                uint balance0;
                uint balance1;
                { // scope for _token{0,1}, avoids stack too deep errors
                address _token0 = token0;
                address _token1 = token1;
                require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO');
                if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
                if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
                if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
                balance0 = IERC20(_token0).balanceOf(address(this));
                balance1 = IERC20(_token1).balanceOf(address(this));
                }
                uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
                uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
                require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT');
                { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
                uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
                uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
                require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K');
                }
        
                _update(balance0, balance1, _reserve0, _reserve1);
                emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
            }
        
            // force balances to match reserves
            function skim(address to) external lock {
                address _token0 = token0; // gas savings
                address _token1 = token1; // gas savings
                _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0));
                _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1));
            }
        
            // force reserves to match balances
            function sync() external lock {
                _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1);
            }
        }

        File 2 of 5: BPool
        {"BColor.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\ncontract BColor {\n    function getColor()\n        external view\n        returns (bytes32);\n}\n\ncontract BBronze is BColor {\n    function getColor()\n        external view\n        returns (bytes32) {\n            return bytes32(\"BRONZE\");\n        }\n}\n"},"BConst.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BColor.sol\";\n\ncontract BConst is BBronze {\n    uint public constant BONE              = 10**18;\n\n    uint public constant MIN_BOUND_TOKENS  = 2;\n    uint public constant MAX_BOUND_TOKENS  = 8;\n\n    uint public constant MIN_FEE           = BONE / 10**6;\n    uint public constant MAX_FEE           = BONE / 10;\n    uint public constant EXIT_FEE          = 0;\n\n    uint public constant MIN_WEIGHT        = BONE;\n    uint public constant MAX_WEIGHT        = BONE * 50;\n    uint public constant MAX_TOTAL_WEIGHT  = BONE * 50;\n    uint public constant MIN_BALANCE       = BONE / 10**12;\n\n    uint public constant INIT_POOL_SUPPLY  = BONE * 100;\n\n    uint public constant MIN_BPOW_BASE     = 1 wei;\n    uint public constant MAX_BPOW_BASE     = (2 * BONE) - 1 wei;\n    uint public constant BPOW_PRECISION    = BONE / 10**10;\n\n    uint public constant MAX_IN_RATIO      = BONE / 2;\n    uint public constant MAX_OUT_RATIO     = (BONE / 3) + 1 wei;\n}\n"},"BMath.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BNum.sol\";\n\ncontract BMath is BBronze, BConst, BNum {\n    /**********************************************************************************************\n    // calcSpotPrice                                                                             //\n    // sP = spotPrice                                                                            //\n    // bI = tokenBalanceIn                ( bI / wI )         1                                  //\n    // bO = tokenBalanceOut         sP =  -----------  *  ----------                             //\n    // wI = tokenWeightIn                 ( bO / wO )     ( 1 - sF )                             //\n    // wO = tokenWeightOut                                                                       //\n    // sF = swapFee                                                                              //\n    **********************************************************************************************/\n    function calcSpotPrice(\n        uint tokenBalanceIn,\n        uint tokenWeightIn,\n        uint tokenBalanceOut,\n        uint tokenWeightOut,\n        uint swapFee\n    )\n        public pure\n        returns (uint spotPrice)\n    {\n        uint numer = bdiv(tokenBalanceIn, tokenWeightIn);\n        uint denom = bdiv(tokenBalanceOut, tokenWeightOut);\n        uint ratio = bdiv(numer, denom);\n        uint scale = bdiv(BONE, bsub(BONE, swapFee));\n        return  (spotPrice = bmul(ratio, scale));\n    }\n\n    /**********************************************************************************************\n    // calcOutGivenIn                                                                            //\n    // aO = tokenAmountOut                                                                       //\n    // bO = tokenBalanceOut                                                                      //\n    // bI = tokenBalanceIn              /      /            bI             \\    (wI / wO) \\      //\n    // aI = tokenAmountIn    aO = bO * |  1 - | --------------------------  | ^            |     //\n    // wI = tokenWeightIn               \\      \\ ( bI + ( aI * ( 1 - sF )) /              /      //\n    // wO = tokenWeightOut                                                                       //\n    // sF = swapFee                                                                              //\n    **********************************************************************************************/\n    function calcOutGivenIn(\n        uint tokenBalanceIn,\n        uint tokenWeightIn,\n        uint tokenBalanceOut,\n        uint tokenWeightOut,\n        uint tokenAmountIn,\n        uint swapFee\n    )\n        public pure\n        returns (uint tokenAmountOut)\n    {\n        uint weightRatio = bdiv(tokenWeightIn, tokenWeightOut);\n        uint adjustedIn = bsub(BONE, swapFee);\n        adjustedIn = bmul(tokenAmountIn, adjustedIn);\n        uint y = bdiv(tokenBalanceIn, badd(tokenBalanceIn, adjustedIn));\n        uint foo = bpow(y, weightRatio);\n        uint bar = bsub(BONE, foo);\n        tokenAmountOut = bmul(tokenBalanceOut, bar);\n        return tokenAmountOut;\n    }\n\n    /**********************************************************************************************\n    // calcInGivenOut                                                                            //\n    // aI = tokenAmountIn                                                                        //\n    // bO = tokenBalanceOut               /  /     bO      \\    (wO / wI)      \\                 //\n    // bI = tokenBalanceIn          bI * |  | ------------  | ^            - 1  |                //\n    // aO = tokenAmountOut    aI =        \\  \\ ( bO - aO ) /                   /                 //\n    // wI = tokenWeightIn           --------------------------------------------                 //\n    // wO = tokenWeightOut                          ( 1 - sF )                                   //\n    // sF = swapFee                                                                              //\n    **********************************************************************************************/\n    function calcInGivenOut(\n        uint tokenBalanceIn,\n        uint tokenWeightIn,\n        uint tokenBalanceOut,\n        uint tokenWeightOut,\n        uint tokenAmountOut,\n        uint swapFee\n    )\n        public pure\n        returns (uint tokenAmountIn)\n    {\n        uint weightRatio = bdiv(tokenWeightOut, tokenWeightIn);\n        uint diff = bsub(tokenBalanceOut, tokenAmountOut);\n        uint y = bdiv(tokenBalanceOut, diff);\n        uint foo = bpow(y, weightRatio);\n        foo = bsub(foo, BONE);\n        tokenAmountIn = bsub(BONE, swapFee);\n        tokenAmountIn = bdiv(bmul(tokenBalanceIn, foo), tokenAmountIn);\n        return tokenAmountIn;\n    }\n\n    /**********************************************************************************************\n    // calcPoolOutGivenSingleIn                                                                  //\n    // pAo = poolAmountOut         /                                              \\              //\n    // tAi = tokenAmountIn        ///      /     //    wI \\      \\\\       \\     wI \\             //\n    // wI = tokenWeightIn        //| tAi *| 1 - || 1 - --  | * sF || + tBi \\    --  \\            //\n    // tW = totalWeight     pAo=||  \\      \\     \\\\    tW /      //         | ^ tW   | * pS - pS //\n    // tBi = tokenBalanceIn      \\\\  ------------------------------------- /        /            //\n    // pS = poolSupply            \\\\                    tBi               /        /             //\n    // sF = swapFee                \\                                              /              //\n    **********************************************************************************************/\n    function calcPoolOutGivenSingleIn(\n        uint tokenBalanceIn,\n        uint tokenWeightIn,\n        uint poolSupply,\n        uint totalWeight,\n        uint tokenAmountIn,\n        uint swapFee\n    )\n        public pure\n        returns (uint poolAmountOut)\n    {\n        // Charge the trading fee for the proportion of tokenAi\n        ///  which is implicitly traded to the other pool tokens.\n        // That proportion is (1- weightTokenIn)\n        // tokenAiAfterFee = tAi * (1 - (1-weightTi) * poolFee);\n        uint normalizedWeight = bdiv(tokenWeightIn, totalWeight);\n        uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee); \n        uint tokenAmountInAfterFee = bmul(tokenAmountIn, bsub(BONE, zaz));\n\n        uint newTokenBalanceIn = badd(tokenBalanceIn, tokenAmountInAfterFee);\n        uint tokenInRatio = bdiv(newTokenBalanceIn, tokenBalanceIn);\n\n        // uint newPoolSupply = (ratioTi ^ weightTi) * poolSupply;\n        uint poolRatio = bpow(tokenInRatio, normalizedWeight);\n        uint newPoolSupply = bmul(poolRatio, poolSupply);\n        poolAmountOut = bsub(newPoolSupply, poolSupply);\n        return poolAmountOut;\n    }\n\n    /**********************************************************************************************\n    // calcSingleInGivenPoolOut                                                                  //\n    // tAi = tokenAmountIn              //(pS + pAo)\\     /    1    \\\\                           //\n    // pS = poolSupply                 || ---------  | ^ | --------- || * bI - bI                //\n    // pAo = poolAmountOut              \\\\    pS    /     \\(wI / tW)//                           //\n    // bI = balanceIn          tAi =  --------------------------------------------               //\n    // wI = weightIn                              /      wI  \\                                   //\n    // tW = totalWeight                          |  1 - ----  |  * sF                            //\n    // sF = swapFee                               \\      tW  /                                   //\n    **********************************************************************************************/\n    function calcSingleInGivenPoolOut(\n        uint tokenBalanceIn,\n        uint tokenWeightIn,\n        uint poolSupply,\n        uint totalWeight,\n        uint poolAmountOut,\n        uint swapFee\n    )\n        public pure\n        returns (uint tokenAmountIn)\n    {\n        uint normalizedWeight = bdiv(tokenWeightIn, totalWeight);\n        uint newPoolSupply = badd(poolSupply, poolAmountOut);\n        uint poolRatio = bdiv(newPoolSupply, poolSupply);\n      \n        //uint newBalTi = poolRatio^(1/weightTi) * balTi;\n        uint boo = bdiv(BONE, normalizedWeight); \n        uint tokenInRatio = bpow(poolRatio, boo);\n        uint newTokenBalanceIn = bmul(tokenInRatio, tokenBalanceIn);\n        uint tokenAmountInAfterFee = bsub(newTokenBalanceIn, tokenBalanceIn);\n        // Do reverse order of fees charged in joinswap_ExternAmountIn, this way \n        //     ``` pAo == joinswap_ExternAmountIn(Ti, joinswap_PoolAmountOut(pAo, Ti)) ```\n        //uint tAi = tAiAfterFee / (1 - (1-weightTi) * swapFee) ;\n        uint zar = bmul(bsub(BONE, normalizedWeight), swapFee);\n        tokenAmountIn = bdiv(tokenAmountInAfterFee, bsub(BONE, zar));\n        return tokenAmountIn;\n    }\n\n    /**********************************************************************************************\n    // calcSingleOutGivenPoolIn                                                                  //\n    // tAo = tokenAmountOut            /      /                                             \\\\   //\n    // bO = tokenBalanceOut           /      // pS - (pAi * (1 - eF)) \\     /    1    \\      \\\\  //\n    // pAi = poolAmountIn            | bO - || ----------------------- | ^ | --------- | * b0 || //\n    // ps = poolSupply                \\      \\\\          pS           /     \\(wO / tW)/      //  //\n    // wI = tokenWeightIn      tAo =   \\      \\                                             //   //\n    // tW = totalWeight                    /     /      wO \\       \\                             //\n    // sF = swapFee                    *  | 1 - |  1 - ---- | * sF  |                            //\n    // eF = exitFee                        \\     \\      tW /       /                             //\n    **********************************************************************************************/\n    function calcSingleOutGivenPoolIn(\n        uint tokenBalanceOut,\n        uint tokenWeightOut,\n        uint poolSupply,\n        uint totalWeight,\n        uint poolAmountIn,\n        uint swapFee\n    )\n        public pure\n        returns (uint tokenAmountOut)\n    {\n        uint normalizedWeight = bdiv(tokenWeightOut, totalWeight);\n        // charge exit fee on the pool token side\n        // pAiAfterExitFee = pAi*(1-exitFee)\n        uint poolAmountInAfterExitFee = bmul(poolAmountIn, bsub(BONE, EXIT_FEE));\n        uint newPoolSupply = bsub(poolSupply, poolAmountInAfterExitFee);\n        uint poolRatio = bdiv(newPoolSupply, poolSupply);\n     \n        // newBalTo = poolRatio^(1/weightTo) * balTo;\n        uint tokenOutRatio = bpow(poolRatio, bdiv(BONE, normalizedWeight));\n        uint newTokenBalanceOut = bmul(tokenOutRatio, tokenBalanceOut);\n\n        uint tokenAmountOutBeforeSwapFee = bsub(tokenBalanceOut, newTokenBalanceOut);\n\n        // charge swap fee on the output token side \n        //uint tAo = tAoBeforeSwapFee * (1 - (1-weightTo) * swapFee)\n        uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee); \n        tokenAmountOut = bmul(tokenAmountOutBeforeSwapFee, bsub(BONE, zaz));\n        return tokenAmountOut;\n    }\n\n    /**********************************************************************************************\n    // calcPoolInGivenSingleOut                                                                  //\n    // pAi = poolAmountIn               // /               tAo             \\\\     / wO \\     \\   //\n    // bO = tokenBalanceOut            // | bO - -------------------------- |\\   | ---- |     \\  //\n    // tAo = tokenAmountOut      pS - ||   \\     1 - ((1 - (tO / tW)) * sF)/  | ^ \\ tW /  * pS | //\n    // ps = poolSupply                 \\\\ -----------------------------------/                /  //\n    // wO = tokenWeightOut  pAi =       \\\\               bO                 /                /   //\n    // tW = totalWeight           -------------------------------------------------------------  //\n    // sF = swapFee                                        ( 1 - eF )                            //\n    // eF = exitFee                                                                              //\n    **********************************************************************************************/\n    function calcPoolInGivenSingleOut(\n        uint tokenBalanceOut,\n        uint tokenWeightOut,\n        uint poolSupply,\n        uint totalWeight,\n        uint tokenAmountOut,\n        uint swapFee\n    )\n        public pure\n        returns (uint poolAmountIn)\n    {\n\n        // charge swap fee on the output token side \n        uint normalizedWeight = bdiv(tokenWeightOut, totalWeight);\n        //uint tAoBeforeSwapFee = tAo / (1 - (1-weightTo) * swapFee) ;\n        uint zoo = bsub(BONE, normalizedWeight);\n        uint zar = bmul(zoo, swapFee); \n        uint tokenAmountOutBeforeSwapFee = bdiv(tokenAmountOut, bsub(BONE, zar));\n\n        uint newTokenBalanceOut = bsub(tokenBalanceOut, tokenAmountOutBeforeSwapFee);\n        uint tokenOutRatio = bdiv(newTokenBalanceOut, tokenBalanceOut);\n\n        //uint newPoolSupply = (ratioTo ^ weightTo) * poolSupply;\n        uint poolRatio = bpow(tokenOutRatio, normalizedWeight);\n        uint newPoolSupply = bmul(poolRatio, poolSupply);\n        uint poolAmountInAfterExitFee = bsub(poolSupply, newPoolSupply);\n\n        // charge exit fee on the pool token side\n        // pAi = pAiAfterExitFee/(1-exitFee)\n        poolAmountIn = bdiv(poolAmountInAfterExitFee, bsub(BONE, EXIT_FEE));\n        return poolAmountIn;\n    }\n\n\n}\n"},"BNum.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BConst.sol\";\n\ncontract BNum is BConst {\n\n    function btoi(uint a)\n        internal pure \n        returns (uint)\n    {\n        return a / BONE;\n    }\n\n    function bfloor(uint a)\n        internal pure\n        returns (uint)\n    {\n        return btoi(a) * BONE;\n    }\n\n    function badd(uint a, uint b)\n        internal pure\n        returns (uint)\n    {\n        uint c = a + b;\n        require(c \u003e= a, \"ERR_ADD_OVERFLOW\");\n        return c;\n    }\n\n    function bsub(uint a, uint b)\n        internal pure\n        returns (uint)\n    {\n        (uint c, bool flag) = bsubSign(a, b);\n        require(!flag, \"ERR_SUB_UNDERFLOW\");\n        return c;\n    }\n\n    function bsubSign(uint a, uint b)\n        internal pure\n        returns (uint, bool)\n    {\n        if (a \u003e= b) {\n            return (a - b, false);\n        } else {\n            return (b - a, true);\n        }\n    }\n\n    function bmul(uint a, uint b)\n        internal pure\n        returns (uint)\n    {\n        uint c0 = a * b;\n        require(a == 0 || c0 / a == b, \"ERR_MUL_OVERFLOW\");\n        uint c1 = c0 + (BONE / 2);\n        require(c1 \u003e= c0, \"ERR_MUL_OVERFLOW\");\n        uint c2 = c1 / BONE;\n        return c2;\n    }\n\n    function bdiv(uint a, uint b)\n        internal pure\n        returns (uint)\n    {\n        require(b != 0, \"ERR_DIV_ZERO\");\n        uint c0 = a * BONE;\n        require(a == 0 || c0 / a == BONE, \"ERR_DIV_INTERNAL\"); // bmul overflow\n        uint c1 = c0 + (b / 2);\n        require(c1 \u003e= c0, \"ERR_DIV_INTERNAL\"); //  badd require\n        uint c2 = c1 / b;\n        return c2;\n    }\n\n    // DSMath.wpow\n    function bpowi(uint a, uint n)\n        internal pure\n        returns (uint)\n    {\n        uint z = n % 2 != 0 ? a : BONE;\n\n        for (n /= 2; n != 0; n /= 2) {\n            a = bmul(a, a);\n\n            if (n % 2 != 0) {\n                z = bmul(z, a);\n            }\n        }\n        return z;\n    }\n\n    // Compute b^(e.w) by splitting it into (b^e)*(b^0.w).\n    // Use `bpowi` for `b^e` and `bpowK` for k iterations\n    // of approximation of b^0.w\n    function bpow(uint base, uint exp)\n        internal pure\n        returns (uint)\n    {\n        require(base \u003e= MIN_BPOW_BASE, \"ERR_BPOW_BASE_TOO_LOW\");\n        require(base \u003c= MAX_BPOW_BASE, \"ERR_BPOW_BASE_TOO_HIGH\");\n\n        uint whole  = bfloor(exp);   \n        uint remain = bsub(exp, whole);\n\n        uint wholePow = bpowi(base, btoi(whole));\n\n        if (remain == 0) {\n            return wholePow;\n        }\n\n        uint partialResult = bpowApprox(base, remain, BPOW_PRECISION);\n        return bmul(wholePow, partialResult);\n    }\n\n    function bpowApprox(uint base, uint exp, uint precision)\n        internal pure\n        returns (uint)\n    {\n        // term 0:\n        uint a     = exp;\n        (uint x, bool xneg)  = bsubSign(base, BONE);\n        uint term = BONE;\n        uint sum   = term;\n        bool negative = false;\n\n\n        // term(k) = numer / denom \n        //         = (product(a - i - 1, i=1--\u003ek) * x^k) / (k!)\n        // each iteration, multiply previous term by (a-(k-1)) * x / k\n        // continue until term is less than precision\n        for (uint i = 1; term \u003e= precision; i++) {\n            uint bigK = i * BONE;\n            (uint c, bool cneg) = bsubSign(a, bsub(bigK, BONE));\n            term = bmul(term, bmul(c, x));\n            term = bdiv(term, bigK);\n            if (term == 0) break;\n\n            if (xneg) negative = !negative;\n            if (cneg) negative = !negative;\n            if (negative) {\n                sum = bsub(sum, term);\n            } else {\n                sum = badd(sum, term);\n            }\n        }\n\n        return sum;\n    }\n\n}\n"},"BPool.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BToken.sol\";\nimport \"./BMath.sol\";\n\ncontract BPool is BBronze, BToken, BMath {\n\n    struct Record {\n        bool bound;   // is token bound to pool\n        uint index;   // private\n        uint denorm;  // denormalized weight\n        uint balance;\n    }\n\n    event LOG_SWAP(\n        address indexed caller,\n        address indexed tokenIn,\n        address indexed tokenOut,\n        uint256         tokenAmountIn,\n        uint256         tokenAmountOut\n    );\n\n    event LOG_JOIN(\n        address indexed caller,\n        address indexed tokenIn,\n        uint256         tokenAmountIn\n    );\n\n    event LOG_EXIT(\n        address indexed caller,\n        address indexed tokenOut,\n        uint256         tokenAmountOut\n    );\n\n    event LOG_CALL(\n        bytes4  indexed sig,\n        address indexed caller,\n        bytes           data\n    ) anonymous;\n\n    modifier _logs_() {\n        emit LOG_CALL(msg.sig, msg.sender, msg.data);\n        _;\n    }\n\n    modifier _lock_() {\n        require(!_mutex, \"ERR_REENTRY\");\n        _mutex = true;\n        _;\n        _mutex = false;\n    }\n\n    modifier _viewlock_() {\n        require(!_mutex, \"ERR_REENTRY\");\n        _;\n    }\n\n    bool private _mutex;\n\n    address private _factory;    // BFactory address to push token exitFee to\n    address private _controller; // has CONTROL role\n    bool private _publicSwap; // true if PUBLIC can call SWAP functions\n\n    // `setSwapFee` and `finalize` require CONTROL\n    // `finalize` sets `PUBLIC can SWAP`, `PUBLIC can JOIN`\n    uint private _swapFee;\n    bool private _finalized;\n\n    address[] private _tokens;\n    mapping(address=\u003eRecord) private  _records;\n    uint private _totalWeight;\n\n    constructor() public {\n        _controller = msg.sender;\n        _factory = msg.sender;\n        _swapFee = MIN_FEE;\n        _publicSwap = false;\n        _finalized = false;\n    }\n\n    function isPublicSwap()\n        external view\n        returns (bool)\n    {\n        return _publicSwap;\n    }\n\n    function isFinalized()\n        external view\n        returns (bool)\n    {\n        return _finalized;\n    }\n\n    function isBound(address t)\n        external view\n        returns (bool)\n    {\n        return _records[t].bound;\n    }\n\n    function getNumTokens()\n        external view\n        returns (uint) \n    {\n        return _tokens.length;\n    }\n\n    function getCurrentTokens()\n        external view _viewlock_\n        returns (address[] memory tokens)\n    {\n        return _tokens;\n    }\n\n    function getFinalTokens()\n        external view\n        _viewlock_\n        returns (address[] memory tokens)\n    {\n        require(_finalized, \"ERR_NOT_FINALIZED\");\n        return _tokens;\n    }\n\n    function getDenormalizedWeight(address token)\n        external view\n        _viewlock_\n        returns (uint)\n    {\n\n        require(_records[token].bound, \"ERR_NOT_BOUND\");\n        return _records[token].denorm;\n    }\n\n    function getTotalDenormalizedWeight()\n        external view\n        _viewlock_\n        returns (uint)\n    {\n        return _totalWeight;\n    }\n\n    function getNormalizedWeight(address token)\n        external view\n        _viewlock_\n        returns (uint)\n    {\n\n        require(_records[token].bound, \"ERR_NOT_BOUND\");\n        uint denorm = _records[token].denorm;\n        return bdiv(denorm, _totalWeight);\n    }\n\n    function getBalance(address token)\n        external view\n        _viewlock_\n        returns (uint)\n    {\n\n        require(_records[token].bound, \"ERR_NOT_BOUND\");\n        return _records[token].balance;\n    }\n\n    function getSwapFee()\n        external view\n        _viewlock_\n        returns (uint)\n    {\n        return _swapFee;\n    }\n\n    function getController()\n        external view\n        _viewlock_\n        returns (address)\n    {\n        return _controller;\n    }\n\n    function setSwapFee(uint swapFee)\n        external\n        _logs_\n        _lock_\n    { \n        require(!_finalized, \"ERR_IS_FINALIZED\");\n        require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n        require(swapFee \u003e= MIN_FEE, \"ERR_MIN_FEE\");\n        require(swapFee \u003c= MAX_FEE, \"ERR_MAX_FEE\");\n        _swapFee = swapFee;\n    }\n\n    function setController(address manager)\n        external\n        _logs_\n        _lock_\n    {\n        require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n        _controller = manager;\n    }\n\n    function setPublicSwap(bool public_)\n        external\n        _logs_\n        _lock_\n    {\n        require(!_finalized, \"ERR_IS_FINALIZED\");\n        require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n        _publicSwap = public_;\n    }\n\n    function finalize()\n        external\n        _logs_\n        _lock_\n    {\n        require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n        require(!_finalized, \"ERR_IS_FINALIZED\");\n        require(_tokens.length \u003e= MIN_BOUND_TOKENS, \"ERR_MIN_TOKENS\");\n\n        _finalized = true;\n        _publicSwap = true;\n\n        _mintPoolShare(INIT_POOL_SUPPLY);\n        _pushPoolShare(msg.sender, INIT_POOL_SUPPLY);\n    }\n\n\n    function bind(address token, uint balance, uint denorm)\n        external\n        _logs_\n        // _lock_  Bind does not lock because it jumps to `rebind`, which does\n    {\n        require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n        require(!_records[token].bound, \"ERR_IS_BOUND\");\n        require(!_finalized, \"ERR_IS_FINALIZED\");\n\n        require(_tokens.length \u003c MAX_BOUND_TOKENS, \"ERR_MAX_TOKENS\");\n\n        _records[token] = Record({\n            bound: true,\n            index: _tokens.length,\n            denorm: 0,    // balance and denorm will be validated\n            balance: 0   // and set by `rebind`\n        });\n        _tokens.push(token);\n        rebind(token, balance, denorm);\n    }\n\n    function rebind(address token, uint balance, uint denorm)\n        public\n        _logs_\n        _lock_\n    {\n\n        require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n        require(_records[token].bound, \"ERR_NOT_BOUND\");\n        require(!_finalized, \"ERR_IS_FINALIZED\");\n\n        require(denorm \u003e= MIN_WEIGHT, \"ERR_MIN_WEIGHT\");\n        require(denorm \u003c= MAX_WEIGHT, \"ERR_MAX_WEIGHT\");\n        require(balance \u003e= MIN_BALANCE, \"ERR_MIN_BALANCE\");\n\n        // Adjust the denorm and totalWeight\n        uint oldWeight = _records[token].denorm;\n        if (denorm \u003e oldWeight) {\n            _totalWeight = badd(_totalWeight, bsub(denorm, oldWeight));\n            require(_totalWeight \u003c= MAX_TOTAL_WEIGHT, \"ERR_MAX_TOTAL_WEIGHT\");\n        } else if (denorm \u003c oldWeight) {\n            _totalWeight = bsub(_totalWeight, bsub(oldWeight, denorm));\n        }        \n        _records[token].denorm = denorm;\n\n        // Adjust the balance record and actual token balance\n        uint oldBalance = _records[token].balance;\n        _records[token].balance = balance;\n        if (balance \u003e oldBalance) {\n            _pullUnderlying(token, msg.sender, bsub(balance, oldBalance));\n        } else if (balance \u003c oldBalance) {\n            // In this case liquidity is being withdrawn, so charge EXIT_FEE\n            uint tokenBalanceWithdrawn = bsub(oldBalance, balance);\n            uint tokenExitFee = bmul(tokenBalanceWithdrawn, EXIT_FEE);\n            _pushUnderlying(token, msg.sender, bsub(tokenBalanceWithdrawn, tokenExitFee));\n            _pushUnderlying(token, _factory, tokenExitFee);\n        }\n    }\n\n    function unbind(address token)\n        external\n        _logs_\n        _lock_\n    {\n\n        require(msg.sender == _controller, \"ERR_NOT_CONTROLLER\");\n        require(_records[token].bound, \"ERR_NOT_BOUND\");\n        require(!_finalized, \"ERR_IS_FINALIZED\");\n\n        uint tokenBalance = _records[token].balance;\n        uint tokenExitFee = bmul(tokenBalance, EXIT_FEE);\n\n        _totalWeight = bsub(_totalWeight, _records[token].denorm);\n\n        // Swap the token-to-unbind with the last token,\n        // then delete the last token\n        uint index = _records[token].index;\n        uint last = _tokens.length - 1;\n        _tokens[index] = _tokens[last];\n        _records[_tokens[index]].index = index;\n        _tokens.pop();\n        _records[token] = Record({\n            bound: false,\n            index: 0,\n            denorm: 0,\n            balance: 0\n        });\n\n        _pushUnderlying(token, msg.sender, bsub(tokenBalance, tokenExitFee));\n        _pushUnderlying(token, _factory, tokenExitFee);\n    }\n\n    // Absorb any tokens that have been sent to this contract into the pool\n    function gulp(address token)\n        external\n        _logs_\n        _lock_\n    {\n        require(_records[token].bound, \"ERR_NOT_BOUND\");\n        _records[token].balance = IERC20(token).balanceOf(address(this));\n    }\n\n    function getSpotPrice(address tokenIn, address tokenOut)\n        external view\n        _viewlock_\n        returns (uint spotPrice)\n    {\n        require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n        require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n        Record storage inRecord = _records[tokenIn];\n        Record storage outRecord = _records[tokenOut];\n        return calcSpotPrice(inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, _swapFee);\n    }\n\n    function getSpotPriceSansFee(address tokenIn, address tokenOut)\n        external view\n        _viewlock_\n        returns (uint spotPrice)\n    {\n        require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n        require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n        Record storage inRecord = _records[tokenIn];\n        Record storage outRecord = _records[tokenOut];\n        return calcSpotPrice(inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, 0);\n    }\n\n    function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn)\n        external\n        _logs_\n        _lock_\n    {\n        require(_finalized, \"ERR_NOT_FINALIZED\");\n\n        uint poolTotal = totalSupply();\n        uint ratio = bdiv(poolAmountOut, poolTotal);\n        require(ratio != 0, \"ERR_MATH_APPROX\");\n\n        for (uint i = 0; i \u003c _tokens.length; i++) {\n            address t = _tokens[i];\n            uint bal = _records[t].balance;\n            uint tokenAmountIn = bmul(ratio, bal);\n            require(tokenAmountIn != 0, \"ERR_MATH_APPROX\");\n            require(tokenAmountIn \u003c= maxAmountsIn[i], \"ERR_LIMIT_IN\");\n            _records[t].balance = badd(_records[t].balance, tokenAmountIn);\n            emit LOG_JOIN(msg.sender, t, tokenAmountIn);\n            _pullUnderlying(t, msg.sender, tokenAmountIn);\n        }\n        _mintPoolShare(poolAmountOut);\n        _pushPoolShare(msg.sender, poolAmountOut);\n    }\n\n    function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut)\n        external\n        _logs_\n        _lock_\n    {\n        require(_finalized, \"ERR_NOT_FINALIZED\");\n\n        uint poolTotal = totalSupply();\n        uint exitFee = bmul(poolAmountIn, EXIT_FEE);\n        uint pAiAfterExitFee = bsub(poolAmountIn, exitFee);\n        uint ratio = bdiv(pAiAfterExitFee, poolTotal);\n        require(ratio != 0, \"ERR_MATH_APPROX\");\n\n        _pullPoolShare(msg.sender, poolAmountIn);\n        _pushPoolShare(_factory, exitFee);\n        _burnPoolShare(pAiAfterExitFee);\n\n        for (uint i = 0; i \u003c _tokens.length; i++) {\n            address t = _tokens[i];\n            uint bal = _records[t].balance;\n            uint tokenAmountOut = bmul(ratio, bal);\n            require(tokenAmountOut != 0, \"ERR_MATH_APPROX\");\n            require(tokenAmountOut \u003e= minAmountsOut[i], \"ERR_LIMIT_OUT\");\n            _records[t].balance = bsub(_records[t].balance, tokenAmountOut);\n            emit LOG_EXIT(msg.sender, t, tokenAmountOut);\n            _pushUnderlying(t, msg.sender, tokenAmountOut);\n        }\n\n    }\n\n\n    function swapExactAmountIn(\n        address tokenIn,\n        uint tokenAmountIn,\n        address tokenOut,\n        uint minAmountOut,\n        uint maxPrice\n    )\n        external\n        _logs_\n        _lock_\n        returns (uint tokenAmountOut, uint spotPriceAfter)\n    {\n\n        require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n        require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n        require(_publicSwap, \"ERR_SWAP_NOT_PUBLIC\");\n\n        Record storage inRecord = _records[address(tokenIn)];\n        Record storage outRecord = _records[address(tokenOut)];\n\n        require(tokenAmountIn \u003c= bmul(inRecord.balance, MAX_IN_RATIO), \"ERR_MAX_IN_RATIO\");\n\n        uint spotPriceBefore = calcSpotPrice(\n                                    inRecord.balance,\n                                    inRecord.denorm,\n                                    outRecord.balance,\n                                    outRecord.denorm,\n                                    _swapFee\n                                );\n        require(spotPriceBefore \u003c= maxPrice, \"ERR_BAD_LIMIT_PRICE\");\n\n        tokenAmountOut = calcOutGivenIn(\n                            inRecord.balance,\n                            inRecord.denorm,\n                            outRecord.balance,\n                            outRecord.denorm,\n                            tokenAmountIn,\n                            _swapFee\n                        );\n        require(tokenAmountOut \u003e= minAmountOut, \"ERR_LIMIT_OUT\");\n\n        inRecord.balance = badd(inRecord.balance, tokenAmountIn);\n        outRecord.balance = bsub(outRecord.balance, tokenAmountOut);\n\n        spotPriceAfter = calcSpotPrice(\n                                inRecord.balance,\n                                inRecord.denorm,\n                                outRecord.balance,\n                                outRecord.denorm,\n                                _swapFee\n                            );\n        require(spotPriceAfter \u003e= spotPriceBefore, \"ERR_MATH_APPROX\");     \n        require(spotPriceAfter \u003c= maxPrice, \"ERR_LIMIT_PRICE\");\n        require(spotPriceBefore \u003c= bdiv(tokenAmountIn, tokenAmountOut), \"ERR_MATH_APPROX\");\n\n        emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOut);\n\n        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);\n        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);\n\n        return (tokenAmountOut, spotPriceAfter);\n    }\n\n    function swapExactAmountOut(\n        address tokenIn,\n        uint maxAmountIn,\n        address tokenOut,\n        uint tokenAmountOut,\n        uint maxPrice\n    )\n        external\n        _logs_\n        _lock_ \n        returns (uint tokenAmountIn, uint spotPriceAfter)\n    {\n        require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n        require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n        require(_publicSwap, \"ERR_SWAP_NOT_PUBLIC\");\n\n        Record storage inRecord = _records[address(tokenIn)];\n        Record storage outRecord = _records[address(tokenOut)];\n\n        require(tokenAmountOut \u003c= bmul(outRecord.balance, MAX_OUT_RATIO), \"ERR_MAX_OUT_RATIO\");\n\n        uint spotPriceBefore = calcSpotPrice(\n                                    inRecord.balance,\n                                    inRecord.denorm,\n                                    outRecord.balance,\n                                    outRecord.denorm,\n                                    _swapFee\n                                );\n        require(spotPriceBefore \u003c= maxPrice, \"ERR_BAD_LIMIT_PRICE\");\n\n        tokenAmountIn = calcInGivenOut(\n                            inRecord.balance,\n                            inRecord.denorm,\n                            outRecord.balance,\n                            outRecord.denorm,\n                            tokenAmountOut,\n                            _swapFee\n                        );\n        require(tokenAmountIn \u003c= maxAmountIn, \"ERR_LIMIT_IN\");\n\n        inRecord.balance = badd(inRecord.balance, tokenAmountIn);\n        outRecord.balance = bsub(outRecord.balance, tokenAmountOut);\n\n        spotPriceAfter = calcSpotPrice(\n                                inRecord.balance,\n                                inRecord.denorm,\n                                outRecord.balance,\n                                outRecord.denorm,\n                                _swapFee\n                            );\n        require(spotPriceAfter \u003e= spotPriceBefore, \"ERR_MATH_APPROX\");\n        require(spotPriceAfter \u003c= maxPrice, \"ERR_LIMIT_PRICE\");\n        require(spotPriceBefore \u003c= bdiv(tokenAmountIn, tokenAmountOut), \"ERR_MATH_APPROX\");\n\n        emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOut);\n\n        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);\n        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);\n\n        return (tokenAmountIn, spotPriceAfter);\n    }\n\n\n    function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut)\n        external\n        _logs_\n        _lock_\n        returns (uint poolAmountOut)\n\n    {        \n        require(_finalized, \"ERR_NOT_FINALIZED\");\n        require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n        require(tokenAmountIn \u003c= bmul(_records[tokenIn].balance, MAX_IN_RATIO), \"ERR_MAX_IN_RATIO\");\n\n        Record storage inRecord = _records[tokenIn];\n\n        poolAmountOut = calcPoolOutGivenSingleIn(\n                            inRecord.balance,\n                            inRecord.denorm,\n                            _totalSupply,\n                            _totalWeight,\n                            tokenAmountIn,\n                            _swapFee\n                        );\n\n        require(poolAmountOut \u003e= minPoolAmountOut, \"ERR_LIMIT_OUT\");\n\n        inRecord.balance = badd(inRecord.balance, tokenAmountIn);\n\n        emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn);\n\n        _mintPoolShare(poolAmountOut);\n        _pushPoolShare(msg.sender, poolAmountOut);\n        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);\n\n        return poolAmountOut;\n    }\n\n    function joinswapPoolAmountOut(address tokenIn, uint poolAmountOut, uint maxAmountIn)\n        external\n        _logs_\n        _lock_\n        returns (uint tokenAmountIn)\n    {\n        require(_finalized, \"ERR_NOT_FINALIZED\");\n        require(_records[tokenIn].bound, \"ERR_NOT_BOUND\");\n\n        Record storage inRecord = _records[tokenIn];\n\n        tokenAmountIn = calcSingleInGivenPoolOut(\n                            inRecord.balance,\n                            inRecord.denorm,\n                            _totalSupply,\n                            _totalWeight,\n                            poolAmountOut,\n                            _swapFee\n                        );\n\n        require(tokenAmountIn != 0, \"ERR_MATH_APPROX\");\n        require(tokenAmountIn \u003c= maxAmountIn, \"ERR_LIMIT_IN\");\n        \n        require(tokenAmountIn \u003c= bmul(_records[tokenIn].balance, MAX_IN_RATIO), \"ERR_MAX_IN_RATIO\");\n\n        inRecord.balance = badd(inRecord.balance, tokenAmountIn);\n\n        emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn);\n\n        _mintPoolShare(poolAmountOut);\n        _pushPoolShare(msg.sender, poolAmountOut);\n        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);\n\n        return tokenAmountIn;\n    }\n\n    function exitswapPoolAmountIn(address tokenOut, uint poolAmountIn, uint minAmountOut)\n        external\n        _logs_\n        _lock_\n        returns (uint tokenAmountOut)\n    {\n        require(_finalized, \"ERR_NOT_FINALIZED\");\n        require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n\n        Record storage outRecord = _records[tokenOut];\n\n        tokenAmountOut = calcSingleOutGivenPoolIn(\n                            outRecord.balance,\n                            outRecord.denorm,\n                            _totalSupply,\n                            _totalWeight,\n                            poolAmountIn,\n                            _swapFee\n                        );\n\n        require(tokenAmountOut \u003e= minAmountOut, \"ERR_LIMIT_OUT\");\n        \n        require(tokenAmountOut \u003c= bmul(_records[tokenOut].balance, MAX_OUT_RATIO), \"ERR_MAX_OUT_RATIO\");\n\n        outRecord.balance = bsub(outRecord.balance, tokenAmountOut);\n\n        uint exitFee = bmul(poolAmountIn, EXIT_FEE);\n\n        emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut);\n\n        _pullPoolShare(msg.sender, poolAmountIn);\n        _burnPoolShare(bsub(poolAmountIn, exitFee));\n        _pushPoolShare(_factory, exitFee);\n        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);\n\n        return tokenAmountOut;\n    }\n\n    function exitswapExternAmountOut(address tokenOut, uint tokenAmountOut, uint maxPoolAmountIn)\n        external\n        _logs_\n        _lock_\n        returns (uint poolAmountIn)\n    {\n        require(_finalized, \"ERR_NOT_FINALIZED\");\n        require(_records[tokenOut].bound, \"ERR_NOT_BOUND\");\n        require(tokenAmountOut \u003c= bmul(_records[tokenOut].balance, MAX_OUT_RATIO), \"ERR_MAX_OUT_RATIO\");\n\n        Record storage outRecord = _records[tokenOut];\n\n        poolAmountIn = calcPoolInGivenSingleOut(\n                            outRecord.balance,\n                            outRecord.denorm,\n                            _totalSupply,\n                            _totalWeight,\n                            tokenAmountOut,\n                            _swapFee\n                        );\n\n        require(poolAmountIn != 0, \"ERR_MATH_APPROX\");\n        require(poolAmountIn \u003c= maxPoolAmountIn, \"ERR_LIMIT_IN\");\n\n        outRecord.balance = bsub(outRecord.balance, tokenAmountOut);\n\n        uint exitFee = bmul(poolAmountIn, EXIT_FEE);\n\n        emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut);\n\n        _pullPoolShare(msg.sender, poolAmountIn);\n        _burnPoolShare(bsub(poolAmountIn, exitFee));\n        _pushPoolShare(_factory, exitFee);\n        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);        \n\n        return poolAmountIn;\n    }\n\n\n    // ==\n    // \u0027Underlying\u0027 token-manipulation functions make external calls but are NOT locked\n    // You must `_lock_` or otherwise ensure reentry-safety\n\n    function _pullUnderlying(address erc20, address from, uint amount)\n        internal\n    {\n        bool xfer = IERC20(erc20).transferFrom(from, address(this), amount);\n        require(xfer, \"ERR_ERC20_FALSE\");\n    }\n\n    function _pushUnderlying(address erc20, address to, uint amount)\n        internal\n    {\n        bool xfer = IERC20(erc20).transfer(to, amount);\n        require(xfer, \"ERR_ERC20_FALSE\");\n    }\n\n    function _pullPoolShare(address from, uint amount)\n        internal\n    {\n        _pull(from, amount);\n    }\n\n    function _pushPoolShare(address to, uint amount)\n        internal\n    {\n        _push(to, amount);\n    }\n\n    function _mintPoolShare(uint amount)\n        internal\n    {\n        _mint(amount);\n    }\n\n    function _burnPoolShare(uint amount)\n        internal\n    {\n        _burn(amount);\n    }\n\n}\n"},"BToken.sol":{"content":"// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\npragma solidity 0.5.12;\n\nimport \"./BNum.sol\";\n\n// Highly opinionated token implementation\n\ninterface IERC20 {\n    event Approval(address indexed src, address indexed dst, uint amt);\n    event Transfer(address indexed src, address indexed dst, uint amt);\n\n    function totalSupply() external view returns (uint);\n    function balanceOf(address whom) external view returns (uint);\n    function allowance(address src, address dst) external view returns (uint);\n\n    function approve(address dst, uint amt) external returns (bool);\n    function transfer(address dst, uint amt) external returns (bool);\n    function transferFrom(\n        address src, address dst, uint amt\n    ) external returns (bool);\n}\n\ncontract BTokenBase is BNum {\n\n    mapping(address =\u003e uint)                   internal _balance;\n    mapping(address =\u003e mapping(address=\u003euint)) internal _allowance;\n    uint internal _totalSupply;\n\n    event Approval(address indexed src, address indexed dst, uint amt);\n    event Transfer(address indexed src, address indexed dst, uint amt);\n\n    function _mint(uint amt) internal {\n        _balance[address(this)] = badd(_balance[address(this)], amt);\n        _totalSupply = badd(_totalSupply, amt);\n        emit Transfer(address(0), address(this), amt);\n    }\n\n    function _burn(uint amt) internal {\n        require(_balance[address(this)] \u003e= amt, \"ERR_INSUFFICIENT_BAL\");\n        _balance[address(this)] = bsub(_balance[address(this)], amt);\n        _totalSupply = bsub(_totalSupply, amt);\n        emit Transfer(address(this), address(0), amt);\n    }\n\n    function _move(address src, address dst, uint amt) internal {\n        require(_balance[src] \u003e= amt, \"ERR_INSUFFICIENT_BAL\");\n        _balance[src] = bsub(_balance[src], amt);\n        _balance[dst] = badd(_balance[dst], amt);\n        emit Transfer(src, dst, amt);\n    }\n\n    function _push(address to, uint amt) internal {\n        _move(address(this), to, amt);\n    }\n\n    function _pull(address from, uint amt) internal {\n        _move(from, address(this), amt);\n    }\n}\n\ncontract BToken is BTokenBase, IERC20 {\n\n    string  private _name     = \"Balancer Pool Token\";\n    string  private _symbol   = \"BPT\";\n    uint8   private _decimals = 18;\n\n    function name() public view returns (string memory) {\n        return _name;\n    }\n\n    function symbol() public view returns (string memory) {\n        return _symbol;\n    }\n\n    function decimals() public view returns(uint8) {\n        return _decimals;\n    }\n\n    function allowance(address src, address dst) external view returns (uint) {\n        return _allowance[src][dst];\n    }\n\n    function balanceOf(address whom) external view returns (uint) {\n        return _balance[whom];\n    }\n\n    function totalSupply() public view returns (uint) {\n        return _totalSupply;\n    }\n\n    function approve(address dst, uint amt) external returns (bool) {\n        _allowance[msg.sender][dst] = amt;\n        emit Approval(msg.sender, dst, amt);\n        return true;\n    }\n\n    function increaseApproval(address dst, uint amt) external returns (bool) {\n        _allowance[msg.sender][dst] = badd(_allowance[msg.sender][dst], amt);\n        emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);\n        return true;\n    }\n\n    function decreaseApproval(address dst, uint amt) external returns (bool) {\n        uint oldValue = _allowance[msg.sender][dst];\n        if (amt \u003e oldValue) {\n            _allowance[msg.sender][dst] = 0;\n        } else {\n            _allowance[msg.sender][dst] = bsub(oldValue, amt);\n        }\n        emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);\n        return true;\n    }\n\n    function transfer(address dst, uint amt) external returns (bool) {\n        _move(msg.sender, dst, amt);\n        return true;\n    }\n\n    function transferFrom(address src, address dst, uint amt) external returns (bool) {\n        require(msg.sender == src || amt \u003c= _allowance[src][msg.sender], \"ERR_BTOKEN_BAD_CALLER\");\n        _move(src, dst, amt);\n        if (msg.sender != src \u0026\u0026 _allowance[src][msg.sender] != uint256(-1)) {\n            _allowance[src][msg.sender] = bsub(_allowance[src][msg.sender], amt);\n            emit Approval(msg.sender, dst, _allowance[src][msg.sender]);\n        }\n        return true;\n    }\n}\n"}}

        File 3 of 5: KyberReserve
        pragma solidity ^0.4.13;
        
        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);
        }
        
        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);
        }
        
        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);
        }
        
        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;
                    }
                }
            }
        }
        
        interface SanityRatesInterface {
            function getSanityRate(ERC20 src, ERC20 dest) public view returns(uint);
        }
        
        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
            }
        }
        
        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);
            }
        }
        
        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 4 of 5: ConversionRates
        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);
        }
        
        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);
        }
        
        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;
                    }
                }
            }
        }
        
        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);
            }
        }
        
        contract VolumeImbalanceRecorder is Withdrawable {
        
            uint constant internal SLIDING_WINDOW_SIZE = 5;
            uint constant internal POW_2_64 = 2 ** 64;
        
            struct TokenControlInfo {
                uint minimalRecordResolution; // can be roughly 1 cent
                uint maxPerBlockImbalance; // in twei resolution
                uint maxTotalImbalance; // max total imbalance (between rate updates)
                                    // before halting trade
            }
        
            mapping(address => TokenControlInfo) internal tokenControlInfo;
        
            struct TokenImbalanceData {
                int  lastBlockBuyUnitsImbalance;
                uint lastBlock;
        
                int  totalBuyUnitsImbalance;
                uint lastRateUpdateBlock;
            }
        
            mapping(address => mapping(uint=>uint)) public tokenImbalanceData;
        
            function VolumeImbalanceRecorder(address _admin) public {
                require(_admin != address(0));
                admin = _admin;
            }
        
            function setTokenControlInfo(
                ERC20 token,
                uint minimalRecordResolution,
                uint maxPerBlockImbalance,
                uint maxTotalImbalance
            )
                public
                onlyAdmin
            {
                tokenControlInfo[token] =
                    TokenControlInfo(
                        minimalRecordResolution,
                        maxPerBlockImbalance,
                        maxTotalImbalance
                    );
            }
        
            function getTokenControlInfo(ERC20 token) public view returns(uint, uint, uint) {
                return (tokenControlInfo[token].minimalRecordResolution,
                        tokenControlInfo[token].maxPerBlockImbalance,
                        tokenControlInfo[token].maxTotalImbalance);
            }
        
            function addImbalance(
                ERC20 token,
                int buyAmount,
                uint rateUpdateBlock,
                uint currentBlock
            )
                internal
            {
                uint currentBlockIndex = currentBlock % SLIDING_WINDOW_SIZE;
                int recordedBuyAmount = int(buyAmount / int(tokenControlInfo[token].minimalRecordResolution));
        
                int prevImbalance = 0;
        
                TokenImbalanceData memory currentBlockData =
                    decodeTokenImbalanceData(tokenImbalanceData[token][currentBlockIndex]);
        
                // first scenario - this is not the first tx in the current block
                if (currentBlockData.lastBlock == currentBlock) {
                    if (uint(currentBlockData.lastRateUpdateBlock) == rateUpdateBlock) {
                        // just increase imbalance
                        currentBlockData.lastBlockBuyUnitsImbalance += recordedBuyAmount;
                        currentBlockData.totalBuyUnitsImbalance += recordedBuyAmount;
                    } else {
                        // imbalance was changed in the middle of the block
                        prevImbalance = getImbalanceInRange(token, rateUpdateBlock, currentBlock);
                        currentBlockData.totalBuyUnitsImbalance = int(prevImbalance) + recordedBuyAmount;
                        currentBlockData.lastBlockBuyUnitsImbalance += recordedBuyAmount;
                        currentBlockData.lastRateUpdateBlock = uint(rateUpdateBlock);
                    }
                } else {
                    // first tx in the current block
                    int currentBlockImbalance;
                    (prevImbalance, currentBlockImbalance) = getImbalanceSinceRateUpdate(token, rateUpdateBlock, currentBlock);
        
                    currentBlockData.lastBlockBuyUnitsImbalance = recordedBuyAmount;
                    currentBlockData.lastBlock = uint(currentBlock);
                    currentBlockData.lastRateUpdateBlock = uint(rateUpdateBlock);
                    currentBlockData.totalBuyUnitsImbalance = int(prevImbalance) + recordedBuyAmount;
                }
        
                tokenImbalanceData[token][currentBlockIndex] = encodeTokenImbalanceData(currentBlockData);
            }
        
            function setGarbageToVolumeRecorder(ERC20 token) internal {
                for (uint i = 0; i < SLIDING_WINDOW_SIZE; i++) {
                    tokenImbalanceData[token][i] = 0x1;
                }
            }
        
            function getImbalanceInRange(ERC20 token, uint startBlock, uint endBlock) internal view returns(int buyImbalance) {
                // check the imbalance in the sliding window
                require(startBlock <= endBlock);
        
                buyImbalance = 0;
        
                for (uint windowInd = 0; windowInd < SLIDING_WINDOW_SIZE; windowInd++) {
                    TokenImbalanceData memory perBlockData = decodeTokenImbalanceData(tokenImbalanceData[token][windowInd]);
        
                    if (perBlockData.lastBlock <= endBlock && perBlockData.lastBlock >= startBlock) {
                        buyImbalance += int(perBlockData.lastBlockBuyUnitsImbalance);
                    }
                }
            }
        
            function getImbalanceSinceRateUpdate(ERC20 token, uint rateUpdateBlock, uint currentBlock)
                internal view
                returns(int buyImbalance, int currentBlockImbalance)
            {
                buyImbalance = 0;
                currentBlockImbalance = 0;
                uint latestBlock = 0;
                int imbalanceInRange = 0;
                uint startBlock = rateUpdateBlock;
                uint endBlock = currentBlock;
        
                for (uint windowInd = 0; windowInd < SLIDING_WINDOW_SIZE; windowInd++) {
                    TokenImbalanceData memory perBlockData = decodeTokenImbalanceData(tokenImbalanceData[token][windowInd]);
        
                    if (perBlockData.lastBlock <= endBlock && perBlockData.lastBlock >= startBlock) {
                        imbalanceInRange += perBlockData.lastBlockBuyUnitsImbalance;
                    }
        
                    if (perBlockData.lastRateUpdateBlock != rateUpdateBlock) continue;
                    if (perBlockData.lastBlock < latestBlock) continue;
        
                    latestBlock = perBlockData.lastBlock;
                    buyImbalance = perBlockData.totalBuyUnitsImbalance;
                    if (uint(perBlockData.lastBlock) == currentBlock) {
                        currentBlockImbalance = perBlockData.lastBlockBuyUnitsImbalance;
                    }
                }
        
                if (buyImbalance == 0) {
                    buyImbalance = imbalanceInRange;
                }
            }
        
            function getImbalance(ERC20 token, uint rateUpdateBlock, uint currentBlock)
                internal view
                returns(int totalImbalance, int currentBlockImbalance)
            {
        
                int resolution = int(tokenControlInfo[token].minimalRecordResolution);
        
                (totalImbalance, currentBlockImbalance) =
                    getImbalanceSinceRateUpdate(
                        token,
                        rateUpdateBlock,
                        currentBlock);
        
                totalImbalance *= resolution;
                currentBlockImbalance *= resolution;
            }
        
            function getMaxPerBlockImbalance(ERC20 token) internal view returns(uint) {
                return tokenControlInfo[token].maxPerBlockImbalance;
            }
        
            function getMaxTotalImbalance(ERC20 token) internal view returns(uint) {
                return tokenControlInfo[token].maxTotalImbalance;
            }
        
            function encodeTokenImbalanceData(TokenImbalanceData data) internal pure returns(uint) {
                // check for overflows
                require(data.lastBlockBuyUnitsImbalance < int(POW_2_64 / 2));
                require(data.lastBlockBuyUnitsImbalance > int(-1 * int(POW_2_64) / 2));
                require(data.lastBlock < POW_2_64);
                require(data.totalBuyUnitsImbalance < int(POW_2_64 / 2));
                require(data.totalBuyUnitsImbalance > int(-1 * int(POW_2_64) / 2));
                require(data.lastRateUpdateBlock < POW_2_64);
        
                // do encoding
                uint result = uint(data.lastBlockBuyUnitsImbalance) & (POW_2_64 - 1);
                result |= data.lastBlock * POW_2_64;
                result |= (uint(data.totalBuyUnitsImbalance) & (POW_2_64 - 1)) * POW_2_64 * POW_2_64;
                result |= data.lastRateUpdateBlock * POW_2_64 * POW_2_64 * POW_2_64;
        
                return result;
            }
        
            function decodeTokenImbalanceData(uint input) internal pure returns(TokenImbalanceData) {
                TokenImbalanceData memory data;
        
                data.lastBlockBuyUnitsImbalance = int(int64(input & (POW_2_64 - 1)));
                data.lastBlock = uint(uint64((input / POW_2_64) & (POW_2_64 - 1)));
                data.totalBuyUnitsImbalance = int(int64((input / (POW_2_64 * POW_2_64)) & (POW_2_64 - 1)));
                data.lastRateUpdateBlock = uint(uint64((input / (POW_2_64 * POW_2_64 * POW_2_64))));
        
                return data;
            }
        }
        
        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
            }
        }
        
        contract ConversionRates is ConversionRatesInterface, VolumeImbalanceRecorder, Utils {
        
            // bps - basic rate steps. one step is 1 / 10000 of the rate.
            struct StepFunction {
                int[] x; // quantity for each step. Quantity of each step includes previous steps.
                int[] y; // rate change per quantity step  in bps.
            }
        
            struct TokenData {
                bool listed;  // was added to reserve
                bool enabled; // whether trade is enabled
        
                // position in the compact data
                uint compactDataArrayIndex;
                uint compactDataFieldIndex;
        
                // rate data. base and changes according to quantity and reserve balance.
                // generally speaking. Sell rate is 1 / buy rate i.e. the buy in the other direction.
                uint baseBuyRate;  // in PRECISION units. see KyberConstants
                uint baseSellRate; // PRECISION units. without (sell / buy) spread it is 1 / baseBuyRate
                StepFunction buyRateQtyStepFunction; // in bps. higher quantity - bigger the rate.
                StepFunction sellRateQtyStepFunction;// in bps. higher the qua
                StepFunction buyRateImbalanceStepFunction; // in BPS. higher reserve imbalance - bigger the rate.
                StepFunction sellRateImbalanceStepFunction;
            }
        
            /*
            this is the data for tokenRatesCompactData
            but solidity compiler optimizer is sub-optimal, and cannot write this structure in a single storage write
            so we represent it as bytes32 and do the byte tricks ourselves.
            struct TokenRatesCompactData {
                bytes14 buy;  // change buy rate of token from baseBuyRate in 10 bps
                bytes14 sell; // change sell rate of token from baseSellRate in 10 bps
        
                uint32 blockNumber;
            } */
            uint public validRateDurationInBlocks = 10; // rates are valid for this amount of blocks
            ERC20[] internal listedTokens;
            mapping(address=>TokenData) internal tokenData;
            bytes32[] internal tokenRatesCompactData;
            uint public numTokensInCurrentCompactData = 0;
            address public reserveContract;
            uint constant internal NUM_TOKENS_IN_COMPACT_DATA = 14;
            uint constant internal BYTES_14_OFFSET = (2 ** (8 * NUM_TOKENS_IN_COMPACT_DATA));
            uint constant internal MAX_STEPS_IN_FUNCTION = 10;
            int  constant internal MAX_BPS_ADJUSTMENT = 10 ** 11; // 1B %
            int  constant internal MIN_BPS_ADJUSTMENT = -100 * 100; // cannot go down by more than 100%
        
            function ConversionRates(address _admin) public VolumeImbalanceRecorder(_admin)
                { } // solhint-disable-line no-empty-blocks
        
            function addToken(ERC20 token) public onlyAdmin {
        
                require(!tokenData[token].listed);
                tokenData[token].listed = true;
                listedTokens.push(token);
        
                if (numTokensInCurrentCompactData == 0) {
                    tokenRatesCompactData.length++; // add new structure
                }
        
                tokenData[token].compactDataArrayIndex = tokenRatesCompactData.length - 1;
                tokenData[token].compactDataFieldIndex = numTokensInCurrentCompactData;
        
                numTokensInCurrentCompactData = (numTokensInCurrentCompactData + 1) % NUM_TOKENS_IN_COMPACT_DATA;
        
                setGarbageToVolumeRecorder(token);
        
                setDecimals(token);
            }
        
            function setCompactData(bytes14[] buy, bytes14[] sell, uint blockNumber, uint[] indices) public onlyOperator {
        
                require(buy.length == sell.length);
                require(indices.length == buy.length);
                require(blockNumber <= 0xFFFFFFFF);
        
                uint bytes14Offset = BYTES_14_OFFSET;
        
                for (uint i = 0; i < indices.length; i++) {
                    require(indices[i] < tokenRatesCompactData.length);
                    uint data = uint(buy[i]) | uint(sell[i]) * bytes14Offset | (blockNumber * (bytes14Offset * bytes14Offset));
                    tokenRatesCompactData[indices[i]] = bytes32(data);
                }
            }
        
            function setBaseRate(
                ERC20[] tokens,
                uint[] baseBuy,
                uint[] baseSell,
                bytes14[] buy,
                bytes14[] sell,
                uint blockNumber,
                uint[] indices
            )
                public
                onlyOperator
            {
                require(tokens.length == baseBuy.length);
                require(tokens.length == baseSell.length);
                require(sell.length == buy.length);
                require(sell.length == indices.length);
        
                for (uint ind = 0; ind < tokens.length; ind++) {
                    require(tokenData[tokens[ind]].listed);
                    tokenData[tokens[ind]].baseBuyRate = baseBuy[ind];
                    tokenData[tokens[ind]].baseSellRate = baseSell[ind];
                }
        
                setCompactData(buy, sell, blockNumber, indices);
            }
        
            function setQtyStepFunction(
                ERC20 token,
                int[] xBuy,
                int[] yBuy,
                int[] xSell,
                int[] ySell
            )
                public
                onlyOperator
            {
                require(xBuy.length == yBuy.length);
                require(xSell.length == ySell.length);
                require(xBuy.length <= MAX_STEPS_IN_FUNCTION);
                require(xSell.length <= MAX_STEPS_IN_FUNCTION);
                require(tokenData[token].listed);
        
                tokenData[token].buyRateQtyStepFunction = StepFunction(xBuy, yBuy);
                tokenData[token].sellRateQtyStepFunction = StepFunction(xSell, ySell);
            }
        
            function setImbalanceStepFunction(
                ERC20 token,
                int[] xBuy,
                int[] yBuy,
                int[] xSell,
                int[] ySell
            )
                public
                onlyOperator
            {
                require(xBuy.length == yBuy.length);
                require(xSell.length == ySell.length);
                require(xBuy.length <= MAX_STEPS_IN_FUNCTION);
                require(xSell.length <= MAX_STEPS_IN_FUNCTION);
                require(tokenData[token].listed);
        
                tokenData[token].buyRateImbalanceStepFunction = StepFunction(xBuy, yBuy);
                tokenData[token].sellRateImbalanceStepFunction = StepFunction(xSell, ySell);
            }
        
            function setValidRateDurationInBlocks(uint duration) public onlyAdmin {
                validRateDurationInBlocks = duration;
            }
        
            function enableTokenTrade(ERC20 token) public onlyAdmin {
                require(tokenData[token].listed);
                require(tokenControlInfo[token].minimalRecordResolution != 0);
                tokenData[token].enabled = true;
            }
        
            function disableTokenTrade(ERC20 token) public onlyAlerter {
                require(tokenData[token].listed);
                tokenData[token].enabled = false;
            }
        
            function setReserveAddress(address reserve) public onlyAdmin {
                reserveContract = reserve;
            }
        
            function recordImbalance(
                ERC20 token,
                int buyAmount,
                uint rateUpdateBlock,
                uint currentBlock
            )
                public
            {
                require(msg.sender == reserveContract);
        
                if (rateUpdateBlock == 0) rateUpdateBlock = getRateUpdateBlock(token);
        
                return addImbalance(token, buyAmount, rateUpdateBlock, currentBlock);
            }
        
            /* solhint-disable function-max-lines */
            function getRate(ERC20 token, uint currentBlockNumber, bool buy, uint qty) public view returns(uint) {
                // check if trade is enabled
                if (!tokenData[token].enabled) return 0;
                if (tokenControlInfo[token].minimalRecordResolution == 0) return 0; // token control info not set
        
                // get rate update block
                bytes32 compactData = tokenRatesCompactData[tokenData[token].compactDataArrayIndex];
        
                uint updateRateBlock = getLast4Bytes(compactData);
                if (currentBlockNumber >= updateRateBlock + validRateDurationInBlocks) return 0; // rate is expired
                // check imbalance
                int totalImbalance;
                int blockImbalance;
                (totalImbalance, blockImbalance) = getImbalance(token, updateRateBlock, currentBlockNumber);
        
                // calculate actual rate
                int imbalanceQty;
                int extraBps;
                int8 rateUpdate;
                uint rate;
        
                if (buy) {
                    // start with base rate
                    rate = tokenData[token].baseBuyRate;
        
                    // add rate update
                    rateUpdate = getRateByteFromCompactData(compactData, token, true);
                    extraBps = int(rateUpdate) * 10;
                    rate = addBps(rate, extraBps);
        
                    // compute token qty
                    qty = getTokenQty(token, rate, qty);
                    imbalanceQty = int(qty);
                    totalImbalance += imbalanceQty;
        
                    // add qty overhead
                    extraBps = executeStepFunction(tokenData[token].buyRateQtyStepFunction, int(qty));
                    rate = addBps(rate, extraBps);
        
                    // add imbalance overhead
                    extraBps = executeStepFunction(tokenData[token].buyRateImbalanceStepFunction, totalImbalance);
                    rate = addBps(rate, extraBps);
                } else {
                    // start with base rate
                    rate = tokenData[token].baseSellRate;
        
                    // add rate update
                    rateUpdate = getRateByteFromCompactData(compactData, token, false);
                    extraBps = int(rateUpdate) * 10;
                    rate = addBps(rate, extraBps);
        
                    // compute token qty
                    imbalanceQty = -1 * int(qty);
                    totalImbalance += imbalanceQty;
        
                    // add qty overhead
                    extraBps = executeStepFunction(tokenData[token].sellRateQtyStepFunction, int(qty));
                    rate = addBps(rate, extraBps);
        
                    // add imbalance overhead
                    extraBps = executeStepFunction(tokenData[token].sellRateImbalanceStepFunction, totalImbalance);
                    rate = addBps(rate, extraBps);
                }
        
                if (abs(totalImbalance) >= getMaxTotalImbalance(token)) return 0;
                if (abs(blockImbalance + imbalanceQty) >= getMaxPerBlockImbalance(token)) return 0;
        
                return rate;
            }
            /* solhint-enable function-max-lines */
        
            function getBasicRate(ERC20 token, bool buy) public view returns(uint) {
                if (buy)
                    return tokenData[token].baseBuyRate;
                else
                    return tokenData[token].baseSellRate;
            }
        
            function getCompactData(ERC20 token) public view returns(uint, uint, byte, byte) {
                require(tokenData[token].listed);
        
                uint arrayIndex = tokenData[token].compactDataArrayIndex;
                uint fieldOffset = tokenData[token].compactDataFieldIndex;
        
                return (
                    arrayIndex,
                    fieldOffset,
                    byte(getRateByteFromCompactData(tokenRatesCompactData[arrayIndex], token, true)),
                    byte(getRateByteFromCompactData(tokenRatesCompactData[arrayIndex], token, false))
                );
            }
        
            function getTokenBasicData(ERC20 token) public view returns(bool, bool) {
                return (tokenData[token].listed, tokenData[token].enabled);
            }
        
            /* solhint-disable code-complexity */
            function getStepFunctionData(ERC20 token, uint command, uint param) public view returns(int) {
                if (command == 0) return int(tokenData[token].buyRateQtyStepFunction.x.length);
                if (command == 1) return tokenData[token].buyRateQtyStepFunction.x[param];
                if (command == 2) return int(tokenData[token].buyRateQtyStepFunction.y.length);
                if (command == 3) return tokenData[token].buyRateQtyStepFunction.y[param];
        
                if (command == 4) return int(tokenData[token].sellRateQtyStepFunction.x.length);
                if (command == 5) return tokenData[token].sellRateQtyStepFunction.x[param];
                if (command == 6) return int(tokenData[token].sellRateQtyStepFunction.y.length);
                if (command == 7) return tokenData[token].sellRateQtyStepFunction.y[param];
        
                if (command == 8) return int(tokenData[token].buyRateImbalanceStepFunction.x.length);
                if (command == 9) return tokenData[token].buyRateImbalanceStepFunction.x[param];
                if (command == 10) return int(tokenData[token].buyRateImbalanceStepFunction.y.length);
                if (command == 11) return tokenData[token].buyRateImbalanceStepFunction.y[param];
        
                if (command == 12) return int(tokenData[token].sellRateImbalanceStepFunction.x.length);
                if (command == 13) return tokenData[token].sellRateImbalanceStepFunction.x[param];
                if (command == 14) return int(tokenData[token].sellRateImbalanceStepFunction.y.length);
                if (command == 15) return tokenData[token].sellRateImbalanceStepFunction.y[param];
        
                revert();
            }
            /* solhint-enable code-complexity */
        
            function getRateUpdateBlock(ERC20 token) public view returns(uint) {
                bytes32 compactData = tokenRatesCompactData[tokenData[token].compactDataArrayIndex];
                return getLast4Bytes(compactData);
            }
        
            function getListedTokens() public view returns(ERC20[]) {
                return listedTokens;
            }
        
            function getTokenQty(ERC20 token, uint ethQty, uint rate) internal view returns(uint) {
                uint dstDecimals = getDecimals(token);
                uint srcDecimals = ETH_DECIMALS;
        
                return calcDstQty(ethQty, srcDecimals, dstDecimals, rate);
            }
        
            function getLast4Bytes(bytes32 b) internal pure returns(uint) {
                // cannot trust compiler with not turning bit operations into EXP opcode
                return uint(b) / (BYTES_14_OFFSET * BYTES_14_OFFSET);
            }
        
            function getRateByteFromCompactData(bytes32 data, ERC20 token, bool buy) internal view returns(int8) {
                uint fieldOffset = tokenData[token].compactDataFieldIndex;
                uint byteOffset;
                if (buy)
                    byteOffset = 32 - NUM_TOKENS_IN_COMPACT_DATA + fieldOffset;
                else
                    byteOffset = 4 + fieldOffset;
        
                return int8(data[byteOffset]);
            }
        
            function executeStepFunction(StepFunction f, int x) internal pure returns(int) {
                uint len = f.y.length;
                for (uint ind = 0; ind < len; ind++) {
                    if (x <= f.x[ind]) return f.y[ind];
                }
        
                return f.y[len-1];
            }
        
            function addBps(uint rate, int bps) internal pure returns(uint) {
                require(rate <= MAX_RATE);
                require(bps >= MIN_BPS_ADJUSTMENT);
                require(bps <= MAX_BPS_ADJUSTMENT);
        
                uint maxBps = 100 * 100;
                return (rate * uint(int(maxBps) + bps)) / maxBps;
            }
        
            function abs(int x) internal pure returns(uint) {
                if (x < 0)
                    return uint(-1 * x);
                else
                    return uint(x);
            }
        }

        File 5 of 5: WBTC
        pragma solidity 0.4.24;
        
        // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
        
        /**
         * @title ERC20Basic
         * @dev Simpler version of ERC20 interface
         * See https://github.com/ethereum/EIPs/issues/179
         */
        contract ERC20Basic {
          function totalSupply() public view returns (uint256);
          function balanceOf(address _who) public view returns (uint256);
          function transfer(address _to, uint256 _value) public returns (bool);
          event Transfer(address indexed from, address indexed to, uint256 value);
        }
        
        // File: openzeppelin-solidity/contracts/math/SafeMath.sol
        
        /**
         * @title SafeMath
         * @dev Math operations with safety checks that throw on error
         */
        library SafeMath {
        
          /**
          * @dev Multiplies two numbers, throws on overflow.
          */
          function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
            // Gas optimization: this is cheaper than asserting '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;
            }
        
            c = _a * _b;
            assert(c / _a == _b);
            return c;
          }
        
          /**
          * @dev Integer division of two numbers, truncating the quotient.
          */
          function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
            // assert(_b > 0); // Solidity automatically throws when dividing by 0
            // uint256 c = _a / _b;
            // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
            return _a / _b;
          }
        
          /**
          * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
          */
          function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
            assert(_b <= _a);
            return _a - _b;
          }
        
          /**
          * @dev Adds two numbers, throws on overflow.
          */
          function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
            c = _a + _b;
            assert(c >= _a);
            return c;
          }
        }
        
        // File: openzeppelin-solidity/contracts/token/ERC20/BasicToken.sol
        
        /**
         * @title Basic token
         * @dev Basic version of StandardToken, with no allowances.
         */
        contract BasicToken is ERC20Basic {
          using SafeMath for uint256;
        
          mapping(address => uint256) internal balances;
        
          uint256 internal totalSupply_;
        
          /**
          * @dev Total number of tokens in existence
          */
          function totalSupply() public view returns (uint256) {
            return totalSupply_;
          }
        
          /**
          * @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) {
            require(_value <= balances[msg.sender]);
            require(_to != address(0));
        
            balances[msg.sender] = balances[msg.sender].sub(_value);
            balances[_to] = balances[_to].add(_value);
            emit Transfer(msg.sender, _to, _value);
            return true;
          }
        
          /**
          * @dev Gets the balance of the specified address.
          * @param _owner The address to query the 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];
          }
        
        }
        
        // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
        
        /**
         * @title ERC20 interface
         * @dev see https://github.com/ethereum/EIPs/issues/20
         */
        contract ERC20 is ERC20Basic {
          function allowance(address _owner, address _spender)
            public view returns (uint256);
        
          function transferFrom(address _from, address _to, uint256 _value)
            public returns (bool);
        
          function approve(address _spender, uint256 _value) public returns (bool);
          event Approval(
            address indexed owner,
            address indexed spender,
            uint256 value
          );
        }
        
        // File: openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol
        
        /**
         * @title Standard ERC20 token
         *
         * @dev Implementation of the basic standard token.
         * https://github.com/ethereum/EIPs/issues/20
         * Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
         */
        contract StandardToken is ERC20, BasicToken {
        
          mapping (address => mapping (address => uint256)) internal allowed;
        
        
          /**
           * @dev Transfer tokens from one address to another
           * @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)
          {
            require(_value <= balances[_from]);
            require(_value <= allowed[_from][msg.sender]);
            require(_to != address(0));
        
            balances[_from] = balances[_from].sub(_value);
            balances[_to] = balances[_to].add(_value);
            allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
            emit Transfer(_from, _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) {
            allowed[msg.sender][_spender] = _value;
            emit Approval(msg.sender, _spender, _value);
            return true;
          }
        
          /**
           * @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 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
           * @param _spender The address which will spend the funds.
           * @param _addedValue The amount of tokens to increase the allowance by.
           */
          function increaseApproval(
            address _spender,
            uint256 _addedValue
          )
            public
            returns (bool)
          {
            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
           * @param _spender The address which will spend the funds.
           * @param _subtractedValue The amount of tokens to decrease the allowance by.
           */
          function decreaseApproval(
            address _spender,
            uint256 _subtractedValue
          )
            public
            returns (bool)
          {
            uint256 oldValue = allowed[msg.sender][_spender];
            if (_subtractedValue >= oldValue) {
              allowed[msg.sender][_spender] = 0;
            } else {
              allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
            }
            emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
            return true;
          }
        
        }
        
        // File: openzeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol
        
        /**
         * @title DetailedERC20 token
         * @dev The decimals are only for visualization purposes.
         * All the operations are done using the smallest and indivisible token unit,
         * just as on Ethereum all the operations are done in wei.
         */
        contract DetailedERC20 is ERC20 {
          string public name;
          string public symbol;
          uint8 public decimals;
        
          constructor(string _name, string _symbol, uint8 _decimals) public {
            name = _name;
            symbol = _symbol;
            decimals = _decimals;
          }
        }
        
        // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
        
        /**
         * @title Ownable
         * @dev The Ownable contract has an owner address, and provides basic authorization control
         * functions, this simplifies the implementation of "user permissions".
         */
        contract Ownable {
          address public owner;
        
        
          event OwnershipRenounced(address indexed previousOwner);
          event OwnershipTransferred(
            address indexed previousOwner,
            address indexed newOwner
          );
        
        
          /**
           * @dev The Ownable constructor sets the original `owner` of the contract to the sender
           * account.
           */
          constructor() public {
            owner = msg.sender;
          }
        
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
            require(msg.sender == owner);
            _;
          }
        
          /**
           * @dev Allows the current owner to relinquish control of the contract.
           * @notice Renouncing to ownership will leave the contract without an owner.
           * It will not be possible to call the functions with the `onlyOwner`
           * modifier anymore.
           */
          function renounceOwnership() public onlyOwner {
            emit OwnershipRenounced(owner);
            owner = address(0);
          }
        
          /**
           * @dev Allows the current owner to transfer control of the contract to a newOwner.
           * @param _newOwner The address to transfer ownership to.
           */
          function transferOwnership(address _newOwner) public onlyOwner {
            _transferOwnership(_newOwner);
          }
        
          /**
           * @dev Transfers control of the contract to a newOwner.
           * @param _newOwner The address to transfer ownership to.
           */
          function _transferOwnership(address _newOwner) internal {
            require(_newOwner != address(0));
            emit OwnershipTransferred(owner, _newOwner);
            owner = _newOwner;
          }
        }
        
        // File: openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol
        
        /**
         * @title Mintable token
         * @dev Simple ERC20 Token example, with mintable token creation
         * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
         */
        contract MintableToken is StandardToken, Ownable {
          event Mint(address indexed to, uint256 amount);
          event MintFinished();
        
          bool public mintingFinished = false;
        
        
          modifier canMint() {
            require(!mintingFinished);
            _;
          }
        
          modifier hasMintPermission() {
            require(msg.sender == owner);
            _;
          }
        
          /**
           * @dev Function to mint tokens
           * @param _to The address that will receive the minted tokens.
           * @param _amount The amount of tokens to mint.
           * @return A boolean that indicates if the operation was successful.
           */
          function mint(
            address _to,
            uint256 _amount
          )
            public
            hasMintPermission
            canMint
            returns (bool)
          {
            totalSupply_ = totalSupply_.add(_amount);
            balances[_to] = balances[_to].add(_amount);
            emit Mint(_to, _amount);
            emit Transfer(address(0), _to, _amount);
            return true;
          }
        
          /**
           * @dev Function to stop minting new tokens.
           * @return True if the operation was successful.
           */
          function finishMinting() public onlyOwner canMint returns (bool) {
            mintingFinished = true;
            emit MintFinished();
            return true;
          }
        }
        
        // File: openzeppelin-solidity/contracts/token/ERC20/BurnableToken.sol
        
        /**
         * @title Burnable Token
         * @dev Token that can be irreversibly burned (destroyed).
         */
        contract BurnableToken is BasicToken {
        
          event Burn(address indexed burner, uint256 value);
        
          /**
           * @dev Burns a specific amount of tokens.
           * @param _value The amount of token to be burned.
           */
          function burn(uint256 _value) public {
            _burn(msg.sender, _value);
          }
        
          function _burn(address _who, uint256 _value) internal {
            require(_value <= balances[_who]);
            // no need to require value <= totalSupply, since that would imply the
            // sender's balance is greater than the totalSupply, which *should* be an assertion failure
        
            balances[_who] = balances[_who].sub(_value);
            totalSupply_ = totalSupply_.sub(_value);
            emit Burn(_who, _value);
            emit Transfer(_who, address(0), _value);
          }
        }
        
        // File: openzeppelin-solidity/contracts/lifecycle/Pausable.sol
        
        /**
         * @title Pausable
         * @dev Base contract which allows children to implement an emergency stop mechanism.
         */
        contract Pausable is Ownable {
          event Pause();
          event Unpause();
        
          bool public paused = false;
        
        
          /**
           * @dev Modifier to make a function callable only when the contract is not paused.
           */
          modifier whenNotPaused() {
            require(!paused);
            _;
          }
        
          /**
           * @dev Modifier to make a function callable only when the contract is paused.
           */
          modifier whenPaused() {
            require(paused);
            _;
          }
        
          /**
           * @dev called by the owner to pause, triggers stopped state
           */
          function pause() public onlyOwner whenNotPaused {
            paused = true;
            emit Pause();
          }
        
          /**
           * @dev called by the owner to unpause, returns to normal state
           */
          function unpause() public onlyOwner whenPaused {
            paused = false;
            emit Unpause();
          }
        }
        
        // File: openzeppelin-solidity/contracts/token/ERC20/PausableToken.sol
        
        /**
         * @title Pausable token
         * @dev StandardToken modified with pausable transfers.
         **/
        contract PausableToken is StandardToken, Pausable {
        
          function transfer(
            address _to,
            uint256 _value
          )
            public
            whenNotPaused
            returns (bool)
          {
            return super.transfer(_to, _value);
          }
        
          function transferFrom(
            address _from,
            address _to,
            uint256 _value
          )
            public
            whenNotPaused
            returns (bool)
          {
            return super.transferFrom(_from, _to, _value);
          }
        
          function approve(
            address _spender,
            uint256 _value
          )
            public
            whenNotPaused
            returns (bool)
          {
            return super.approve(_spender, _value);
          }
        
          function increaseApproval(
            address _spender,
            uint _addedValue
          )
            public
            whenNotPaused
            returns (bool success)
          {
            return super.increaseApproval(_spender, _addedValue);
          }
        
          function decreaseApproval(
            address _spender,
            uint _subtractedValue
          )
            public
            whenNotPaused
            returns (bool success)
          {
            return super.decreaseApproval(_spender, _subtractedValue);
          }
        }
        
        // File: openzeppelin-solidity/contracts/ownership/Claimable.sol
        
        /**
         * @title Claimable
         * @dev Extension for the Ownable contract, where the ownership needs to be claimed.
         * This allows the new owner to accept the transfer.
         */
        contract Claimable is Ownable {
          address public pendingOwner;
        
          /**
           * @dev Modifier throws if called by any account other than the pendingOwner.
           */
          modifier onlyPendingOwner() {
            require(msg.sender == pendingOwner);
            _;
          }
        
          /**
           * @dev Allows the current owner to set the pendingOwner address.
           * @param newOwner The address to transfer ownership to.
           */
          function transferOwnership(address newOwner) public onlyOwner {
            pendingOwner = newOwner;
          }
        
          /**
           * @dev Allows the pendingOwner address to finalize the transfer.
           */
          function claimOwnership() public onlyPendingOwner {
            emit OwnershipTransferred(owner, pendingOwner);
            owner = pendingOwner;
            pendingOwner = address(0);
          }
        }
        
        // File: openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol
        
        /**
         * @title SafeERC20
         * @dev Wrappers around ERC20 operations that throw on failure.
         * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
         * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
         */
        library SafeERC20 {
          function safeTransfer(
            ERC20Basic _token,
            address _to,
            uint256 _value
          )
            internal
          {
            require(_token.transfer(_to, _value));
          }
        
          function safeTransferFrom(
            ERC20 _token,
            address _from,
            address _to,
            uint256 _value
          )
            internal
          {
            require(_token.transferFrom(_from, _to, _value));
          }
        
          function safeApprove(
            ERC20 _token,
            address _spender,
            uint256 _value
          )
            internal
          {
            require(_token.approve(_spender, _value));
          }
        }
        
        // File: openzeppelin-solidity/contracts/ownership/CanReclaimToken.sol
        
        /**
         * @title Contracts that should be able to recover tokens
         * @author SylTi
         * @dev This allow a contract to recover any ERC20 token received in a contract by transferring the balance to the contract owner.
         * This will prevent any accidental loss of tokens.
         */
        contract CanReclaimToken is Ownable {
          using SafeERC20 for ERC20Basic;
        
          /**
           * @dev Reclaim all ERC20Basic compatible tokens
           * @param _token ERC20Basic The address of the token contract
           */
          function reclaimToken(ERC20Basic _token) external onlyOwner {
            uint256 balance = _token.balanceOf(this);
            _token.safeTransfer(owner, balance);
          }
        
        }
        
        // File: contracts/utils/OwnableContract.sol
        
        // empty block is used as this contract just inherits others.
        contract OwnableContract is CanReclaimToken, Claimable { } /* solhint-disable-line no-empty-blocks */
        
        // File: contracts/token/WBTC.sol
        
        contract WBTC is StandardToken, DetailedERC20("Wrapped BTC", "WBTC", 8),
            MintableToken, BurnableToken, PausableToken, OwnableContract {
        
            function burn(uint value) public onlyOwner {
                super.burn(value);
            }
        
            function finishMinting() public onlyOwner returns (bool) {
                return false;
            }
        
            function renounceOwnership() public onlyOwner {
                revert("renouncing ownership is blocked");
            }
        }