ETH Price: $3,635.09 (+0.13%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Remove Liquidity125660512021-06-04 5:19:391311 days ago1622783979IN
Bancor: Converter 259
0 ETH0.0028527717
Remove Liquidity120718472021-03-19 22:22:481387 days ago1616192568IN
Bancor: Converter 259
0 ETH0.02339791131
Remove Liquidity119857062021-03-06 15:29:041401 days ago1615044544IN
Bancor: Converter 259
0 ETH0.0122835869.00000156
Set Max Staked B...119777182021-03-05 10:19:431402 days ago1614939583IN
Bancor: Converter 259
0 ETH0.00389179106
Add Liquidity119777182021-03-05 10:19:431402 days ago1614939583IN
Bancor: Converter 259
0 ETH0.01704119106
Set Max Staked B...119777172021-03-05 10:19:171402 days ago1614939557IN
Bancor: Converter 259
0 ETH0.00391468106
Remove Liquidity119776882021-03-05 10:15:161402 days ago1614939316IN
Bancor: Converter 259
0 ETH0.01958451110
Remove Liquidity119717852021-03-04 12:27:081403 days ago1614860828IN
Bancor: Converter 259
0 ETH0.0124645570
Remove Liquidity117338712021-01-26 21:42:541439 days ago1611697374IN
Bancor: Converter 259
0 ETH0.0160851690
Remove Liquidity117338352021-01-26 21:36:271439 days ago1611696987IN
Bancor: Converter 259
0 ETH0.0166218993
Remove Liquidity117338122021-01-26 21:32:221439 days ago1611696742IN
Bancor: Converter 259
0 ETH0.0187970497
Remove Liquidity117328092021-01-26 17:49:541440 days ago1611683394IN
Bancor: Converter 259
0 ETH0.0151448785
Remove Liquidity116538642021-01-14 14:53:431452 days ago1610636023IN
Bancor: Converter 259
0 ETH0.0130559280.00000145
Remove Liquidity114843752020-12-19 14:58:171478 days ago1608389897IN
Bancor: Converter 259
0 ETH0.0108158260.5000016
Remove Liquidity114159212020-12-09 2:18:351488 days ago1607480315IN
Bancor: Converter 259
0 ETH0.0067733838
Remove Liquidity113816772020-12-03 19:51:271493 days ago1607025087IN
Bancor: Converter 259
0 ETH0.0042920124
Remove Liquidity113805912020-12-03 15:54:131494 days ago1607010853IN
Bancor: Converter 259
0 ETH0.0084063247
Remove Liquidity112859062020-11-19 3:14:531508 days ago1605755693IN
Bancor: Converter 259
0 ETH0.0054073133.00000145
Remove Liquidity112838312020-11-18 19:32:311508 days ago1605727951IN
Bancor: Converter 259
0 ETH0.0044561725
Remove Liquidity112838042020-11-18 19:27:571508 days ago1605727677IN
Bancor: Converter 259
0 ETH0.01889418106
Remove Liquidity112601092020-11-15 4:03:201512 days ago1605413000IN
Bancor: Converter 259
0 ETH0.003263520
Remove Liquidity112565132020-11-14 14:58:221513 days ago1605365902IN
Bancor: Converter 259
0 ETH0.0058401532.67000025
Remove Liquidity111987802020-11-05 18:13:471522 days ago1604600027IN
Bancor: Converter 259
0 ETH0.0124459176
Remove Liquidity111770722020-11-02 10:22:421525 days ago1604312562IN
Bancor: Converter 259
0 ETH0.0119834867.00000145
Remove Liquidity111152582020-10-23 22:30:571534 days ago1603492257IN
Bancor: Converter 259
0 ETH0.0048981330
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
107812962020-09-02 10:31:351586 days ago1599042695  Contract Creation0 ETH
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x802C9534...744Ca3C20
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
LiquidityPoolV2Converter

Compiler Version
v0.4.26+commit.4563c3fc

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2020-09-02
*/

// File: solidity/contracts/utility/interfaces/IOwned.sol

pragma solidity 0.4.26;

/*
    Owned contract interface
*/
contract IOwned {
    // this function isn't abstract since the compiler emits automatically generated getter functions as external
    function owner() public view returns (address) {this;}

    function transferOwnership(address _newOwner) public;
    function acceptOwnership() public;
}

// File: solidity/contracts/token/interfaces/IERC20Token.sol

pragma solidity 0.4.26;

/*
    ERC20 Standard Token interface
*/
contract IERC20Token {
    // these functions aren't abstract since the compiler emits automatically generated getter functions as external
    function name() public view returns (string) {this;}
    function symbol() public view returns (string) {this;}
    function decimals() public view returns (uint8) {this;}
    function totalSupply() public view returns (uint256) {this;}
    function balanceOf(address _owner) public view returns (uint256) {_owner; this;}
    function allowance(address _owner, address _spender) public view returns (uint256) {_owner; _spender; this;}

    function transfer(address _to, uint256 _value) public returns (bool success);
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
    function approve(address _spender, uint256 _value) public returns (bool success);
}

// File: solidity/contracts/utility/interfaces/ITokenHolder.sol

pragma solidity 0.4.26;



/*
    Token Holder interface
*/
contract ITokenHolder is IOwned {
    function withdrawTokens(IERC20Token _token, address _to, uint256 _amount) public;
}

// File: solidity/contracts/converter/interfaces/IConverterAnchor.sol

pragma solidity 0.4.26;



/*
    Converter Anchor interface
*/
contract IConverterAnchor is IOwned, ITokenHolder {
}

// File: solidity/contracts/token/interfaces/ISmartToken.sol

pragma solidity 0.4.26;




/*
    Smart Token interface
*/
contract ISmartToken is IConverterAnchor, IERC20Token {
    function disableTransfers(bool _disable) public;
    function issue(address _to, uint256 _amount) public;
    function destroy(address _from, uint256 _amount) public;
}

// File: solidity/contracts/converter/types/liquidity-pool-v2/interfaces/IPoolTokensContainer.sol

pragma solidity 0.4.26;



/*
    Pool Tokens Container interface
*/
contract IPoolTokensContainer is IConverterAnchor {
    function poolTokens() public view returns (ISmartToken[]);
    function createToken() public returns (ISmartToken);
    function mint(ISmartToken _token, address _to, uint256 _amount) public;
    function burn(ISmartToken _token, address _from, uint256 _amount) public;
}

// File: solidity/contracts/utility/Owned.sol

pragma solidity 0.4.26;


/**
  * @dev Provides support and utilities for contract ownership
*/
contract Owned is IOwned {
    address public owner;
    address public newOwner;

    /**
      * @dev triggered when the owner is updated
      *
      * @param _prevOwner previous owner
      * @param _newOwner  new owner
    */
    event OwnerUpdate(address indexed _prevOwner, address indexed _newOwner);

    /**
      * @dev initializes a new Owned instance
    */
    constructor() public {
        owner = msg.sender;
    }

    // allows execution by the owner only
    modifier ownerOnly {
        _ownerOnly();
        _;
    }

    // error message binary size optimization
    function _ownerOnly() internal view {
        require(msg.sender == owner, "ERR_ACCESS_DENIED");
    }

    /**
      * @dev allows transferring the contract ownership
      * the new owner still needs to accept the transfer
      * can only be called by the contract owner
      *
      * @param _newOwner    new contract owner
    */
    function transferOwnership(address _newOwner) public ownerOnly {
        require(_newOwner != owner, "ERR_SAME_OWNER");
        newOwner = _newOwner;
    }

    /**
      * @dev used by a new owner to accept an ownership transfer
    */
    function acceptOwnership() public {
        require(msg.sender == newOwner, "ERR_ACCESS_DENIED");
        emit OwnerUpdate(owner, newOwner);
        owner = newOwner;
        newOwner = address(0);
    }
}

// File: solidity/contracts/utility/Utils.sol

pragma solidity 0.4.26;

/**
  * @dev Utilities & Common Modifiers
*/
contract Utils {
    // verifies that a value is greater than zero
    modifier greaterThanZero(uint256 _value) {
        _greaterThanZero(_value);
        _;
    }

    // error message binary size optimization
    function _greaterThanZero(uint256 _value) internal pure {
        require(_value > 0, "ERR_ZERO_VALUE");
    }

    // validates an address - currently only checks that it isn't null
    modifier validAddress(address _address) {
        _validAddress(_address);
        _;
    }

    // error message binary size optimization
    function _validAddress(address _address) internal pure {
        require(_address != address(0), "ERR_INVALID_ADDRESS");
    }

    // verifies that the address is different than this contract address
    modifier notThis(address _address) {
        _notThis(_address);
        _;
    }

    // error message binary size optimization
    function _notThis(address _address) internal view {
        require(_address != address(this), "ERR_ADDRESS_IS_SELF");
    }
}

// File: solidity/contracts/utility/TokenHandler.sol

pragma solidity 0.4.26;


contract TokenHandler {
    bytes4 private constant APPROVE_FUNC_SELECTOR = bytes4(keccak256("approve(address,uint256)"));
    bytes4 private constant TRANSFER_FUNC_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
    bytes4 private constant TRANSFER_FROM_FUNC_SELECTOR = bytes4(keccak256("transferFrom(address,address,uint256)"));

    /**
      * @dev executes the ERC20 token's `approve` function and reverts upon failure
      * the main purpose of this function is to prevent a non standard ERC20 token
      * from failing silently
      *
      * @param _token   ERC20 token address
      * @param _spender approved address
      * @param _value   allowance amount
    */
    function safeApprove(IERC20Token _token, address _spender, uint256 _value) internal {
       execute(_token, abi.encodeWithSelector(APPROVE_FUNC_SELECTOR, _spender, _value));
    }

    /**
      * @dev executes the ERC20 token's `transfer` function and reverts upon failure
      * the main purpose of this function is to prevent a non standard ERC20 token
      * from failing silently
      *
      * @param _token   ERC20 token address
      * @param _to      target address
      * @param _value   transfer amount
    */
    function safeTransfer(IERC20Token _token, address _to, uint256 _value) internal {
       execute(_token, abi.encodeWithSelector(TRANSFER_FUNC_SELECTOR, _to, _value));
    }

    /**
      * @dev executes the ERC20 token's `transferFrom` function and reverts upon failure
      * the main purpose of this function is to prevent a non standard ERC20 token
      * from failing silently
      *
      * @param _token   ERC20 token address
      * @param _from    source address
      * @param _to      target address
      * @param _value   transfer amount
    */
    function safeTransferFrom(IERC20Token _token, address _from, address _to, uint256 _value) internal {
       execute(_token, abi.encodeWithSelector(TRANSFER_FROM_FUNC_SELECTOR, _from, _to, _value));
    }

    /**
      * @dev executes a function on the ERC20 token and reverts upon failure
      * the main purpose of this function is to prevent a non standard ERC20 token
      * from failing silently
      *
      * @param _token   ERC20 token address
      * @param _data    data to pass in to the token's contract for execution
    */
    function execute(IERC20Token _token, bytes memory _data) private {
        uint256[1] memory ret = [uint256(1)];

        assembly {
            let success := call(
                gas,            // gas remaining
                _token,         // destination address
                0,              // no ether
                add(_data, 32), // input buffer (starts after the first 32 bytes in the `data` array)
                mload(_data),   // input length (loaded from the first 32 bytes in the `data` array)
                ret,            // output buffer
                32              // output length
            )
            if iszero(success) {
                revert(0, 0)
            }
        }

        require(ret[0] != 0, "ERR_TRANSFER_FAILED");
    }
}

// File: solidity/contracts/utility/TokenHolder.sol

pragma solidity 0.4.26;






/**
  * @dev We consider every contract to be a 'token holder' since it's currently not possible
  * for a contract to deny receiving tokens.
  *
  * The TokenHolder's contract sole purpose is to provide a safety mechanism that allows
  * the owner to send tokens that were sent to the contract by mistake back to their sender.
  *
  * Note that we use the non standard ERC-20 interface which has no return value for transfer
  * in order to support both non standard as well as standard token contracts.
  * see https://github.com/ethereum/solidity/issues/4116
*/
contract TokenHolder is ITokenHolder, TokenHandler, Owned, Utils {
    /**
      * @dev withdraws tokens held by the contract and sends them to an account
      * can only be called by the owner
      *
      * @param _token   ERC20 token contract address
      * @param _to      account to receive the new amount
      * @param _amount  amount to withdraw
    */
    function withdrawTokens(IERC20Token _token, address _to, uint256 _amount)
        public
        ownerOnly
        validAddress(_token)
        validAddress(_to)
        notThis(_to)
    {
        safeTransfer(_token, _to, _amount);
    }
}

// File: solidity/contracts/utility/SafeMath.sol

pragma solidity 0.4.26;

/**
  * @dev Library for basic math operations with overflow/underflow protection
*/
library SafeMath {
    /**
      * @dev returns the sum of _x and _y, reverts if the calculation overflows
      *
      * @param _x   value 1
      * @param _y   value 2
      *
      * @return sum
    */
    function add(uint256 _x, uint256 _y) internal pure returns (uint256) {
        uint256 z = _x + _y;
        require(z >= _x, "ERR_OVERFLOW");
        return z;
    }

    /**
      * @dev returns the difference of _x minus _y, reverts if the calculation underflows
      *
      * @param _x   minuend
      * @param _y   subtrahend
      *
      * @return difference
    */
    function sub(uint256 _x, uint256 _y) internal pure returns (uint256) {
        require(_x >= _y, "ERR_UNDERFLOW");
        return _x - _y;
    }

    /**
      * @dev returns the product of multiplying _x by _y, reverts if the calculation overflows
      *
      * @param _x   factor 1
      * @param _y   factor 2
      *
      * @return product
    */
    function mul(uint256 _x, uint256 _y) internal pure returns (uint256) {
        // gas optimization
        if (_x == 0)
            return 0;

        uint256 z = _x * _y;
        require(z / _x == _y, "ERR_OVERFLOW");
        return z;
    }

    /**
      * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
      *
      * @param _x   dividend
      * @param _y   divisor
      *
      * @return quotient
    */
    function div(uint256 _x, uint256 _y) internal pure returns (uint256) {
        require(_y > 0, "ERR_DIVIDE_BY_ZERO");
        uint256 c = _x / _y;
        return c;
    }
}

// File: solidity/contracts/token/ERC20Token.sol

pragma solidity 0.4.26;




/**
  * @dev ERC20 Standard Token implementation
*/
contract ERC20Token is IERC20Token, Utils {
    using SafeMath for uint256;


    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 public totalSupply;
    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;

    /**
      * @dev triggered when tokens are transferred between wallets
      *
      * @param _from    source address
      * @param _to      target address
      * @param _value   transfer amount
    */
    event Transfer(address indexed _from, address indexed _to, uint256 _value);

    /**
      * @dev triggered when a wallet allows another wallet to transfer tokens from on its behalf
      *
      * @param _owner   wallet that approves the allowance
      * @param _spender wallet that receives the allowance
      * @param _value   allowance amount
    */
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);

    /**
      * @dev initializes a new ERC20Token instance
      *
      * @param _name        token name
      * @param _symbol      token symbol
      * @param _decimals    decimal points, for display purposes
      * @param _totalSupply total supply of token units
    */
    constructor(string _name, string _symbol, uint8 _decimals, uint256 _totalSupply) public {
        // validate input
        require(bytes(_name).length > 0, "ERR_INVALID_NAME");
        require(bytes(_symbol).length > 0, "ERR_INVALID_SYMBOL");

        name = _name;
        symbol = _symbol;
        decimals = _decimals;
        totalSupply = _totalSupply;
        balanceOf[msg.sender] = _totalSupply;
    }

    /**
      * @dev transfers tokens to a given address
      * throws on any error rather then return a false flag to minimize user errors
      *
      * @param _to      target address
      * @param _value   transfer amount
      *
      * @return true if the transfer was successful, false if it wasn't
    */
    function transfer(address _to, uint256 _value)
        public
        validAddress(_to)
        returns (bool success)
    {
        balanceOf[msg.sender] = balanceOf[msg.sender].sub(_value);
        balanceOf[_to] = balanceOf[_to].add(_value);
        emit Transfer(msg.sender, _to, _value);
        return true;
    }

    /**
      * @dev transfers tokens to a given address on behalf of another address
      * throws on any error rather then return a false flag to minimize user errors
      *
      * @param _from    source address
      * @param _to      target address
      * @param _value   transfer amount
      *
      * @return true if the transfer was successful, false if it wasn't
    */
    function transferFrom(address _from, address _to, uint256 _value)
        public
        validAddress(_from)
        validAddress(_to)
        returns (bool success)
    {
        allowance[_from][msg.sender] = allowance[_from][msg.sender].sub(_value);
        balanceOf[_from] = balanceOf[_from].sub(_value);
        balanceOf[_to] = balanceOf[_to].add(_value);
        emit Transfer(_from, _to, _value);
        return true;
    }

    /**
      * @dev allows another account/contract to transfers tokens on behalf of the caller
      * throws on any error rather then return a false flag to minimize user errors
      *
      * also, to minimize the risk of the approve/transferFrom attack vector
      * (see https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/), approve has to be called twice
      * in 2 separate transactions - once to change the allowance to 0 and secondly to change it to the new allowance value
      *
      * @param _spender approved address
      * @param _value   allowance amount
      *
      * @return true if the approval was successful, false if it wasn't
    */
    function approve(address _spender, uint256 _value)
        public
        validAddress(_spender)
        returns (bool success)
    {
        // if the allowance isn't 0, it can only be updated to 0 to prevent an allowance change immediately after withdrawal
        require(_value == 0 || allowance[msg.sender][_spender] == 0, "ERR_INVALID_AMOUNT");

        allowance[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }
}

// File: solidity/contracts/token/SmartToken.sol

pragma solidity 0.4.26;





/**
  * @dev Smart Token
  *
  * 'Owned' is specified here for readability reasons
*/
contract SmartToken is ISmartToken, Owned, ERC20Token, TokenHolder {
    using SafeMath for uint256;

    uint16 public constant version = 4;

    bool public transfersEnabled = true;    // true if transfer/transferFrom are enabled, false otherwise

    /**
      * @dev triggered when the total supply is increased
      *
      * @param _amount  amount that gets added to the supply
    */
    event Issuance(uint256 _amount);

    /**
      * @dev triggered when the total supply is decreased
      *
      * @param _amount  amount that gets removed from the supply
    */
    event Destruction(uint256 _amount);

    /**
      * @dev initializes a new SmartToken instance
      *
      * @param _name       token name
      * @param _symbol     token short symbol, minimum 1 character
      * @param _decimals   for display purposes only
    */
    constructor(string _name, string _symbol, uint8 _decimals)
        public
        ERC20Token(_name, _symbol, _decimals, 0)
    {
    }

    // allows execution only when transfers are enabled
    modifier transfersAllowed {
        _transfersAllowed();
        _;
    }

    // error message binary size optimization
    function _transfersAllowed() internal view {
        require(transfersEnabled, "ERR_TRANSFERS_DISABLED");
    }

    /**
      * @dev disables/enables transfers
      * can only be called by the contract owner
      *
      * @param _disable    true to disable transfers, false to enable them
    */
    function disableTransfers(bool _disable) public ownerOnly {
        transfersEnabled = !_disable;
    }

    /**
      * @dev increases the token supply and sends the new tokens to the given account
      * can only be called by the contract owner
      *
      * @param _to      account to receive the new amount
      * @param _amount  amount to increase the supply by
    */
    function issue(address _to, uint256 _amount)
        public
        ownerOnly
        validAddress(_to)
        notThis(_to)
    {
        totalSupply = totalSupply.add(_amount);
        balanceOf[_to] = balanceOf[_to].add(_amount);

        emit Issuance(_amount);
        emit Transfer(address(0), _to, _amount);
    }

    /**
      * @dev removes tokens from the given account and decreases the token supply
      * can only be called by the contract owner
      *
      * @param _from    account to remove the amount from
      * @param _amount  amount to decrease the supply by
    */
    function destroy(address _from, uint256 _amount) public ownerOnly {
        balanceOf[_from] = balanceOf[_from].sub(_amount);
        totalSupply = totalSupply.sub(_amount);

        emit Transfer(_from, address(0), _amount);
        emit Destruction(_amount);
    }

    // ERC20 standard method overrides with some extra functionality

    /**
      * @dev send coins
      * throws on any error rather then return a false flag to minimize user errors
      * in addition to the standard checks, the function throws if transfers are disabled
      *
      * @param _to      target address
      * @param _value   transfer amount
      *
      * @return true if the transfer was successful, false if it wasn't
    */
    function transfer(address _to, uint256 _value) public transfersAllowed returns (bool success) {
        assert(super.transfer(_to, _value));
        return true;
    }

    /**
      * @dev an account/contract attempts to get the coins
      * throws on any error rather then return a false flag to minimize user errors
      * in addition to the standard checks, the function throws if transfers are disabled
      *
      * @param _from    source address
      * @param _to      target address
      * @param _value   transfer amount
      *
      * @return true if the transfer was successful, false if it wasn't
    */
    function transferFrom(address _from, address _to, uint256 _value) public transfersAllowed returns (bool success) {
        assert(super.transferFrom(_from, _to, _value));
        return true;
    }
}

// File: solidity/contracts/converter/types/liquidity-pool-v2/PoolTokensContainer.sol

pragma solidity 0.4.26;





/**
  * @dev The PoolTokensContainer contract serves as a container for multiple pool tokens.
  * It is used by specific liquidity pool types that require more than a single pool token,
  * while still maintaining the single converter / anchor relationship.
  *
  * It maintains and provides a list of the underlying pool tokens.
 */
contract PoolTokensContainer is IPoolTokensContainer, Owned, TokenHolder {
    uint8 internal constant MAX_POOL_TOKENS = 5;    // maximum pool tokens in the container

    string public name;                 // pool name
    string public symbol;               // pool symbol
    uint8 public decimals;              // underlying pool tokens decimals
    ISmartToken[] private _poolTokens;  // underlying pool tokens

    /**
      * @dev initializes a new PoolTokensContainer instance
      *
      * @param  _name       pool name, also used as a prefix for the underlying pool token names
      * @param  _symbol     pool symbol, also used as a prefix for the underlying pool token symbols
      * @param  _decimals   used for the underlying pool token decimals
    */
    constructor(string _name, string _symbol, uint8 _decimals) public {
         // validate input
        require(bytes(_name).length > 0, "ERR_INVALID_NAME");
        require(bytes(_symbol).length > 0, "ERR_INVALID_SYMBOL");

        name = _name;
        symbol = _symbol;
        decimals = _decimals;
    }

    /**
      * @dev returns the list of pool tokens
      *
      * @return list of pool tokens
    */
    function poolTokens() public view returns (ISmartToken[] memory) {
        return _poolTokens;
    }

    /**
      * @dev creates a new pool token and adds it to the list
      *
      * @return new pool token address
    */
    function createToken() public ownerOnly returns (ISmartToken) {
        // verify that the max limit wasn't reached
        require(_poolTokens.length < MAX_POOL_TOKENS, "ERR_MAX_LIMIT_REACHED");

        string memory poolName = concatStrDigit(name, uint8(_poolTokens.length + 1));
        string memory poolSymbol = concatStrDigit(symbol, uint8(_poolTokens.length + 1));

        SmartToken token = new SmartToken(poolName, poolSymbol, decimals);
        _poolTokens.push(token);
        return token;
    }

    /**
      * @dev increases the pool token supply and sends the new tokens to the given account
      * can only be called by the contract owner
      *
      * @param _token   pool token address
      * @param _to      account to receive the newly minted tokens
      * @param _amount  amount to mint
    */
    function mint(ISmartToken _token, address _to, uint256 _amount) public ownerOnly {
        _token.issue(_to, _amount);
    }

    /**
      * @dev removes tokens from the given account and decreases the pool token supply
      * can only be called by the contract owner
      *
      * @param _token   pool token address
      * @param _from    account to remove the tokens from
      * @param _amount  amount to burn
    */
    function burn(ISmartToken _token, address _from, uint256 _amount) public ownerOnly {
        _token.destroy(_from, _amount);
    }

    /**
      * @dev concatenates a string and a digit (single only) and returns the result string
      *
      * @param _str     string
      * @param _digit   digit
      * @return concatenated string
    */
    function concatStrDigit(string _str, uint8 _digit) private pure returns (string) {
        return string(abi.encodePacked(_str, uint8(bytes1('0')) + _digit));
    }
}

// File: solidity/contracts/converter/interfaces/ITypedConverterCustomFactory.sol

pragma solidity 0.4.26;

/*
    Typed Converter Custom Factory interface
*/
contract ITypedConverterCustomFactory {
    function converterType() public pure returns (uint16);
}

// File: solidity/contracts/utility/interfaces/IChainlinkPriceOracle.sol

pragma solidity 0.4.26;

/*
    Chainlink Price Oracle interface
*/
interface IChainlinkPriceOracle {
    function latestAnswer() external view returns (int256);
    function latestTimestamp() external view returns (uint256);
}

// File: solidity/contracts/utility/interfaces/IPriceOracle.sol

pragma solidity 0.4.26;



/*
    Price Oracle interface
*/
contract IPriceOracle {
    function latestRate(IERC20Token _tokenA, IERC20Token _tokenB) public view returns (uint256, uint256);
    function lastUpdateTime() public view returns (uint256);
    function latestRateAndUpdateTime(IERC20Token _tokenA, IERC20Token _tokenB) public view returns (uint256, uint256, uint256);

    function tokenAOracle() public view returns (IChainlinkPriceOracle) {this;}
    function tokenBOracle() public view returns (IChainlinkPriceOracle) {this;}
}

// File: solidity/contracts/utility/PriceOracle.sol

pragma solidity 0.4.26;





/**
  * @dev Provides the off-chain rate between two tokens
  *
  * The price oracle uses chainlink oracles internally to get the rates of the two tokens
  * with respect to a common denominator, and then returns the rate between them, which
  * is equivalent to the rate of TokenA / TokenB
*/
contract PriceOracle is IPriceOracle, Utils {
    using SafeMath for uint256;

    address private constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
    uint8 private constant ETH_DECIMALS = 18;

    IERC20Token public tokenA;                  // token A the oracle supports
    IERC20Token public tokenB;                  // token B the oracle supports
    mapping (address => uint8) public tokenDecimals; // token -> token decimals

    IChainlinkPriceOracle public tokenAOracle;  // token A chainlink price oracle
    IChainlinkPriceOracle public tokenBOracle;  // token B chainlink price oracle
    mapping (address => IChainlinkPriceOracle) public tokensToOracles;  // token -> price oracle for easier access

    /**
      * @dev initializes a new PriceOracle instance
      * note that the oracles must have the same common denominator (USD, ETH etc.)
      *
      * @param  _tokenA         first token to support
      * @param  _tokenB         second token to support
      * @param  _tokenAOracle   first token price oracle
      * @param  _tokenBOracle   second token price oracle
    */
    constructor(IERC20Token _tokenA, IERC20Token _tokenB, IChainlinkPriceOracle _tokenAOracle, IChainlinkPriceOracle _tokenBOracle)
        public
        validUniqueAddresses(_tokenA, _tokenB)
        validUniqueAddresses(_tokenAOracle, _tokenBOracle)
    {
        tokenA = _tokenA;
        tokenB = _tokenB;
        tokenDecimals[_tokenA] = decimals(_tokenA);
        tokenDecimals[_tokenB] = decimals(_tokenB);

        tokenAOracle = _tokenAOracle;
        tokenBOracle = _tokenBOracle;
        tokensToOracles[_tokenA] = _tokenAOracle;
        tokensToOracles[_tokenB] = _tokenBOracle;
    }

    // ensures that the provided addresses are unique valid
    modifier validUniqueAddresses(address _address1, address _address2) {
        _validUniqueAddresses(_address1, _address2);
        _;
    }

    // error message binary size optimization
    function _validUniqueAddresses(address _address1, address _address2) internal pure {
        _validAddress(_address1);
        _validAddress(_address2);
        require(_address1 != _address2, "ERR_SAME_ADDRESS");
    }

    // ensures that the provides tokens are supported by the oracle
    modifier supportedTokens(IERC20Token _tokenA, IERC20Token _tokenB) {
        _supportedTokens(_tokenA, _tokenB);
        _;
    }

    // error message binary size optimization
    function _supportedTokens(IERC20Token _tokenA, IERC20Token _tokenB) internal view {
        _validUniqueAddresses(_tokenA, _tokenB);
        require(tokensToOracles[_tokenA] != address(0) && tokensToOracles[_tokenB] != address(0), "ERR_UNSUPPORTED_TOKEN");
    }

    /**
      * @dev returns the latest known rate between the two given tokens
      * for a given pair of tokens A and B, returns the rate of A / B
      * (the number of B units equivalent to a single A unit)
      * the rate is returned as a fraction (numerator / denominator) for accuracy
      *
      * @param  _tokenA token to get the rate of 1 unit of
      * @param  _tokenB token to get the rate of 1 `_tokenA` against
      *
      * @return numerator
      * @return denominator
    */
    function latestRate(IERC20Token _tokenA, IERC20Token _tokenB)
        public
        view
        supportedTokens(_tokenA, _tokenB)
        returns (uint256, uint256)
    {
        uint256 rateTokenA = uint256(tokensToOracles[_tokenA].latestAnswer());
        uint256 rateTokenB = uint256(tokensToOracles[_tokenB].latestAnswer());
        uint8 decimalsTokenA = tokenDecimals[_tokenA];
        uint8 decimalsTokenB = tokenDecimals[_tokenB];

        // the normalization works as follows:
        //   - token A with decimals of dA and price of rateA per one token (e.g., for 10^dA weiA)
        //   - token B with decimals of dB < dA and price of rateB per one token (e.g., for 10^dB weiB)
        // then the normalized rate, representing the rate between 1 weiA and 1 weiB is rateA / (rateB * 10^(dA - dB)).
        //
        // for example:
        //   - token A with decimals of 5 and price of $10 per one token (e.g., for 100,000 weiA)
        //   - token B with decimals of 2 and price of $2 per one token (e.g., for 100 weiB)
        // then the normalized rate would be: 5 / (2 * 10^3) = 0.0025, which is the correct rate since
        // 1 weiA costs $0.00005, 1 weiB costs $0.02, and weiA / weiB is 0.0025.

        if (decimalsTokenA > decimalsTokenB) {
            rateTokenB = rateTokenB.mul(uint256(10) ** (decimalsTokenA - decimalsTokenB));
        }
        else if (decimalsTokenA < decimalsTokenB) {
            rateTokenA = rateTokenA.mul(uint256(10) ** (decimalsTokenB - decimalsTokenA));
        }

        return (rateTokenA, rateTokenB);
    }

    /**
      * @dev returns the timestamp of the last price update the rates are returned as numerator (token1) and denominator
      * (token2) for accuracy
      *
      * @return timestamp
    */
    function lastUpdateTime()
        public
        view
        returns (uint256) {
        // returns the oldest timestamp between the two
        uint256 timestampA = tokenAOracle.latestTimestamp();
        uint256 timestampB = tokenBOracle.latestTimestamp();

        return  timestampA < timestampB ? timestampA : timestampB;
    }

    /**
      * @dev returns both the rate and the timestamp of the last update in a single call (gas optimization)
      *
      * @param  _tokenA token to get the rate of 1 unit of
      * @param  _tokenB token to get the rate of 1 `_tokenA` against
      *
      * @return numerator
      * @return denominator
      * @return timestamp of the last update
    */
    function latestRateAndUpdateTime(IERC20Token _tokenA, IERC20Token _tokenB)
        public
        view
        returns (uint256, uint256, uint256)
    {
        (uint256 numerator, uint256 denominator) = latestRate(_tokenA, _tokenB);

        return (numerator, denominator, lastUpdateTime());
    }

    /** @dev returns the decimals of a given token */
    function decimals(IERC20Token _token) private view returns (uint8) {
        if (_token == ETH_ADDRESS) {
            return ETH_DECIMALS;
        }

        return _token.decimals();
    }
}

// File: solidity/contracts/converter/types/liquidity-pool-v2/LiquidityPoolV2ConverterCustomFactory.sol

pragma solidity 0.4.26;



/*
    LiquidityPoolV2ConverterCustomFactory Factory
*/
contract LiquidityPoolV2ConverterCustomFactory is ITypedConverterCustomFactory {
    /**
      * @dev returns the converter type the factory is associated with
      *
      * @return converter type
    */
    function converterType() public pure returns (uint16) {
        return 2;
    }

    /**
      * @dev creates a new price oracle
      * note that the oracles must have the same common denominator (USD, ETH etc.)
      *
      * @param  _primaryReserveToken    primary reserve token address
      * @param  _secondaryReserveToken  secondary reserve token address
      * @param  _primaryReserveOracle   primary reserve oracle address
      * @param  _secondaryReserveOracle secondary reserve oracle address
    */
    function createPriceOracle(
        IERC20Token _primaryReserveToken,
        IERC20Token _secondaryReserveToken,
        IChainlinkPriceOracle _primaryReserveOracle,
        IChainlinkPriceOracle _secondaryReserveOracle)
        public
        returns (IPriceOracle)
    {
        return new PriceOracle(_primaryReserveToken, _secondaryReserveToken, _primaryReserveOracle, _secondaryReserveOracle);
    }
}

// File: solidity/contracts/utility/interfaces/IWhitelist.sol

pragma solidity 0.4.26;

/*
    Whitelist interface
*/
contract IWhitelist {
    function isWhitelisted(address _address) public view returns (bool);
}

// File: solidity/contracts/converter/interfaces/IConverter.sol

pragma solidity 0.4.26;





/*
    Converter interface
*/
contract IConverter is IOwned {
    function converterType() public pure returns (uint16);
    function anchor() public view returns (IConverterAnchor) {this;}
    function isActive() public view returns (bool);

    function targetAmountAndFee(IERC20Token _sourceToken, IERC20Token _targetToken, uint256 _amount) public view returns (uint256, uint256);
    function convert(IERC20Token _sourceToken,
                     IERC20Token _targetToken,
                     uint256 _amount,
                     address _trader,
                     address _beneficiary) public payable returns (uint256);

    function conversionWhitelist() public view returns (IWhitelist) {this;}
    function conversionFee() public view returns (uint32) {this;}
    function maxConversionFee() public view returns (uint32) {this;}
    function reserveBalance(IERC20Token _reserveToken) public view returns (uint256);
    function() external payable;

    function transferAnchorOwnership(address _newOwner) public;
    function acceptAnchorOwnership() public;
    function setConversionFee(uint32 _conversionFee) public;
    function setConversionWhitelist(IWhitelist _whitelist) public;
    function withdrawTokens(IERC20Token _token, address _to, uint256 _amount) public;
    function withdrawETH(address _to) public;
    function addReserve(IERC20Token _token, uint32 _ratio) public;

    // deprecated, backward compatibility
    function token() public view returns (IConverterAnchor);
    function transferTokenOwnership(address _newOwner) public;
    function acceptTokenOwnership() public;
    function connectors(address _address) public view returns (uint256, uint32, bool, bool, bool);
    function getConnectorBalance(IERC20Token _connectorToken) public view returns (uint256);
    function connectorTokens(uint256 _index) public view returns (IERC20Token);
    function connectorTokenCount() public view returns (uint16);
}

// File: solidity/contracts/converter/interfaces/IConverterUpgrader.sol

pragma solidity 0.4.26;

/*
    Converter Upgrader interface
*/
contract IConverterUpgrader {
    function upgrade(bytes32 _version) public;
    function upgrade(uint16 _version) public;
}

// File: solidity/contracts/converter/interfaces/IBancorFormula.sol

pragma solidity 0.4.26;

/*
    Bancor Formula interface
*/
contract IBancorFormula {
    function purchaseTargetAmount(uint256 _supply,
                                  uint256 _reserveBalance,
                                  uint32 _reserveWeight,
                                  uint256 _amount)
                                  public view returns (uint256);

    function saleTargetAmount(uint256 _supply,
                              uint256 _reserveBalance,
                              uint32 _reserveWeight,
                              uint256 _amount)
                              public view returns (uint256);

    function crossReserveTargetAmount(uint256 _sourceReserveBalance,
                                      uint32 _sourceReserveWeight,
                                      uint256 _targetReserveBalance,
                                      uint32 _targetReserveWeight,
                                      uint256 _amount)
                                      public view returns (uint256);

    function fundCost(uint256 _supply,
                      uint256 _reserveBalance,
                      uint32 _reserveRatio,
                      uint256 _amount)
                      public view returns (uint256);

    function fundSupplyAmount(uint256 _supply,
                              uint256 _reserveBalance,
                              uint32 _reserveRatio,
                              uint256 _amount)
                              public view returns (uint256);

    function liquidateReserveAmount(uint256 _supply,
                                    uint256 _reserveBalance,
                                    uint32 _reserveRatio,
                                    uint256 _amount)
                                    public view returns (uint256);

    function balancedWeights(uint256 _primaryReserveStakedBalance,
                             uint256 _primaryReserveBalance,
                             uint256 _secondaryReserveBalance,
                             uint256 _reserveRateNumerator,
                             uint256 _reserveRateDenominator)
                             public view returns (uint32, uint32);
}

// File: solidity/contracts/IBancorNetwork.sol

pragma solidity 0.4.26;


/*
    Bancor Network interface
*/
contract IBancorNetwork {
    function convert2(
        IERC20Token[] _path,
        uint256 _amount,
        uint256 _minReturn,
        address _affiliateAccount,
        uint256 _affiliateFee
    ) public payable returns (uint256);

    function claimAndConvert2(
        IERC20Token[] _path,
        uint256 _amount,
        uint256 _minReturn,
        address _affiliateAccount,
        uint256 _affiliateFee
    ) public returns (uint256);

    function convertFor2(
        IERC20Token[] _path,
        uint256 _amount,
        uint256 _minReturn,
        address _for,
        address _affiliateAccount,
        uint256 _affiliateFee
    ) public payable returns (uint256);

    function claimAndConvertFor2(
        IERC20Token[] _path,
        uint256 _amount,
        uint256 _minReturn,
        address _for,
        address _affiliateAccount,
        uint256 _affiliateFee
    ) public returns (uint256);

    // deprecated, backward compatibility
    function convert(
        IERC20Token[] _path,
        uint256 _amount,
        uint256 _minReturn
    ) public payable returns (uint256);

    // deprecated, backward compatibility
    function claimAndConvert(
        IERC20Token[] _path,
        uint256 _amount,
        uint256 _minReturn
    ) public returns (uint256);

    // deprecated, backward compatibility
    function convertFor(
        IERC20Token[] _path,
        uint256 _amount,
        uint256 _minReturn,
        address _for
    ) public payable returns (uint256);

    // deprecated, backward compatibility
    function claimAndConvertFor(
        IERC20Token[] _path,
        uint256 _amount,
        uint256 _minReturn,
        address _for
    ) public returns (uint256);
}

// File: solidity/contracts/utility/interfaces/IContractRegistry.sol

pragma solidity 0.4.26;

/*
    Contract Registry interface
*/
contract IContractRegistry {
    function addressOf(bytes32 _contractName) public view returns (address);

    // deprecated, backward compatibility
    function getAddress(bytes32 _contractName) public view returns (address);
}

// File: solidity/contracts/utility/ContractRegistryClient.sol

pragma solidity 0.4.26;




/**
  * @dev Base contract for ContractRegistry clients
*/
contract ContractRegistryClient is Owned, Utils {
    bytes32 internal constant CONTRACT_REGISTRY = "ContractRegistry";
    bytes32 internal constant BANCOR_NETWORK = "BancorNetwork";
    bytes32 internal constant BANCOR_FORMULA = "BancorFormula";
    bytes32 internal constant CONVERTER_FACTORY = "ConverterFactory";
    bytes32 internal constant CONVERSION_PATH_FINDER = "ConversionPathFinder";
    bytes32 internal constant CONVERTER_UPGRADER = "BancorConverterUpgrader";
    bytes32 internal constant CONVERTER_REGISTRY = "BancorConverterRegistry";
    bytes32 internal constant CONVERTER_REGISTRY_DATA = "BancorConverterRegistryData";
    bytes32 internal constant BNT_TOKEN = "BNTToken";
    bytes32 internal constant BANCOR_X = "BancorX";
    bytes32 internal constant BANCOR_X_UPGRADER = "BancorXUpgrader";
    bytes32 internal constant CHAINLINK_ORACLE_WHITELIST = "ChainlinkOracleWhitelist";

    IContractRegistry public registry;      // address of the current contract-registry
    IContractRegistry public prevRegistry;  // address of the previous contract-registry
    bool public onlyOwnerCanUpdateRegistry; // only an owner can update the contract-registry

    /**
      * @dev verifies that the caller is mapped to the given contract name
      *
      * @param _contractName    contract name
    */
    modifier only(bytes32 _contractName) {
        _only(_contractName);
        _;
    }

    // error message binary size optimization
    function _only(bytes32 _contractName) internal view {
        require(msg.sender == addressOf(_contractName), "ERR_ACCESS_DENIED");
    }

    /**
      * @dev initializes a new ContractRegistryClient instance
      *
      * @param  _registry   address of a contract-registry contract
    */
    constructor(IContractRegistry _registry) internal validAddress(_registry) {
        registry = IContractRegistry(_registry);
        prevRegistry = IContractRegistry(_registry);
    }

    /**
      * @dev updates to the new contract-registry
     */
    function updateRegistry() public {
        // verify that this function is permitted
        require(msg.sender == owner || !onlyOwnerCanUpdateRegistry, "ERR_ACCESS_DENIED");

        // get the new contract-registry
        IContractRegistry newRegistry = IContractRegistry(addressOf(CONTRACT_REGISTRY));

        // verify that the new contract-registry is different and not zero
        require(newRegistry != address(registry) && newRegistry != address(0), "ERR_INVALID_REGISTRY");

        // verify that the new contract-registry is pointing to a non-zero contract-registry
        require(newRegistry.addressOf(CONTRACT_REGISTRY) != address(0), "ERR_INVALID_REGISTRY");

        // save a backup of the current contract-registry before replacing it
        prevRegistry = registry;

        // replace the current contract-registry with the new contract-registry
        registry = newRegistry;
    }

    /**
      * @dev restores the previous contract-registry
    */
    function restoreRegistry() public ownerOnly {
        // restore the previous contract-registry
        registry = prevRegistry;
    }

    /**
      * @dev restricts the permission to update the contract-registry
      *
      * @param _onlyOwnerCanUpdateRegistry  indicates whether or not permission is restricted to owner only
    */
    function restrictRegistryUpdate(bool _onlyOwnerCanUpdateRegistry) public ownerOnly {
        // change the permission to update the contract-registry
        onlyOwnerCanUpdateRegistry = _onlyOwnerCanUpdateRegistry;
    }

    /**
      * @dev returns the address associated with the given contract name
      *
      * @param _contractName    contract name
      *
      * @return contract address
    */
    function addressOf(bytes32 _contractName) internal view returns (address) {
        return registry.addressOf(_contractName);
    }
}

// File: solidity/contracts/utility/ReentrancyGuard.sol

pragma solidity 0.4.26;

/**
  * @dev ReentrancyGuard
  *
  * The contract provides protection against re-entrancy - calling a function (directly or
  * indirectly) from within itself.
*/
contract ReentrancyGuard {
    // true while protected code is being executed, false otherwise
    bool private locked = false;

    /**
      * @dev ensures instantiation only by sub-contracts
    */
    constructor() internal {}

    // protects a function against reentrancy attacks
    modifier protected() {
        _protected();
        locked = true;
        _;
        locked = false;
    }

    // error message binary size optimization
    function _protected() internal view {
        require(!locked, "ERR_REENTRANCY");
    }
}

// File: solidity/contracts/token/interfaces/IEtherToken.sol

pragma solidity 0.4.26;


/*
    Ether Token interface
*/
contract IEtherToken is IERC20Token {
    function deposit() public payable;
    function withdraw(uint256 _amount) public;
    function depositTo(address _to) public payable;
    function withdrawTo(address _to, uint256 _amount) public;
}

// File: solidity/contracts/bancorx/interfaces/IBancorX.sol

pragma solidity 0.4.26;


contract IBancorX {
    function token() public view returns (IERC20Token) {this;}
    function xTransfer(bytes32 _toBlockchain, bytes32 _to, uint256 _amount, uint256 _id) public;
    function getXTransferAmount(uint256 _xTransferId, address _for) public view returns (uint256);
}

// File: solidity/contracts/converter/ConverterBase.sol

pragma solidity 0.4.26;













/**
  * @dev ConverterBase
  *
  * The converter contains the main logic for conversions between different ERC20 tokens.
  *
  * It is also the upgradable part of the mechanism (note that upgrades are opt-in).
  *
  * The anchor must be set on construction and cannot be changed afterwards.
  * Wrappers are provided for some of the anchor's functions, for easier access.
  *
  * Once the converter accepts ownership of the anchor, it becomes the anchor's sole controller
  * and can execute any of its functions.
  *
  * To upgrade the converter, anchor ownership must be transferred to a new converter, along with
  * any relevant data.
  *
  * Note that the converter can transfer anchor ownership to a new converter that
  * doesn't allow upgrades anymore, for finalizing the relationship between the converter
  * and the anchor.
  *
  * Converter types (defined as uint16 type) -
  * 0 = liquid token converter
  * 1 = liquidity pool v1 converter
  * 2 = liquidity pool v2 converter
  *
  * Note that converters don't currently support tokens with transfer fees.
*/
contract ConverterBase is IConverter, TokenHandler, TokenHolder, ContractRegistryClient, ReentrancyGuard {
    using SafeMath for uint256;

    uint32 internal constant WEIGHT_RESOLUTION = 1000000;
    uint32 internal constant CONVERSION_FEE_RESOLUTION = 1000000;
    address internal constant ETH_RESERVE_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    struct Reserve {
        uint256 balance;    // reserve balance
        uint32 weight;      // reserve weight, represented in ppm, 1-1000000
        bool deprecated1;   // deprecated
        bool deprecated2;   // deprecated
        bool isSet;         // true if the reserve is valid, false otherwise
    }

    /**
      * @dev version number
    */
    uint16 public constant version = 37;

    IConverterAnchor public anchor;                 // converter anchor contract
    IWhitelist public conversionWhitelist;          // whitelist contract with list of addresses that are allowed to use the converter
    IERC20Token[] public reserveTokens;             // ERC20 standard token addresses (prior version 17, use 'connectorTokens' instead)
    mapping (address => Reserve) public reserves;   // reserve token addresses -> reserve data (prior version 17, use 'connectors' instead)
    uint32 public reserveRatio = 0;                 // ratio between the reserves and the market cap, equal to the total reserve weights
    uint32 public maxConversionFee = 0;             // maximum conversion fee for the lifetime of the contract,
                                                    // represented in ppm, 0...1000000 (0 = no fee, 100 = 0.01%, 1000000 = 100%)
    uint32 public conversionFee = 0;                // current conversion fee, represented in ppm, 0...maxConversionFee
    bool public constant conversionsEnabled = true; // deprecated, backward compatibility

    /**
      * @dev triggered when the converter is activated
      *
      * @param _type        converter type
      * @param _anchor      converter anchor
      * @param _activated   true if the converter was activated, false if it was deactivated
    */
    event Activation(uint16 indexed _type, IConverterAnchor indexed _anchor, bool indexed _activated);

    /**
      * @dev triggered when a conversion between two tokens occurs
      *
      * @param _fromToken       source ERC20 token
      * @param _toToken         target ERC20 token
      * @param _trader          wallet that initiated the trade
      * @param _amount          amount converted, in the source token
      * @param _return          amount returned, minus conversion fee
      * @param _conversionFee   conversion fee
    */
    event Conversion(
        address indexed _fromToken,
        address indexed _toToken,
        address indexed _trader,
        uint256 _amount,
        uint256 _return,
        int256 _conversionFee
    );

    /**
      * @dev triggered when the rate between two tokens in the converter changes
      * note that the event might be dispatched for rate updates between any two tokens in the converter
      * note that prior to version 28, you should use the 'PriceDataUpdate' event instead
      *
      * @param  _token1 address of the first token
      * @param  _token2 address of the second token
      * @param  _rateN  rate of 1 unit of `_token1` in `_token2` (numerator)
      * @param  _rateD  rate of 1 unit of `_token1` in `_token2` (denominator)
    */
    event TokenRateUpdate(
        address indexed _token1,
        address indexed _token2,
        uint256 _rateN,
        uint256 _rateD
    );

    /**
      * @dev triggered when the conversion fee is updated
      *
      * @param  _prevFee    previous fee percentage, represented in ppm
      * @param  _newFee     new fee percentage, represented in ppm
    */
    event ConversionFeeUpdate(uint32 _prevFee, uint32 _newFee);

    /**
      * @dev used by sub-contracts to initialize a new converter
      *
      * @param  _anchor             anchor governed by the converter
      * @param  _registry           address of a contract registry contract
      * @param  _maxConversionFee   maximum conversion fee, represented in ppm
    */
    constructor(
        IConverterAnchor _anchor,
        IContractRegistry _registry,
        uint32 _maxConversionFee
    )
        validAddress(_anchor)
        ContractRegistryClient(_registry)
        internal
        validConversionFee(_maxConversionFee)
    {
        anchor = _anchor;
        maxConversionFee = _maxConversionFee;
    }

    // ensures that the converter is active
    modifier active() {
        _active();
        _;
    }

    // error message binary size optimization
    function _active() internal view {
        require(isActive(), "ERR_INACTIVE");
    }

    // ensures that the converter is not active
    modifier inactive() {
        _inactive();
        _;
    }

    // error message binary size optimization
    function _inactive() internal view {
        require(!isActive(), "ERR_ACTIVE");
    }

    // validates a reserve token address - verifies that the address belongs to one of the reserve tokens
    modifier validReserve(IERC20Token _address) {
        _validReserve(_address);
        _;
    }

    // error message binary size optimization
    function _validReserve(IERC20Token _address) internal view {
        require(reserves[_address].isSet, "ERR_INVALID_RESERVE");
    }

    // validates conversion fee
    modifier validConversionFee(uint32 _conversionFee) {
        _validConversionFee(_conversionFee);
        _;
    }

    // error message binary size optimization
    function _validConversionFee(uint32 _conversionFee) internal pure {
        require(_conversionFee <= CONVERSION_FEE_RESOLUTION, "ERR_INVALID_CONVERSION_FEE");
    }

    // validates reserve weight
    modifier validReserveWeight(uint32 _weight) {
        _validReserveWeight(_weight);
        _;
    }

    // error message binary size optimization
    function _validReserveWeight(uint32 _weight) internal pure {
        require(_weight > 0 && _weight <= WEIGHT_RESOLUTION, "ERR_INVALID_RESERVE_WEIGHT");
    }

    /**
      * @dev deposits ether
      * can only be called if the converter has an ETH reserve
    */
    function() external payable {
        require(reserves[ETH_RESERVE_ADDRESS].isSet, "ERR_INVALID_RESERVE"); // require(hasETHReserve(), "ERR_INVALID_RESERVE");
        // a workaround for a problem when running solidity-coverage
        // see https://github.com/sc-forks/solidity-coverage/issues/487
    }

    /**
      * @dev withdraws ether
      * can only be called by the owner if the converter is inactive or by upgrader contract
      * can only be called after the upgrader contract has accepted the ownership of this contract
      * can only be called if the converter has an ETH reserve
      *
      * @param _to  address to send the ETH to
    */
    function withdrawETH(address _to)
        public
        protected
        ownerOnly
        validReserve(IERC20Token(ETH_RESERVE_ADDRESS))
    {
        address converterUpgrader = addressOf(CONVERTER_UPGRADER);

        // verify that the converter is inactive or that the owner is the upgrader contract
        require(!isActive() || owner == converterUpgrader, "ERR_ACCESS_DENIED");
        _to.transfer(address(this).balance);

        // sync the ETH reserve balance
        syncReserveBalance(IERC20Token(ETH_RESERVE_ADDRESS));
    }

    /**
      * @dev checks whether or not the converter version is 28 or higher
      *
      * @return true, since the converter version is 28 or higher
    */
    function isV28OrHigher() public pure returns (bool) {
        return true;
    }

    /**
      * @dev allows the owner to update & enable the conversion whitelist contract address
      * when set, only addresses that are whitelisted are actually allowed to use the converter
      * note that the whitelist check is actually done by the BancorNetwork contract
      *
      * @param _whitelist    address of a whitelist contract
    */
    function setConversionWhitelist(IWhitelist _whitelist)
        public
        ownerOnly
        notThis(_whitelist)
    {
        conversionWhitelist = _whitelist;
    }

    /**
      * @dev returns true if the converter is active, false otherwise
      *
      * @return true if the converter is active, false otherwise
    */
    function isActive() public view returns (bool) {
        return anchor.owner() == address(this);
    }

    /**
      * @dev transfers the anchor ownership
      * the new owner needs to accept the transfer
      * can only be called by the converter upgrder while the upgrader is the owner
      * note that prior to version 28, you should use 'transferAnchorOwnership' instead
      *
      * @param _newOwner    new token owner
    */
    function transferAnchorOwnership(address _newOwner)
        public
        ownerOnly
        only(CONVERTER_UPGRADER)
    {
        anchor.transferOwnership(_newOwner);
    }

    /**
      * @dev accepts ownership of the anchor after an ownership transfer
      * most converters are also activated as soon as they accept the anchor ownership
      * can only be called by the contract owner
      * note that prior to version 28, you should use 'acceptTokenOwnership' instead
    */
    function acceptAnchorOwnership() public ownerOnly {
        // verify the the converter has at least one reserve
        require(reserveTokenCount() > 0, "ERR_INVALID_RESERVE_COUNT");
        anchor.acceptOwnership();
        syncReserveBalances();
    }

    /**
      * @dev withdraws tokens held by the anchor and sends them to an account
      * can only be called by the owner
      *
      * @param _token   ERC20 token contract address
      * @param _to      account to receive the new amount
      * @param _amount  amount to withdraw
    */
    function withdrawFromAnchor(IERC20Token _token, address _to, uint256 _amount) public ownerOnly {
        anchor.withdrawTokens(_token, _to, _amount);
    }

    /**
      * @dev updates the current conversion fee
      * can only be called by the contract owner
      *
      * @param _conversionFee new conversion fee, represented in ppm
    */
    function setConversionFee(uint32 _conversionFee) public ownerOnly {
        require(_conversionFee <= maxConversionFee, "ERR_INVALID_CONVERSION_FEE");
        emit ConversionFeeUpdate(conversionFee, _conversionFee);
        conversionFee = _conversionFee;
    }

    /**
      * @dev withdraws tokens held by the converter and sends them to an account
      * can only be called by the owner
      * note that reserve tokens can only be withdrawn by the owner while the converter is inactive
      * unless the owner is the converter upgrader contract
      *
      * @param _token   ERC20 token contract address
      * @param _to      account to receive the new amount
      * @param _amount  amount to withdraw
    */
    function withdrawTokens(IERC20Token _token, address _to, uint256 _amount) public protected ownerOnly {
        address converterUpgrader = addressOf(CONVERTER_UPGRADER);

        // if the token is not a reserve token, allow withdrawal
        // otherwise verify that the converter is inactive or that the owner is the upgrader contract
        require(!reserves[_token].isSet || !isActive() || owner == converterUpgrader, "ERR_ACCESS_DENIED");
        super.withdrawTokens(_token, _to, _amount);

        // if the token is a reserve token, sync the reserve balance
        if (reserves[_token].isSet)
            syncReserveBalance(_token);
    }

    /**
      * @dev upgrades the converter to the latest version
      * can only be called by the owner
      * note that the owner needs to call acceptOwnership on the new converter after the upgrade
    */
    function upgrade() public ownerOnly {
        IConverterUpgrader converterUpgrader = IConverterUpgrader(addressOf(CONVERTER_UPGRADER));

        // trigger de-activation event
        emit Activation(converterType(), anchor, false);

        transferOwnership(converterUpgrader);
        converterUpgrader.upgrade(version);
        acceptOwnership();
    }

    /**
      * @dev returns the number of reserve tokens defined
      * note that prior to version 17, you should use 'connectorTokenCount' instead
      *
      * @return number of reserve tokens
    */
    function reserveTokenCount() public view returns (uint16) {
        return uint16(reserveTokens.length);
    }

    /**
      * @dev defines a new reserve token for the converter
      * can only be called by the owner while the converter is inactive
      *
      * @param _token   address of the reserve token
      * @param _weight  reserve weight, represented in ppm, 1-1000000
    */
    function addReserve(IERC20Token _token, uint32 _weight)
        public
        ownerOnly
        inactive
        validAddress(_token)
        notThis(_token)
        validReserveWeight(_weight)
    {
        // validate input
        require(_token != address(anchor) && !reserves[_token].isSet, "ERR_INVALID_RESERVE");
        require(_weight <= WEIGHT_RESOLUTION - reserveRatio, "ERR_INVALID_RESERVE_WEIGHT");
        require(reserveTokenCount() < uint16(-1), "ERR_INVALID_RESERVE_COUNT");

        Reserve storage newReserve = reserves[_token];
        newReserve.balance = 0;
        newReserve.weight = _weight;
        newReserve.isSet = true;
        reserveTokens.push(_token);
        reserveRatio += _weight;
    }

    /**
      * @dev returns the reserve's weight
      * added in version 28
      *
      * @param _reserveToken    reserve token contract address
      *
      * @return reserve weight
    */
    function reserveWeight(IERC20Token _reserveToken)
        public
        view
        validReserve(_reserveToken)
        returns (uint32)
    {
        return reserves[_reserveToken].weight;
    }

    /**
      * @dev returns the reserve's balance
      * note that prior to version 17, you should use 'getConnectorBalance' instead
      *
      * @param _reserveToken    reserve token contract address
      *
      * @return reserve balance
    */
    function reserveBalance(IERC20Token _reserveToken)
        public
        view
        validReserve(_reserveToken)
        returns (uint256)
    {
        return reserves[_reserveToken].balance;
    }

    /**
      * @dev checks whether or not the converter has an ETH reserve
      *
      * @return true if the converter has an ETH reserve, false otherwise
    */
    function hasETHReserve() public view returns (bool) {
        return reserves[ETH_RESERVE_ADDRESS].isSet;
    }

    /**
      * @dev converts a specific amount of source tokens to target tokens
      * can only be called by the bancor network contract
      *
      * @param _sourceToken source ERC20 token
      * @param _targetToken target ERC20 token
      * @param _amount      amount of tokens to convert (in units of the source token)
      * @param _trader      address of the caller who executed the conversion
      * @param _beneficiary wallet to receive the conversion result
      *
      * @return amount of tokens received (in units of the target token)
    */
    function convert(IERC20Token _sourceToken, IERC20Token _targetToken, uint256 _amount, address _trader, address _beneficiary)
        public
        payable
        protected
        only(BANCOR_NETWORK)
        returns (uint256)
    {
        // validate input
        require(_sourceToken != _targetToken, "ERR_SAME_SOURCE_TARGET");

        // if a whitelist is set, verify that both and trader and the beneficiary are whitelisted
        require(conversionWhitelist == address(0) ||
                (conversionWhitelist.isWhitelisted(_trader) && conversionWhitelist.isWhitelisted(_beneficiary)),
                "ERR_NOT_WHITELISTED");

        return doConvert(_sourceToken, _targetToken, _amount, _trader, _beneficiary);
    }

    /**
      * @dev converts a specific amount of source tokens to target tokens
      * called by ConverterBase and allows the inherited contracts to implement custom conversion logic
      *
      * @param _sourceToken source ERC20 token
      * @param _targetToken target ERC20 token
      * @param _amount      amount of tokens to convert (in units of the source token)
      * @param _trader      address of the caller who executed the conversion
      * @param _beneficiary wallet to receive the conversion result
      *
      * @return amount of tokens received (in units of the target token)
    */
    function doConvert(IERC20Token _sourceToken, IERC20Token _targetToken, uint256 _amount, address _trader, address _beneficiary) internal returns (uint256);

    /**
      * @dev returns the conversion fee for a given target amount
      *
      * @param _targetAmount  target amount
      *
      * @return conversion fee
    */
    function calculateFee(uint256 _targetAmount) internal view returns (uint256) {
        return _targetAmount.mul(conversionFee).div(CONVERSION_FEE_RESOLUTION);
    }

    /**
      * @dev syncs the stored reserve balance for a given reserve with the real reserve balance
      *
      * @param _reserveToken    address of the reserve token
    */
    function syncReserveBalance(IERC20Token _reserveToken) internal validReserve(_reserveToken) {
        if (_reserveToken == ETH_RESERVE_ADDRESS)
            reserves[_reserveToken].balance = address(this).balance;
        else
            reserves[_reserveToken].balance = _reserveToken.balanceOf(this);
    }

    /**
      * @dev syncs all stored reserve balances
    */
    function syncReserveBalances() internal {
        uint256 reserveCount = reserveTokens.length;
        for (uint256 i = 0; i < reserveCount; i++)
            syncReserveBalance(reserveTokens[i]);
    }

    /**
      * @dev helper, dispatches the Conversion event
      *
      * @param _sourceToken     source ERC20 token
      * @param _targetToken     target ERC20 token
      * @param _trader          address of the caller who executed the conversion
      * @param _amount          amount purchased/sold (in the source token)
      * @param _returnAmount    amount returned (in the target token)
    */
    function dispatchConversionEvent(
        IERC20Token _sourceToken,
        IERC20Token _targetToken,
        address _trader,
        uint256 _amount,
        uint256 _returnAmount,
        uint256 _feeAmount)
        internal
    {
        // fee amount is converted to 255 bits -
        // negative amount means the fee is taken from the source token, positive amount means its taken from the target token
        // currently the fee is always taken from the target token
        // since we convert it to a signed number, we first ensure that it's capped at 255 bits to prevent overflow
        assert(_feeAmount < 2 ** 255);
        emit Conversion(_sourceToken, _targetToken, _trader, _amount, _returnAmount, int256(_feeAmount));
    }

    /**
      * @dev deprecated since version 28, backward compatibility - use only for earlier versions
    */
    function token() public view returns (IConverterAnchor) {
        return anchor;
    }

    /**
      * @dev deprecated, backward compatibility
    */
    function transferTokenOwnership(address _newOwner) public ownerOnly {
        transferAnchorOwnership(_newOwner);
    }

    /**
      * @dev deprecated, backward compatibility
    */
    function acceptTokenOwnership() public ownerOnly {
        acceptAnchorOwnership();
    }

    /**
      * @dev deprecated, backward compatibility
    */
    function connectors(address _address) public view returns (uint256, uint32, bool, bool, bool) {
        Reserve memory reserve = reserves[_address];
        return(reserve.balance, reserve.weight, false, false, reserve.isSet);
    }

    /**
      * @dev deprecated, backward compatibility
    */
    function connectorTokens(uint256 _index) public view returns (IERC20Token) {
        return ConverterBase.reserveTokens[_index];
    }

    /**
      * @dev deprecated, backward compatibility
    */
    function connectorTokenCount() public view returns (uint16) {
        return reserveTokenCount();
    }

    /**
      * @dev deprecated, backward compatibility
    */
    function getConnectorBalance(IERC20Token _connectorToken) public view returns (uint256) {
        return reserveBalance(_connectorToken);
    }

    /**
      * @dev deprecated, backward compatibility
    */
    function getReturn(IERC20Token _sourceToken, IERC20Token _targetToken, uint256 _amount) public view returns (uint256, uint256) {
        return targetAmountAndFee(_sourceToken, _targetToken, _amount);
    }
}

// File: solidity/contracts/converter/LiquidityPoolConverter.sol

pragma solidity 0.4.26;


/**
  * @dev Liquidity Pool Converter
  *
  * The liquidity pool converter is the base contract for specific types of converters that
  * manage liquidity pools.
  *
  * Liquidity pools have 2 reserves or more and they allow converting between them.
  *
  * Note that TokenRateUpdate events are dispatched for pool tokens as well.
  * The pool token is the first token in the event in that case.
*/
contract LiquidityPoolConverter is ConverterBase {
    /**
      * @dev triggered after liquidity is added
      *
      * @param  _provider       liquidity provider
      * @param  _reserveToken   reserve token address
      * @param  _amount         reserve token amount
      * @param  _newBalance     reserve token new balance
      * @param  _newSupply      pool token new supply
    */
    event LiquidityAdded(
        address indexed _provider,
        address indexed _reserveToken,
        uint256 _amount,
        uint256 _newBalance,
        uint256 _newSupply
    );

    /**
      * @dev triggered after liquidity is removed
      *
      * @param  _provider       liquidity provider
      * @param  _reserveToken   reserve token address
      * @param  _amount         reserve token amount
      * @param  _newBalance     reserve token new balance
      * @param  _newSupply      pool token new supply
    */
    event LiquidityRemoved(
        address indexed _provider,
        address indexed _reserveToken,
        uint256 _amount,
        uint256 _newBalance,
        uint256 _newSupply
    );

    /**
      * @dev initializes a new LiquidityPoolConverter instance
      *
      * @param  _anchor             anchor governed by the converter
      * @param  _registry           address of a contract registry contract
      * @param  _maxConversionFee   maximum conversion fee, represented in ppm
    */
    constructor(
        IConverterAnchor _anchor,
        IContractRegistry _registry,
        uint32 _maxConversionFee
    )
        ConverterBase(_anchor, _registry, _maxConversionFee)
        internal
    {
    }

    /**
      * @dev accepts ownership of the anchor after an ownership transfer
      * also activates the converter
      * can only be called by the contract owner
      * note that prior to version 28, you should use 'acceptTokenOwnership' instead
    */
    function acceptAnchorOwnership() public {
        // verify that the converter has at least 2 reserves
        require(reserveTokenCount() > 1, "ERR_INVALID_RESERVE_COUNT");
        super.acceptAnchorOwnership();
    }
}

// File: solidity/contracts/converter/interfaces/IConverterFactory.sol

pragma solidity 0.4.26;





/*
    Converter Factory interface
*/
contract IConverterFactory {
    function createAnchor(uint16 _type, string _name, string _symbol, uint8 _decimals) public returns (IConverterAnchor);
    function createConverter(uint16 _type, IConverterAnchor _anchor, IContractRegistry _registry, uint32 _maxConversionFee) public returns (IConverter);

    function customFactories(uint16 _type) public view returns (ITypedConverterCustomFactory) { _type; this; }
}

// File: solidity/contracts/converter/types/liquidity-pool-v2/LiquidityPoolV2Converter.sol

pragma solidity 0.4.26;






/**
  * @dev Liquidity Pool v2 Converter
  *
  * The liquidity pool v2 converter is a specialized version of a converter that uses
  * price oracles to rebalance the reserve weights in such a way that the primary token
  * balance always strives to match the staked balance.
  *
  * This type of liquidity pool always has 2 reserves and the reserve weights are dynamic.
*/
contract LiquidityPoolV2Converter is LiquidityPoolConverter {
    uint8 internal constant AMPLIFICATION_FACTOR = 20;  // factor to use for conversion calculations (reduces slippage)

    struct Fraction {
        uint256 n;  // numerator
        uint256 d;  // denominator
    }

    IPriceOracle public priceOracle;                                // external price oracle
    IERC20Token public primaryReserveToken;                         // primary reserve in the pool
    IERC20Token public secondaryReserveToken;                       // secondary reserve in the pool (cache)
    mapping (address => uint256) private stakedBalances;            // tracks the staked liquidity in the pool plus the fees
    mapping (address => ISmartToken) private reservesToPoolTokens;  // maps each reserve to its pool token
    mapping (address => IERC20Token) private poolTokensToReserves;  // maps each pool token to its reserve

    bool public referenceRateEnabled = true;    // reference rate enable / disable flag
    Fraction public referenceRate;              // reference rate from the previous block(s) of 1 primary token in secondary tokens
    uint256 public referenceRateUpdateTime;     // last time when the reference rate was updated (in seconds)

    Fraction public lastConversionRate;         // last conversion rate of 1 primary token in secondary tokens

    // used by the temp liquidity limit mechanism during the pilot
    mapping (address => uint256) public maxStakedBalances;
    bool public maxStakedBalanceEnabled = true;

    uint256 public dynamicFeeFactor = 0; // initial dynamic fee factor is 0%, represented in ppm
    uint256 public weightSpreadFactor = 20000; // initial weight spread factor is 2%, represented in ppm
    uint256 public ratePropagationPeriod = 600 seconds; // initial time until the last rate takes full effect, represented in seconds

    /**
      * @dev triggered when the reference rate is enabled or disabled
      *
      * @param  _newState   true if enabled, false if disabled
    */
    event ReferenceRateEnabled(bool _newState);

    /**
      * @dev triggered when the dynamic fee factor is updated
      *
      * @param  _prevFactor    previous factor percentage, represented in ppm
      * @param  _newFactor     new factor percentage, represented in ppm
    */
    event DynamicFeeFactorUpdate(uint256 _prevFactor, uint256 _newFactor);

    /**
      * @dev triggered when the weight spread factor is updated
      *
      * @param  _prevFactor    previous factor percentage, represented in ppm
      * @param  _newFactor     new factor percentage, represented in ppm
    */
    event WeightSpreadFactorUpdate(uint256 _prevFactor, uint256 _newFactor);

    /**
      * @dev triggered when the rate propagation period is updated
      *
      * @param  _prevPeriod    previous time period, represented in seconds
      * @param  _newPeriod     new time period, represented in seconds
    */
    event RatePropagationPeriodUpdate(uint256 _prevPeriod, uint256 _newPeriod);

    /**
      * @dev initializes a new LiquidityPoolV2Converter instance
      *
      * @param  _poolTokensContainer    pool tokens container governed by the converter
      * @param  _registry               address of a contract registry contract
      * @param  _maxConversionFee       maximum conversion fee, represented in ppm
    */
    constructor(IPoolTokensContainer _poolTokensContainer, IContractRegistry _registry, uint32 _maxConversionFee)
        public LiquidityPoolConverter(_poolTokensContainer, _registry, _maxConversionFee)
    {
    }

    // ensures the address is a pool token
    modifier validPoolToken(ISmartToken _address) {
        _validPoolToken(_address);
        _;
    }

    // error message binary size optimization
    function _validPoolToken(ISmartToken _address) internal view {
        require(poolTokensToReserves[_address] != address(0), "ERR_INVALID_POOL_TOKEN");
    }

    /**
      * @dev returns the converter type
      *
      * @return see the converter types in the the main contract doc
    */
    function converterType() public pure returns (uint16) {
        return 2;
    }

    /**
      * @dev returns true if the converter is active, false otherwise
      *
      * @return true if the converter is active, false otherwise
    */
    function isActive() public view returns (bool) {
        return super.isActive() && priceOracle != address(0);
    }

    /**
      * @dev returns the liquidity amplification factor in the pool
      *
      * @return liquidity amplification factor
    */
    function amplificationFactor() public pure returns (uint8) {
        return AMPLIFICATION_FACTOR;
    }

    /**
      * @dev sets the pool's primary reserve token / price oracles and activates the pool
      * each oracle must be able to provide the rate for each reserve token
      * note that the oracle must be whitelisted prior to the call
      * can only be called by the owner while the pool is inactive
      *
      * @param _primaryReserveToken     address of the pool's primary reserve token
      * @param _primaryReserveOracle    address of a chainlink price oracle for the primary reserve token
      * @param _secondaryReserveOracle  address of a chainlink price oracle for the secondary reserve token
    */
    function activate(IERC20Token _primaryReserveToken, IChainlinkPriceOracle _primaryReserveOracle, IChainlinkPriceOracle _secondaryReserveOracle)
        public
        inactive
        ownerOnly
        validReserve(_primaryReserveToken)
        notThis(_primaryReserveOracle)
        notThis(_secondaryReserveOracle)
        validAddress(_primaryReserveOracle)
        validAddress(_secondaryReserveOracle)
    {
        // validate anchor ownership
        require(anchor.owner() == address(this), "ERR_ANCHOR_NOT_OWNED");

        // validate oracles
        IWhitelist oracleWhitelist = IWhitelist(addressOf(CHAINLINK_ORACLE_WHITELIST));
        require(oracleWhitelist.isWhitelisted(_primaryReserveOracle), "ERR_INVALID_ORACLE");
        require(oracleWhitelist.isWhitelisted(_secondaryReserveOracle), "ERR_INVALID_ORACLE");

        // create the converter's pool tokens if they don't already exist
        createPoolTokens();

        // sets the primary & secondary reserve tokens
        primaryReserveToken = _primaryReserveToken;
        if (_primaryReserveToken == reserveTokens[0])
            secondaryReserveToken = reserveTokens[1];
        else
            secondaryReserveToken = reserveTokens[0];

        // creates and initalizes the price oracle and sets initial rates
        LiquidityPoolV2ConverterCustomFactory customFactory =
            LiquidityPoolV2ConverterCustomFactory(IConverterFactory(addressOf(CONVERTER_FACTORY)).customFactories(converterType()));
        priceOracle = customFactory.createPriceOracle(_primaryReserveToken, secondaryReserveToken, _primaryReserveOracle, _secondaryReserveOracle);

        (referenceRate.n, referenceRate.d) = priceOracle.latestRate(primaryReserveToken, secondaryReserveToken);
        lastConversionRate = referenceRate;

        referenceRateUpdateTime = time();

        // if we are upgrading from an older converter, make sure that reserve balances are in-sync and rebalance
        uint256 primaryReserveStakedBalance = reserveStakedBalance(primaryReserveToken);
        uint256 primaryReserveBalance = reserveBalance(primaryReserveToken);
        uint256 secondaryReserveBalance = reserveBalance(secondaryReserveToken);

        if (primaryReserveStakedBalance == primaryReserveBalance) {
            if (primaryReserveStakedBalance > 0 || secondaryReserveBalance > 0) {
                rebalance();
            }
        }
        else if (primaryReserveStakedBalance > 0 && primaryReserveBalance > 0 && secondaryReserveBalance > 0) {
            rebalance();
        }

        emit Activation(converterType(), anchor, true);
    }

    /**
      * @dev enables or disables the reference rate
      * can only be called by the contract owner
      *
      * @param _referenceRateEnabled    true for enabling, false for disabling
    */
    function setReferenceRateEnabled(bool _referenceRateEnabled) public ownerOnly {
        emit ReferenceRateEnabled(_referenceRateEnabled);
        referenceRateEnabled = _referenceRateEnabled;
    }

    /**
      * @dev updates the current dynamic fee factor
      * can only be called by the contract owner
      *
      * @param _dynamicFeeFactor new dynamic fee factor, represented in ppm
    */
    function setDynamicFeeFactor(uint256 _dynamicFeeFactor) public ownerOnly {
        require(_dynamicFeeFactor <= CONVERSION_FEE_RESOLUTION, "ERR_INVALID_DYNAMIC_FEE_FACTOR");
        emit DynamicFeeFactorUpdate(dynamicFeeFactor, _dynamicFeeFactor);
        dynamicFeeFactor = _dynamicFeeFactor;
    }

    /**
      * @dev updates the current weight spread factor
      * can only be called by the contract owner
      *
      * @param _weightSpreadFactor new weight spread factor, represented in ppm
    */
    function setWeightSpreadFactor(uint256 _weightSpreadFactor) public ownerOnly {
        require(_weightSpreadFactor <= CONVERSION_FEE_RESOLUTION, "ERR_INVALID_WEIGHT_SPREAD_FACTOR");
        emit WeightSpreadFactorUpdate(weightSpreadFactor, _weightSpreadFactor);
        weightSpreadFactor = _weightSpreadFactor;
    }

    /**
      * @dev updates the current rate propagation period
      * can only be called by the contract owner
      *
      * @param _ratePropagationPeriod new rate propagation period, represented in seconds
    */
    function setRatePropagationPeriod(uint256 _ratePropagationPeriod) public ownerOnly {
        emit RatePropagationPeriodUpdate(ratePropagationPeriod, _ratePropagationPeriod);
        ratePropagationPeriod = _ratePropagationPeriod;
    }

    /**
      * @dev updates the current dynamic fee factor, the current weight spread factor and the current rate propagation period
      * can only be called by the contract owner
      *
      * @param _dynamicFeeFactor new dynamic fee factor, represented in ppm
      * @param _weightSpreadFactor new weight spread factor, represented in ppm
      * @param _ratePropagationPeriod new rate propagation period, represented in seconds
    */
    function customizeAll(uint256 _dynamicFeeFactor, uint256 _weightSpreadFactor, uint256 _ratePropagationPeriod) public ownerOnly {
        if (_dynamicFeeFactor != dynamicFeeFactor)
            setDynamicFeeFactor(_dynamicFeeFactor);
        if (_weightSpreadFactor != weightSpreadFactor)
            setWeightSpreadFactor(_weightSpreadFactor);
        if (_ratePropagationPeriod != ratePropagationPeriod)
            setRatePropagationPeriod(_ratePropagationPeriod);
    }

    /**
      * @dev returns the staked balance of a given reserve token
      *
      * @param _reserveToken    reserve token address
      *
      * @return staked balance
    */
    function reserveStakedBalance(IERC20Token _reserveToken)
        public
        view
        validReserve(_reserveToken)
        returns (uint256)
    {
        return stakedBalances[_reserveToken];
    }

    /**
      * @dev returns the amplified balance of a given reserve token
      *
      * @param _reserveToken   reserve token address
      *
      * @return amplified balance
    */
    function reserveAmplifiedBalance(IERC20Token _reserveToken)
        public
        view
        validReserve(_reserveToken)
        returns (uint256)
    {
        return stakedBalances[_reserveToken].mul(AMPLIFICATION_FACTOR - 1).add(reserveBalance(_reserveToken));
    }

    /**
      * @dev sets the reserve's staked balance
      * can only be called by the upgrader contract while the upgrader is the owner
      *
      * @param _reserveToken    reserve token address
      * @param _balance         new reserve staked balance
    */
    function setReserveStakedBalance(IERC20Token _reserveToken, uint256 _balance)
        public
        ownerOnly
        only(CONVERTER_UPGRADER)
        validReserve(_reserveToken)
    {
        stakedBalances[_reserveToken] = _balance;
    }

    /**
      * @dev sets the max staked balance for both reserves
      * available as a temporary mechanism during the pilot
      * can only be called by the owner
      *
      * @param _reserve1MaxStakedBalance    max staked balance for reserve 1
      * @param _reserve2MaxStakedBalance    max staked balance for reserve 2
    */
    function setMaxStakedBalances(uint256 _reserve1MaxStakedBalance, uint256 _reserve2MaxStakedBalance) public ownerOnly {
        maxStakedBalances[reserveTokens[0]] = _reserve1MaxStakedBalance;
        maxStakedBalances[reserveTokens[1]] = _reserve2MaxStakedBalance;
    }

    /**
      * @dev disables the max staked balance mechanism
      * available as a temporary mechanism during the pilot
      * once disabled, it cannot be re-enabled
      * can only be called by the owner
    */
    function disableMaxStakedBalances() public ownerOnly {
        maxStakedBalanceEnabled = false;
    }

    /**
      * @dev returns the pool token address by the reserve token address
      *
      * @param _reserveToken    reserve token address
      *
      * @return pool token address
    */
    function poolToken(IERC20Token _reserveToken) public view returns (ISmartToken) {
        return reservesToPoolTokens[_reserveToken];
    }

    /**
      * @dev returns the maximum number of pool tokens that can currently be liquidated
      *
      * @param _poolToken   address of the pool token
      *
      * @return liquidation limit
    */
    function liquidationLimit(ISmartToken _poolToken) public view returns (uint256) {
        // get the pool token supply
        uint256 poolTokenSupply = _poolToken.totalSupply();

        // get the reserve token associated with the pool token and its balance / staked balance
        IERC20Token reserveToken = poolTokensToReserves[_poolToken];
        uint256 balance = reserveBalance(reserveToken);
        uint256 stakedBalance = stakedBalances[reserveToken];

        // calculate the amount that's available for liquidation
        return balance.mul(poolTokenSupply).div(stakedBalance);
    }

    /**
      * @dev defines a new reserve token for the converter
      * can only be called by the owner while the converter is inactive and
      * 2 reserves aren't defined yet
      *
      * @param _token   address of the reserve token
      * @param _weight  reserve weight, represented in ppm, 1-1000000
    */
    function addReserve(IERC20Token _token, uint32 _weight) public {
        // verify that the converter doesn't have 2 reserves yet
        require(reserveTokenCount() < 2, "ERR_INVALID_RESERVE_COUNT");
        super.addReserve(_token, _weight);
    }

    /**
      * @dev returns the effective rate of 1 primary token in secondary tokens
      *
      * @return rate of 1 primary token in secondary tokens (numerator)
      * @return rate of 1 primary token in secondary tokens (denominator)
    */
    function effectiveTokensRate() public view returns (uint256, uint256) {
        Fraction memory rate = _effectiveTokensRate();
        return (rate.n, rate.d);
    }

    /**
      * @dev returns the effective reserve tokens weights
      *
      * @return reserve1 weight
      * @return reserve2 weight
    */
    function effectiveReserveWeights() public view returns (uint256, uint256) {
        Fraction memory rate = _effectiveTokensRate();
        (uint32 primaryReserveWeight, uint32 secondaryReserveWeight) = effectiveReserveWeights(rate);

        if (primaryReserveToken == reserveTokens[0]) {
            return (primaryReserveWeight, secondaryReserveWeight);
        }

        return (secondaryReserveWeight, primaryReserveWeight);
    }

    /**
      * @dev returns the expected target amount of converting one reserve to another along with the fee
      *
      * @param _sourceToken contract address of the source reserve token
      * @param _targetToken contract address of the target reserve token
      * @param _amount      amount of tokens received from the user
      *
      * @return expected target amount
      * @return expected fee
    */
    function targetAmountAndFee(IERC20Token _sourceToken, IERC20Token _targetToken, uint256 _amount)
        public
        view
        active
        returns (uint256, uint256)
    {
        // validate input
        // not using the `validReserve` modifier to circumvent `stack too deep` compiler error
        _validReserve(_sourceToken);
        _validReserve(_targetToken);
        require(_sourceToken != _targetToken, "ERR_SAME_SOURCE_TARGET");

        // check if rebalance is required (some of this code is duplicated for gas optimization)
        uint32 sourceTokenWeight;
        uint32 targetTokenWeight;

        // if the rate was already checked in this block, use the current weights.
        // otherwise, get the new weights
        Fraction memory rate;
        if (referenceRateUpdateTime == time()) {
            rate = referenceRate;
            sourceTokenWeight = reserves[_sourceToken].weight;
            targetTokenWeight = reserves[_targetToken].weight;
        }
        else {
            // get the new rate / reserve weights
            rate = _effectiveTokensRate();
            (uint32 primaryReserveWeight, uint32 secondaryReserveWeight) = effectiveReserveWeights(rate);

            if (_sourceToken == primaryReserveToken) {
                sourceTokenWeight = primaryReserveWeight;
                targetTokenWeight = secondaryReserveWeight;
            }
            else {
                sourceTokenWeight = secondaryReserveWeight;
                targetTokenWeight = primaryReserveWeight;
            }
        }

        // return the target amount and the conversion fee using the updated reserve weights
        (uint256 targetAmount, , uint256 fee) = targetAmountAndFees(_sourceToken, _targetToken, sourceTokenWeight, targetTokenWeight, rate, _amount);
        return (targetAmount, fee);
    }

    /**
      * @dev converts a specific amount of source tokens to target tokens
      * can only be called by the bancor network contract
      *
      * @param _sourceToken source ERC20 token
      * @param _targetToken target ERC20 token
      * @param _amount      amount of tokens to convert (in units of the source token)
      * @param _trader      address of the caller who executed the conversion
      * @param _beneficiary wallet to receive the conversion result
      *
      * @return amount of tokens received (in units of the target token)
    */
    function doConvert(IERC20Token _sourceToken, IERC20Token _targetToken, uint256 _amount, address _trader, address _beneficiary)
        internal
        active
        validReserve(_sourceToken)
        validReserve(_targetToken)
        returns (uint256)
    {
        // convert the amount and return the resulted amount and fee
        (uint256 amount, uint256 fee) = doConvert(_sourceToken, _targetToken, _amount);

        // transfer funds to the beneficiary in the to reserve token
        if (_targetToken == ETH_RESERVE_ADDRESS) {
            _beneficiary.transfer(amount);
        }
        else {
            safeTransfer(_targetToken, _beneficiary, amount);
        }

        // dispatch the conversion event
        dispatchConversionEvent(_sourceToken, _targetToken, _trader, _amount, amount, fee);

        // dispatch rate updates for the pool / reserve tokens
        dispatchRateEvents(_sourceToken, _targetToken, reserves[_sourceToken].weight, reserves[_targetToken].weight);

        // return the conversion result amount
        return amount;
    }

    /**
      * @dev converts a specific amount of source tokens to target tokens
      * can only be called by the bancor network contract
      *
      * @param _sourceToken source ERC20 token
      * @param _targetToken target ERC20 token
      * @param _amount      amount of tokens to convert (in units of the source token)
      *
      * @return amount of tokens received (in units of the target token)
      * @return expected fee
    */
    function doConvert(IERC20Token _sourceToken, IERC20Token _targetToken, uint256 _amount) private returns (uint256, uint256) {
        // check if the rate has changed and rebalance the pool if needed (once in a block)
        (bool rateUpdated, Fraction memory rate) = handleRateChange();

        // get expected target amount and fees
        (uint256 amount, uint256 standardFee, uint256 dynamicFee) = targetAmountAndFees(_sourceToken, _targetToken, 0, 0, rate, _amount);

        // ensure that the trade gives something in return
        require(amount != 0, "ERR_ZERO_TARGET_AMOUNT");

        // ensure that the trade won't deplete the reserve balance
        uint256 targetReserveBalance = reserveBalance(_targetToken);
        require(amount < targetReserveBalance, "ERR_TARGET_AMOUNT_TOO_HIGH");

        // ensure that the input amount was already deposited
        if (_sourceToken == ETH_RESERVE_ADDRESS)
            require(msg.value == _amount, "ERR_ETH_AMOUNT_MISMATCH");
        else
            require(msg.value == 0 && _sourceToken.balanceOf(this).sub(reserveBalance(_sourceToken)) >= _amount, "ERR_INVALID_AMOUNT");

        // sync the reserve balances
        syncReserveBalance(_sourceToken);
        reserves[_targetToken].balance = targetReserveBalance.sub(amount);

        // update the target staked balance with the fee
        stakedBalances[_targetToken] = stakedBalances[_targetToken].add(standardFee);

        // update the last conversion rate
        if (rateUpdated) {
            lastConversionRate = tokensRate(primaryReserveToken, secondaryReserveToken, 0, 0);
        }

        return (amount, dynamicFee);
    }

    /**
      * @dev increases the pool's liquidity and mints new shares in the pool to the caller
      *
      * @param _reserveToken    address of the reserve token to add liquidity to
      * @param _amount          amount of liquidity to add
      * @param _minReturn       minimum return-amount of pool tokens
      *
      * @return amount of pool tokens minted
    */
    function addLiquidity(IERC20Token _reserveToken, uint256 _amount, uint256 _minReturn)
        public
        payable
        protected
        active
        validReserve(_reserveToken)
        greaterThanZero(_amount)
        greaterThanZero(_minReturn)
        returns (uint256)
    {
        // verify that msg.value is identical to the provided amount for ETH reserve, or 0 otherwise
        require(_reserveToken == ETH_RESERVE_ADDRESS ? msg.value == _amount : msg.value == 0, "ERR_ETH_AMOUNT_MISMATCH");

        // sync the reserve balances just in case
        syncReserveBalances();

        // for ETH reserve, deduct the amount that was just synced (since it's already in the converter)
        if (_reserveToken == ETH_RESERVE_ADDRESS)
            reserves[ETH_RESERVE_ADDRESS].balance = reserves[ETH_RESERVE_ADDRESS].balance.sub(msg.value);

        // get the reserve staked balance before adding the liquidity to it
        uint256 initialStakedBalance = stakedBalances[_reserveToken];

        // during the pilot, ensure that the new staked balance isn't greater than the max limit
        if (maxStakedBalanceEnabled) {
            require(maxStakedBalances[_reserveToken] == 0 || initialStakedBalance.add(_amount) <= maxStakedBalances[_reserveToken], "ERR_MAX_STAKED_BALANCE_REACHED");
        }

        // get the pool token associated with the reserve and its supply
        ISmartToken reservePoolToken = reservesToPoolTokens[_reserveToken];
        uint256 poolTokenSupply = reservePoolToken.totalSupply();

        // for non ETH reserve, transfer the funds from the user to the pool
        if (_reserveToken != ETH_RESERVE_ADDRESS)
            safeTransferFrom(_reserveToken, msg.sender, this, _amount);

        // sync the reserve balance / staked balance
        reserves[_reserveToken].balance = reserves[_reserveToken].balance.add(_amount);
        stakedBalances[_reserveToken] = initialStakedBalance.add(_amount);

        // calculate how many pool tokens to mint
        // for an empty pool, the price is 1:1, otherwise the price is based on the ratio
        // between the pool token supply and the staked balance
        uint256 poolTokenAmount = 0;
        if (initialStakedBalance == 0 || poolTokenSupply == 0)
            poolTokenAmount = _amount;
        else
            poolTokenAmount = _amount.mul(poolTokenSupply).div(initialStakedBalance);
        require(poolTokenAmount >= _minReturn, "ERR_RETURN_TOO_LOW");

        // mint new pool tokens to the caller
        IPoolTokensContainer(anchor).mint(reservePoolToken, msg.sender, poolTokenAmount);

        // rebalance the pool's reserve weights
        rebalance();

        // dispatch the LiquidityAdded event
        emit LiquidityAdded(msg.sender, _reserveToken, _amount, initialStakedBalance.add(_amount), poolTokenSupply.add(poolTokenAmount));

        // dispatch the `TokenRateUpdate` event for the pool token
        dispatchPoolTokenRateUpdateEvent(reservePoolToken, poolTokenSupply.add(poolTokenAmount), _reserveToken);

        // dispatch the `TokenRateUpdate` event for the reserve tokens
        dispatchTokenRateUpdateEvent(reserveTokens[0], reserveTokens[1], 0, 0);

        // return the amount of pool tokens minted
        return poolTokenAmount;
    }

    /**
      * @dev decreases the pool's liquidity and burns the caller's shares in the pool
      *
      * @param _poolToken   address of the pool token
      * @param _amount      amount of pool tokens to burn
      * @param _minReturn   minimum return-amount of reserve tokens
      *
      * @return amount of liquidity removed
    */
    function removeLiquidity(ISmartToken _poolToken, uint256 _amount, uint256 _minReturn)
        public
        protected
        active
        validPoolToken(_poolToken)
        greaterThanZero(_amount)
        greaterThanZero(_minReturn)
        returns (uint256)
    {
        // sync the reserve balances just in case
        syncReserveBalances();

        // get the pool token supply before burning the caller's shares
        uint256 initialPoolSupply = _poolToken.totalSupply();

        // get the reserve token return before burning the caller's shares
        (uint256 reserveAmount, ) = removeLiquidityReturnAndFee(_poolToken, _amount);
        require(reserveAmount >= _minReturn, "ERR_RETURN_TOO_LOW");

        // get the reserve token associated with the pool token
        IERC20Token reserveToken = poolTokensToReserves[_poolToken];

        // burn the caller's pool tokens
        IPoolTokensContainer(anchor).burn(_poolToken, msg.sender, _amount);

        // sync the reserve balance / staked balance
        reserves[reserveToken].balance = reserves[reserveToken].balance.sub(reserveAmount);
        uint256 newStakedBalance = stakedBalances[reserveToken].sub(reserveAmount);
        stakedBalances[reserveToken] = newStakedBalance;

        // transfer the reserve amount to the caller
        if (reserveToken == ETH_RESERVE_ADDRESS)
            msg.sender.transfer(reserveAmount);
        else
            safeTransfer(reserveToken, msg.sender, reserveAmount);

        // rebalance the pool's reserve weights
        rebalance();

        uint256 newPoolTokenSupply = initialPoolSupply.sub(_amount);

        // dispatch the LiquidityRemoved event
        emit LiquidityRemoved(msg.sender, reserveToken, reserveAmount, newStakedBalance, newPoolTokenSupply);

        // dispatch the `TokenRateUpdate` event for the pool token
        dispatchPoolTokenRateUpdateEvent(_poolToken, newPoolTokenSupply, reserveToken);

        // dispatch the `TokenRateUpdate` event for the reserve tokens
        dispatchTokenRateUpdateEvent(reserveTokens[0], reserveTokens[1], 0, 0);

        // return the amount of liquidity removed
        return reserveAmount;
    }

    /**
      * @dev calculates the amount of reserve tokens entitled for a given amount of pool tokens
      * note that a fee is applied according to the equilibrium level of the primary reserve token
      *
      * @param _poolToken   address of the pool token
      * @param _amount      amount of pool tokens
      *
      * @return amount after fee and fee, in reserve token units
    */
    function removeLiquidityReturnAndFee(ISmartToken _poolToken, uint256 _amount)
        public
        view
        returns (uint256, uint256)
    {
        uint256 totalSupply = _poolToken.totalSupply();
        uint256 stakedBalance = stakedBalances[poolTokensToReserves[_poolToken]];

        if (_amount < totalSupply) {
            uint256 x = stakedBalances[primaryReserveToken].mul(AMPLIFICATION_FACTOR);
            uint256 y = reserveAmplifiedBalance(primaryReserveToken);
            (uint256 min, uint256 max) = x < y ? (x, y) : (y, x);
            uint256 amountBeforeFee = _amount.mul(stakedBalance).div(totalSupply);
            uint256 amountAfterFee = amountBeforeFee.mul(min).div(max);
            return (amountAfterFee, amountBeforeFee - amountAfterFee);
        }
        return (stakedBalance, 0);
    }

    /**
      * @dev returns the expected target amount of converting one reserve to another along with the fees
      * this version of the function expects the reserve weights as an input (gas optimization)
      *
      * @param _sourceToken     contract address of the source reserve token
      * @param _targetToken     contract address of the target reserve token
      * @param _sourceWeight    source reserve token weight or 0 to read it from storage
      * @param _targetWeight    target reserve token weight or 0 to read it from storage
      * @param _rate            rate between the reserve tokens
      * @param _amount          amount of tokens received from the user
      *
      * @return expected target amount
      * @return expected standard conversion fee
      * @return expected dynamic conversion fee
    */
    function targetAmountAndFees(
        IERC20Token _sourceToken,
        IERC20Token _targetToken,
        uint32 _sourceWeight,
        uint32 _targetWeight,
        Fraction memory _rate,
        uint256 _amount)
        private
        view
        returns (uint256 targetAmount, uint256 standardFee, uint256 dynamicFee)
    {
        if (_sourceWeight == 0)
            _sourceWeight = reserves[_sourceToken].weight;
        if (_targetWeight == 0)
            _targetWeight = reserves[_targetToken].weight;

        // get the tokens amplified balances
        uint256 sourceBalance = reserveAmplifiedBalance(_sourceToken);
        uint256 targetBalance = reserveAmplifiedBalance(_targetToken);

        // get the weight spread
        uint32 weightSpread = uint32(uint256(_sourceWeight) * weightSpreadFactor / CONVERSION_FEE_RESOLUTION);

        // get the target amount
        targetAmount = IBancorFormula(addressOf(BANCOR_FORMULA)).crossReserveTargetAmount(
            sourceBalance,
            _sourceWeight - weightSpread,
            targetBalance,
            _targetWeight + weightSpread,
            _amount
        );

        // return a tuple of [target amount minus dynamic conversion fee, standard conversion fee, dynamic conversion fee]
        standardFee = calculateFee(targetAmount);
        dynamicFee = calculateDynamicFee(_targetToken, _sourceWeight, _targetWeight, _rate, targetAmount).add(standardFee);
        targetAmount = targetAmount.sub(dynamicFee);
    }

    /**
      * @dev returns the dynamic fee for a given target amount
      *
      * @param _targetToken     contract address of the target reserve token
      * @param _sourceWeight    source reserve token weight
      * @param _targetWeight    target reserve token weight
      * @param _rate            rate of 1 primary token in secondary tokens
      * @param _targetAmount    target amount
      *
      * @return dynamic fee
    */
    function calculateDynamicFee(
        IERC20Token _targetToken,
        uint32 _sourceWeight,
        uint32 _targetWeight,
        Fraction memory _rate,
        uint256 _targetAmount)
        internal view returns (uint256)
    {
        uint256 fee;

        if (_targetToken == secondaryReserveToken) {
            fee = calculateFeeToEquilibrium(
                stakedBalances[primaryReserveToken],
                stakedBalances[secondaryReserveToken],
                _sourceWeight,
                _targetWeight,
                _rate.n,
                _rate.d,
                dynamicFeeFactor);
        }
        else {
            fee = calculateFeeToEquilibrium(
                stakedBalances[primaryReserveToken],
                stakedBalances[secondaryReserveToken],
                _targetWeight,
                _sourceWeight,
                _rate.n,
                _rate.d,
                dynamicFeeFactor);
        }

        return _targetAmount.mul(fee).div(CONVERSION_FEE_RESOLUTION);
    }

    /**
      * @dev returns the relative fee required for mitigating the secondary reserve distance from equilibrium
      *
      * @param _primaryReserveStaked    primary reserve staked balance
      * @param _secondaryReserveStaked  secondary reserve staked balance
      * @param _primaryReserveWeight    primary reserve weight
      * @param _secondaryReserveWeight  secondary reserve weight
      * @param _primaryReserveRate      primary reserve rate
      * @param _secondaryReserveRate    secondary reserve rate
      * @param _dynamicFeeFactor        dynamic fee factor
      *
      * @return relative fee, represented in ppm
    */
    function calculateFeeToEquilibrium(
        uint256 _primaryReserveStaked,
        uint256 _secondaryReserveStaked,
        uint256 _primaryReserveWeight,
        uint256 _secondaryReserveWeight,
        uint256 _primaryReserveRate,
        uint256 _secondaryReserveRate,
        uint256 _dynamicFeeFactor)
        internal
        pure
        returns (uint256)
    {
        uint256 x = _primaryReserveStaked.mul(_primaryReserveRate).mul(_secondaryReserveWeight);
        uint256 y = _secondaryReserveStaked.mul(_secondaryReserveRate).mul(_primaryReserveWeight);
        if (y > x)
            return (y - x).mul(_dynamicFeeFactor).mul(AMPLIFICATION_FACTOR).div(y);
        return 0;
    }

    /**
      * @dev creates the converter's pool tokens
      * note that technically pool tokens can be created on deployment but gas limit
      * might get too high for a block, so creating them on first activation
      *
    */
    function createPoolTokens() internal {
        IPoolTokensContainer container = IPoolTokensContainer(anchor);
        ISmartToken[] memory poolTokens = container.poolTokens();
        bool initialSetup = poolTokens.length == 0;

        uint256 reserveCount = reserveTokens.length;
        for (uint256 i = 0; i < reserveCount; i++) {
            ISmartToken reservePoolToken;
            if (initialSetup) {
                reservePoolToken = container.createToken();
            }
            else {
                reservePoolToken = poolTokens[i];
            }

            // cache the pool token address (gas optimization)
            reservesToPoolTokens[reserveTokens[i]] = reservePoolToken;
            poolTokensToReserves[reservePoolToken] = reserveTokens[i];
        }
    }

    /**
      * @dev returns the effective rate between the two reserve tokens
      *
      * @return rate
    */
    function _effectiveTokensRate() private view returns (Fraction memory) {
        // get the external rate between the reserves
        (uint256 externalRateN, uint256 externalRateD, uint256 updateTime) = priceOracle.latestRateAndUpdateTime(primaryReserveToken, secondaryReserveToken);

        // if the reference rate is not enabled or the external rate was recently updated - prefer it over the internal rate
        if (!referenceRateEnabled || updateTime > referenceRateUpdateTime) {
            return Fraction({ n: externalRateN, d: externalRateD });
        }

        // get the elapsed time between the current and the last conversion
        uint256 timeElapsed = time() - referenceRateUpdateTime;

        // if both of the conversions are in the same block - use the reference rate
        if (timeElapsed == 0) {
            return referenceRate;
        }

        // given N as the sampling window, the new internal rate is calculated according to the following formula:
        //   newRate = referenceRate + timeElapsed * [lastConversionRate - referenceRate] / N

        // if a long period of time, since the last update, has passed - the last rate should fully take effect
        if (timeElapsed >= ratePropagationPeriod) {
            return lastConversionRate;
        }

        // calculate the numerator and the denumerator of the new rate
        Fraction memory ref = referenceRate;
        Fraction memory last = lastConversionRate;

        uint256 x = ref.d.mul(last.n);
        uint256 y = ref.n.mul(last.d);

        // since we know that timeElapsed < ratePropagationPeriod, we can avoid using SafeMath:
        uint256 newRateN = y.mul(ratePropagationPeriod - timeElapsed).add(x.mul(timeElapsed));
        uint256 newRateD = ref.d.mul(last.d).mul(ratePropagationPeriod);

        return reduceRate(newRateN, newRateD);
    }

    /**
      * @dev checks if the rate has changed and if so, rebalances the weights
      * note that rebalancing based on rate change only happens once per block
      *
      * @return whether the rate was updated
      * @return rate between the reserve tokens
    */
    function handleRateChange() private returns (bool, Fraction memory) {
        uint256 currentTime = time();

        // avoid updating the rate more than once per block
        if (referenceRateUpdateTime == currentTime) {
            return (false, referenceRate);
        }

        // get and store the effective rate between the reserves
        Fraction memory newRate = _effectiveTokensRate();

        // if the rate has changed, update it and rebalance the pool
        Fraction memory ref = referenceRate;
        if (newRate.n == ref.n && newRate.d == ref.d) {
            return (false, newRate);
        }

        referenceRate = newRate;
        referenceRateUpdateTime = currentTime;

        rebalance();

        return (true, newRate);
    }

    /**
      * @dev updates the pool's reserve weights with new values in order to push the current primary
      * reserve token balance to its staked balance
    */
    function rebalance() private {
        // get the new reserve weights
        (uint32 primaryReserveWeight, uint32 secondaryReserveWeight) = effectiveReserveWeights(referenceRate);

        // update the reserve weights with the new values
        reserves[primaryReserveToken].weight = primaryReserveWeight;
        reserves[secondaryReserveToken].weight = secondaryReserveWeight;
    }

    /**
      * @dev returns the effective reserve weights based on the staked balance, current balance and oracle price
      *
      * @param _rate    rate between the reserve tokens
      *
      * @return new primary reserve weight
      * @return new secondary reserve weight
    */
    function effectiveReserveWeights(Fraction memory _rate) private view returns (uint32, uint32) {
        // get the primary reserve staked balance
        uint256 primaryStakedBalance = stakedBalances[primaryReserveToken];

        // get the tokens amplified balances
        uint256 primaryBalance = reserveAmplifiedBalance(primaryReserveToken);
        uint256 secondaryBalance = reserveAmplifiedBalance(secondaryReserveToken);

        // get the new weights
        return IBancorFormula(addressOf(BANCOR_FORMULA)).balancedWeights(
            primaryStakedBalance.mul(AMPLIFICATION_FACTOR),
            primaryBalance,
            secondaryBalance,
            _rate.n,
            _rate.d);
    }

    /**
      * @dev calculates and returns the rate between two reserve tokens
      *
      * @param _token1          contract address of the token to calculate the rate of one unit of
      * @param _token2          contract address of the token to calculate the rate of one `_token1` unit in
      * @param _token1Weight    reserve weight of token1
      * @param _token2Weight    reserve weight of token2
      *
      * @return rate
    */
    function tokensRate(IERC20Token _token1, IERC20Token _token2, uint32 _token1Weight, uint32 _token2Weight) private view returns (Fraction memory) {
        // apply the amplification factor
        uint256 token1Balance = reserveAmplifiedBalance(_token1);
        uint256 token2Balance = reserveAmplifiedBalance(_token2);

        // get reserve weights
        if (_token1Weight == 0) {
            _token1Weight = reserves[_token1].weight;
        }

        if (_token2Weight == 0) {
            _token2Weight = reserves[_token2].weight;
        }

        return Fraction({ n: token2Balance.mul(_token1Weight), d: token1Balance.mul(_token2Weight) });
    }

    /**
      * @dev dispatches rate events for both reserve tokens and for the target pool token
      * only used to circumvent the `stack too deep` compiler error
      *
      * @param _sourceToken     contract address of the source reserve token
      * @param _targetToken     contract address of the target reserve token
      * @param _sourceWeight    source reserve token weight
      * @param _targetWeight    target reserve token weight
    */
    function dispatchRateEvents(IERC20Token _sourceToken, IERC20Token _targetToken, uint32 _sourceWeight, uint32 _targetWeight) private {
        dispatchTokenRateUpdateEvent(_sourceToken, _targetToken, _sourceWeight, _targetWeight);

        // dispatch the `TokenRateUpdate` event for the pool token
        // the target reserve pool token rate is the only one that's affected
        // by conversions since conversion fees are applied to the target reserve
        ISmartToken targetPoolToken = poolToken(_targetToken);
        uint256 targetPoolTokenSupply = targetPoolToken.totalSupply();
        dispatchPoolTokenRateUpdateEvent(targetPoolToken, targetPoolTokenSupply, _targetToken);
    }

    /**
      * @dev dispatches token rate update event
      * only used to circumvent the `stack too deep` compiler error
      *
      * @param _token1          contract address of the token to calculate the rate of one unit of
      * @param _token2          contract address of the token to calculate the rate of one `_token1` unit in
      * @param _token1Weight    reserve weight of token1
      * @param _token2Weight    reserve weight of token2
    */
    function dispatchTokenRateUpdateEvent(IERC20Token _token1, IERC20Token _token2, uint32 _token1Weight, uint32 _token2Weight) private {
        // dispatch token rate update event
        Fraction memory rate = tokensRate(_token1, _token2, _token1Weight, _token2Weight);

        emit TokenRateUpdate(_token1, _token2, rate.n, rate.d);
    }

    /**
      * @dev dispatches the `TokenRateUpdate` for the pool token
      * only used to circumvent the `stack too deep` compiler error
      *
      * @param _poolToken       address of the pool token
      * @param _poolTokenSupply total pool token supply
      * @param _reserveToken    address of the reserve token
    */
    function dispatchPoolTokenRateUpdateEvent(ISmartToken _poolToken, uint256 _poolTokenSupply, IERC20Token _reserveToken) private {
        emit TokenRateUpdate(_poolToken, _reserveToken, stakedBalances[_reserveToken], _poolTokenSupply);
    }

    /**
      * @dev returns the current time
    */
    function time() internal view returns (uint256) {
        return now;
    }

    uint256 private constant MAX_RATE_FACTOR_LOWER_BOUND = 1e30;
    uint256 private constant MAX_RATE_FACTOR_UPPER_BOUND = uint256(-1) / MAX_RATE_FACTOR_LOWER_BOUND;

    /**
      * @dev reduces the numerator and denominator while maintaining the ratio between them as accurately as possible
    */
    function reduceRate(uint256 _n, uint256 _d) internal pure returns (Fraction memory) {
        if (_n >= _d) {
            return reduceFactors(_n, _d);
        }

        Fraction memory rate = reduceFactors(_d, _n);
        return Fraction({ n: rate.d, d: rate.n });
    }

    /**
      * @dev reduces the factors while maintaining the ratio between them as accurately as possible
    */
    function reduceFactors(uint256 _max, uint256 _min) internal pure returns (Fraction memory) {
        if (_min > MAX_RATE_FACTOR_UPPER_BOUND) {
            return Fraction({
                n: MAX_RATE_FACTOR_LOWER_BOUND,
                d: _min / (_max / MAX_RATE_FACTOR_LOWER_BOUND)
            });
        }

        if (_max > MAX_RATE_FACTOR_LOWER_BOUND) {
            return Fraction({
                n: MAX_RATE_FACTOR_LOWER_BOUND,
                d: _min * MAX_RATE_FACTOR_LOWER_BOUND / _max
            });
        }

        return Fraction({ n: _max, d: _min });
    }
}

Contract Security Audit

Contract ABI

[{"constant":true,"inputs":[{"name":"_reserveToken","type":"address"}],"name":"reserveStakedBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_onlyOwnerCanUpdateRegistry","type":"bool"}],"name":"restrictRegistryUpdate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"primaryReserveToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxStakedBalanceEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"reserveRatio","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"}],"name":"connectors","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint32"},{"name":"","type":"bool"},{"name":"","type":"bool"},{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_primaryReserveToken","type":"address"},{"name":"_primaryReserveOracle","type":"address"},{"name":"_secondaryReserveOracle","type":"address"}],"name":"activate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hasETHReserve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"disableMaxStakedBalances","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_index","type":"uint256"}],"name":"connectorTokens","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_reserveToken","type":"address"}],"name":"reserveWeight","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_sourceToken","type":"address"},{"name":"_targetToken","type":"address"},{"name":"_amount","type":"uint256"}],"name":"getReturn","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferTokenOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"priceOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_reserveToken","type":"address"}],"name":"reserveAmplifiedBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_poolToken","type":"address"}],"name":"liquidationLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"onlyOwnerCanUpdateRegistry","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"referenceRateEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptTokenOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"withdrawFromAnchor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"converterType","outputs":[{"name":"","type":"uint16"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_dynamicFeeFactor","type":"uint256"},{"name":"_weightSpreadFactor","type":"uint256"},{"name":"_ratePropagationPeriod","type":"uint256"}],"name":"customizeAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_reserve1MaxStakedBalance","type":"uint256"},{"name":"_reserve2MaxStakedBalance","type":"uint256"}],"name":"setMaxStakedBalances","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"updateRegistry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_whitelist","type":"address"}],"name":"setConversionWhitelist","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"weightSpreadFactor","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reserveToken","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_minReturn","type":"uint256"}],"name":"addLiquidity","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_reserveToken","type":"address"}],"name":"poolToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"conversionFee","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_weightSpreadFactor","type":"uint256"}],"name":"setWeightSpreadFactor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"withdrawTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_ratePropagationPeriod","type":"uint256"}],"name":"setRatePropagationPeriod","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"prevRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferAnchorOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_poolToken","type":"address"},{"name":"_amount","type":"uint256"}],"name":"removeLiquidityReturnAndFee","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"}],"name":"withdrawETH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_dynamicFeeFactor","type":"uint256"}],"name":"setDynamicFeeFactor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_weight","type":"uint32"}],"name":"addReserve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"connectorTokenCount","outputs":[{"name":"","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"registry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxConversionFee","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"maxStakedBalances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ratePropagationPeriod","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"reserveTokenCount","outputs":[{"name":"","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"referenceRate","outputs":[{"name":"n","type":"uint256"},{"name":"d","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_sourceToken","type":"address"},{"name":"_targetToken","type":"address"},{"name":"_amount","type":"uint256"}],"name":"targetAmountAndFee","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"restoreRegistry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"conversionsEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reserveToken","type":"address"},{"name":"_balance","type":"uint256"}],"name":"setReserveStakedBalance","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"referenceRateUpdateTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"conversionWhitelist","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptAnchorOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"reserveTokens","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isV28OrHigher","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"anchor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"newOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"upgrade","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"amplificationFactor","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"reserves","outputs":[{"name":"balance","type":"uint256"},{"name":"weight","type":"uint32"},{"name":"deprecated1","type":"bool"},{"name":"deprecated2","type":"bool"},{"name":"isSet","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referenceRateEnabled","type":"bool"}],"name":"setReferenceRateEnabled","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_connectorToken","type":"address"}],"name":"getConnectorBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"effectiveTokensRate","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"secondaryReserveToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_reserveToken","type":"address"}],"name":"reserveBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_poolToken","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_minReturn","type":"uint256"}],"name":"removeLiquidity","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"dynamicFeeFactor","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sourceToken","type":"address"},{"name":"_targetToken","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_trader","type":"address"},{"name":"_beneficiary","type":"address"}],"name":"convert","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"effectiveReserveWeights","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_conversionFee","type":"uint32"}],"name":"setConversionFee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"lastConversionRate","outputs":[{"name":"n","type":"uint256"},{"name":"d","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_poolTokensContainer","type":"address"},{"name":"_registry","type":"address"},{"name":"_maxConversionFee","type":"uint32"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_newState","type":"bool"}],"name":"ReferenceRateEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_prevFactor","type":"uint256"},{"indexed":false,"name":"_newFactor","type":"uint256"}],"name":"DynamicFeeFactorUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_prevFactor","type":"uint256"},{"indexed":false,"name":"_newFactor","type":"uint256"}],"name":"WeightSpreadFactorUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_prevPeriod","type":"uint256"},{"indexed":false,"name":"_newPeriod","type":"uint256"}],"name":"RatePropagationPeriodUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_provider","type":"address"},{"indexed":true,"name":"_reserveToken","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"},{"indexed":false,"name":"_newBalance","type":"uint256"},{"indexed":false,"name":"_newSupply","type":"uint256"}],"name":"LiquidityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_provider","type":"address"},{"indexed":true,"name":"_reserveToken","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"},{"indexed":false,"name":"_newBalance","type":"uint256"},{"indexed":false,"name":"_newSupply","type":"uint256"}],"name":"LiquidityRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_type","type":"uint16"},{"indexed":true,"name":"_anchor","type":"address"},{"indexed":true,"name":"_activated","type":"bool"}],"name":"Activation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_fromToken","type":"address"},{"indexed":true,"name":"_toToken","type":"address"},{"indexed":true,"name":"_trader","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"},{"indexed":false,"name":"_return","type":"uint256"},{"indexed":false,"name":"_conversionFee","type":"int256"}],"name":"Conversion","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_token1","type":"address"},{"indexed":true,"name":"_token2","type":"address"},{"indexed":false,"name":"_rateN","type":"uint256"},{"indexed":false,"name":"_rateD","type":"uint256"}],"name":"TokenRateUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_prevFee","type":"uint32"},{"indexed":false,"name":"_newFee","type":"uint32"}],"name":"ConversionFeeUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_prevOwner","type":"address"},{"indexed":true,"name":"_newOwner","type":"address"}],"name":"OwnerUpdate","type":"event"}]

Deployed Bytecode

0x60806040526004361061035f5763ffffffff60e060020a6000350416625e319c81146103fd578063024c7ec7146104305780630337e3fb1461044a5780630a55fb3d1461047b5780630c7d5cd8146104a45780630e53aae9146104d2578063119b90cd1461052757806312c2aca41461055457806316912f961461056957806319b640151461057e5780631cfab290146105965780631e1401f8146105b757806321e6b53d146105fa57806322f3e2d41461061b5780632630c12f146106305780632bd3c107146106455780632bf0c985146106665780632fe8a6ad1461068757806336fe4d2e1461069c57806338a5e016146106b1578063395900d4146106c65780633e8ff43f146106f0578063419161d61461071c578063467494681461073a57806349d10b64146107555780634af80f0e1461076a578063522a4a1c1461078b57806354fd4d50146107a057806355776b77146107b55780635768adcf146107cf578063579cd3ca146107f05780635d474c3e146108055780635e35359e1461081d578063617640731461084757806361cd756e1461085f57806367b6d57c1461087457806369067d9514610895578063690d8320146108b957806369d1354a146108da5780636a49d2c4146108f257806371f52bf31461091c57806379ba5097146109315780637b103999146109465780638da5cb5b1461095b57806394c275ad1461097057806398a71dcb14610985578063991e92b6146109a65780639b99a8e2146109bb578063a32bff44146109d0578063af94b8d8146109e5578063b4a176d314610a0f578063bf75455814610a24578063bf7da6ba14610a39578063c3321fb014610a5d578063c45d3d9214610a72578063cdc91c6914610a87578063d031370b14610a9c578063d260529c14610ab4578063d3fb73b414610ac9578063d4ee1d9014610ade578063d55ec69714610af3578063d64c5a1a14610b08578063d66bd52414610b33578063d672671214610b54578063d895951214610b6e578063db2830a414610b8f578063dc75eb9a14610ba4578063dc8de37914610bb9578063e38192e314610bda578063e8104af914610c01578063e8dc12ff14610c16578063ec2240f514610c40578063ecbca55d14610c55578063f2fde38b14610c73578063f9cddde214610c94578063fc0c546a14610ca9575b60008051602061562d83398151915260005260076020527fb2084a3e4595ccf007fb44245853374aaf0de960074375e8e0fb334712e94d0f546601000000000000900460ff1615156103fb576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f494e56414c49445f5245534552564500000000000000000000000000604482015290519081900360640190fd5b005b34801561040957600080fd5b5061041e600160a060020a0360043516610cbe565b60408051918252519081900360200190f35b34801561043c57600080fd5b506103fb6004351515610ce7565b34801561045657600080fd5b5061045f610d2f565b60408051600160a060020a039092168252519081900360200190f35b34801561048757600080fd5b50610490610d3e565b604080519115158252519081900360200190f35b3480156104b057600080fd5b506104b9610d47565b6040805163ffffffff9092168252519081900360200190f35b3480156104de57600080fd5b506104f3600160a060020a0360043516610d53565b6040805195865263ffffffff9094166020860152911515848401521515606084015215156080830152519081900360a00190f35b34801561053357600080fd5b506103fb600160a060020a0360043581169060243581169060443516610dee565b34801561056057600080fd5b50610490611559565b34801561057557600080fd5b506103fb6115a2565b34801561058a57600080fd5b5061045f6004356115b6565b3480156105a257600080fd5b506104b9600160a060020a03600435166115e2565b3480156105c357600080fd5b506105e1600160a060020a0360043581169060243516604435611614565b6040805192835260208301919091528051918290030190f35b34801561060657600080fd5b506103fb600160a060020a036004351661162e565b34801561062757600080fd5b50610490611642565b34801561063c57600080fd5b5061045f611677565b34801561065157600080fd5b5061041e600160a060020a0360043516611696565b34801561067257600080fd5b5061041e600160a060020a03600435166116eb565b34801561069357600080fd5b506104906117ce565b3480156106a857600080fd5b506104906117ef565b3480156106bd57600080fd5b506103fb6117f8565b3480156106d257600080fd5b506103fb600160a060020a036004358116906024351660443561180a565b3480156106fc57600080fd5b506107056118a9565b6040805161ffff9092168252519081900360200190f35b34801561072857600080fd5b506103fb6004356024356044356118ae565b34801561074657600080fd5b506103fb6004356024356118f1565b34801561076157600080fd5b506103fb611975565b34801561077657600080fd5b506103fb600160a060020a0360043516611bd5565b34801561079757600080fd5b5061041e611c0a565b3480156107ac57600080fd5b50610705611c10565b61041e600160a060020a0360043516602435604435611c15565b3480156107db57600080fd5b5061045f600160a060020a036004351661219e565b3480156107fc57600080fd5b506104b96121bc565b34801561081157600080fd5b506103fb6004356121d4565b34801561082957600080fd5b506103fb600160a060020a0360043581169060243516604435612279565b34801561085357600080fd5b506103fb6004356123a9565b34801561086b57600080fd5b5061045f6123f3565b34801561088057600080fd5b506103fb600160a060020a0360043516612402565b3480156108a157600080fd5b506105e1600160a060020a03600435166024356124a9565b3480156108c557600080fd5b506103fb600160a060020a0360043516612604565b3480156108e657600080fd5b506103fb600435612725565b3480156108fe57600080fd5b506103fb600160a060020a036004351663ffffffff602435166127ca565b34801561092857600080fd5b50610705612829565b34801561093d57600080fd5b506103fb612833565b34801561095257600080fd5b5061045f6128e7565b34801561096757600080fd5b5061045f6128f6565b34801561097c57600080fd5b506104b9612905565b34801561099157600080fd5b5061041e600160a060020a0360043516612919565b3480156109b257600080fd5b5061041e61292b565b3480156109c757600080fd5b50610705612931565b3480156109dc57600080fd5b506105e1612937565b3480156109f157600080fd5b506105e1600160a060020a0360043581169060243516604435612940565b348015610a1b57600080fd5b506103fb612ae4565b348015610a3057600080fd5b50610490612b10565b348015610a4557600080fd5b506103fb600160a060020a0360043516602435612b15565b348015610a6957600080fd5b5061041e612b5d565b348015610a7e57600080fd5b5061045f612b63565b348015610a9357600080fd5b506103fb612b72565b348015610aa857600080fd5b5061045f600435612bcb565b348015610ac057600080fd5b50610490612bf3565b348015610ad557600080fd5b5061045f612bf8565b348015610aea57600080fd5b5061045f612c07565b348015610aff57600080fd5b506103fb612c16565b348015610b1457600080fd5b50610b1d612d0b565b6040805160ff9092168252519081900360200190f35b348015610b3f57600080fd5b506104f3600160a060020a0360043516612d10565b348015610b6057600080fd5b506103fb6004351515612d56565b348015610b7a57600080fd5b5061041e600160a060020a0360043516612da6565b348015610b9b57600080fd5b506105e1612db7565b348015610bb057600080fd5b5061045f612ddc565b348015610bc557600080fd5b5061041e600160a060020a0360043516612deb565b348015610be657600080fd5b5061041e600160a060020a0360043516602435604435612e14565b348015610c0d57600080fd5b5061041e613195565b61041e600160a060020a03600435811690602435811690604435906064358116906084351661319b565b348015610c4c57600080fd5b506105e161340a565b348015610c6157600080fd5b506103fb63ffffffff6004351661348a565b348015610c7f57600080fd5b506103fb600160a060020a036004351661357f565b348015610ca057600080fd5b506105e161360f565b348015610cb557600080fd5b5061045f613618565b600081610cca81613627565b5050600160a060020a03166000908152600b602052604090205490565b610cef6136a6565b60038054911515740100000000000000000000000000000000000000000274ff000000000000000000000000000000000000000019909216919091179055565b600954600160a060020a031681565b60155460ff1681565b60085463ffffffff1681565b6000806000806000610d636155c8565b50505050600160a060020a03929092166000908152600760209081526040808320815160a081018352815480825260019092015463ffffffff811694820185905260ff64010000000082048116151594830194909452650100000000008104841615156060830152660100000000000090049092161515608090920182905295919450919250829190565b6000806000806000610dfe6136f6565b610e066136a6565b87610e1081613627565b87610e1a81613753565b87610e2481613753565b89610e2e816137b4565b89610e38816137b4565b60048054604080517f8da5cb5b00000000000000000000000000000000000000000000000000000000815290513093600160a060020a0390931692638da5cb5b928082019260209290918290030181600087803b158015610e9857600080fd5b505af1158015610eac573d6000803e3d6000fd5b505050506040513d6020811015610ec257600080fd5b5051600160a060020a031614610f22576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f414e43484f525f4e4f545f4f574e4544000000000000000000000000604482015290519081900360640190fd5b610f4b7f436861696e6c696e6b4f7261636c6557686974656c6973740000000000000000613814565b995089600160a060020a0316633af32abf8d6040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b158015610fa857600080fd5b505af1158015610fbc573d6000803e3d6000fd5b505050506040513d6020811015610fd257600080fd5b5051151561102a576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f494e56414c49445f4f5241434c450000000000000000000000000000604482015290519081900360640190fd5b89600160a060020a0316633af32abf8c6040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561108557600080fd5b505af1158015611099573d6000803e3d6000fd5b505050506040513d60208110156110af57600080fd5b50511515611107576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f494e56414c49445f4f5241434c450000000000000000000000000000604482015290519081900360640190fd5b61110f6138ac565b60098054600160a060020a031916600160a060020a038f1617905560068054600090811061113957fe5b600091825260209091200154600160a060020a038e8116911614156111975760068054600190811061116757fe5b600091825260209091200154600a8054600160a060020a031916600160a060020a039092169190911790556111d2565b6006805460009081106111a657fe5b600091825260209091200154600a8054600160a060020a031916600160a060020a039092169190911790555b6111fb7f436f6e766572746572466163746f727900000000000000000000000000000000613814565b600160a060020a031663c977aed26112116118a9565b6040518263ffffffff1660e060020a028152600401808261ffff1661ffff168152602001915050602060405180830381600087803b15801561125257600080fd5b505af1158015611266573d6000803e3d6000fd5b505050506040513d602081101561127c57600080fd5b8101908080519060200190929190505050985088600160a060020a0316631b27444e8e600a60009054906101000a9004600160a060020a03168f8f6040518563ffffffff1660e060020a0281526004018085600160a060020a0316600160a060020a0316815260200184600160a060020a0316600160a060020a0316815260200183600160a060020a0316600160a060020a0316815260200182600160a060020a0316600160a060020a03168152602001945050505050602060405180830381600087803b15801561134d57600080fd5b505af1158015611361573d6000803e3d6000fd5b505050506040513d602081101561137757600080fd5b5051600880546bffffffffffffffffffffffff166c01000000000000000000000000600160a060020a0393841681029190911791829055600954600a54604080517fae818004000000000000000000000000000000000000000000000000000000008152928616600484015290851660248301528051929093049093169263ae8180049260448083019391928290030181600087803b15801561141957600080fd5b505af115801561142d573d6000803e3d6000fd5b505050506040513d604081101561144357600080fd5b5080516020909101516010819055600f829055601291909155601355611467613ae8565b60115560095461147f90600160a060020a0316610cbe565b60095490985061149790600160a060020a0316612deb565b600a549097506114af90600160a060020a0316612deb565b9550868814156114da5760008811806114c85750600086115b156114d5576114d5613aec565b611503565b6000881180156114ea5750600087115b80156114f65750600086115b1561150357611503613aec565b600454600190600160a060020a031661151a6118a9565b61ffff167f6b08c2e2c9969e55a647a764db9b554d64dc42f1a704da11a6d5b129ad163f2c60405160405180910390a450505050505050505050505050565b60008051602061562d83398151915260005260076020527fb2084a3e4595ccf007fb44245853374aaf0de960074375e8e0fb334712e94d0f546601000000000000900460ff1690565b6115aa6136a6565b6015805460ff19169055565b60006006828154811015156115c757fe5b600091825260209091200154600160a060020a031692915050565b6000816115ee81613627565b5050600160a060020a031660009081526007602052604090206001015463ffffffff1690565b600080611622858585612940565b91509150935093915050565b6116366136a6565b61163f81612402565b50565b600061164c613b64565b801561167257506008546c010000000000000000000000009004600160a060020a031615155b905090565b6008546c010000000000000000000000009004600160a060020a031681565b6000816116a281613627565b6116e46116ae84612deb565b600160a060020a0385166000908152600b60205260409020546116d890601363ffffffff613bfd16565b9063ffffffff613c8116565b9392505050565b600080600080600085600160a060020a03166318160ddd6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561173157600080fd5b505af1158015611745573d6000803e3d6000fd5b505050506040513d602081101561175b57600080fd5b5051600160a060020a038088166000908152600d602052604090205491955016925061178683612deb565b600160a060020a0384166000908152600b602052604090205490925090506117c4816117b8848763ffffffff613bfd16565b9063ffffffff613cde16565b9695505050505050565b60035474010000000000000000000000000000000000000000900460ff1681565b600e5460ff1681565b6118006136a6565b611808612b72565b565b6118126136a6565b60048054604080517f5e35359e000000000000000000000000000000000000000000000000000000008152600160a060020a038781169482019490945285841660248201526044810185905290519290911691635e35359e9160648082019260009290919082900301818387803b15801561188c57600080fd5b505af11580156118a0573d6000803e3d6000fd5b50505050505050565b600290565b6118b66136a6565b60165483146118c8576118c883612725565b60175482146118da576118da826121d4565b60185481146118ec576118ec816123a9565b505050565b6118f96136a6565b81601460006006600081548110151561190e57fe5b6000918252602080832090910154600160a060020a031683528201929092526040018120919091556006805483926014929091600190811061194c57fe5b6000918252602080832090910154600160a060020a031683528201929092526040019020555050565b60008054600160a060020a03163314806119aa575060035474010000000000000000000000000000000000000000900460ff16155b15156119ee576040805160e560020a62461bcd028152602060048201526011602482015260008051602061566d833981519152604482015290519081900360640190fd5b611a177f436f6e7472616374526567697374727900000000000000000000000000000000613814565b600254909150600160a060020a03808316911614801590611a405750600160a060020a03811615155b1515611a96576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e56414c49445f5245474953545259000000000000000000000000604482015290519081900360640190fd5b604080517fbb34534c0000000000000000000000000000000000000000000000000000000081527f436f6e747261637452656769737472790000000000000000000000000000000060048201529051600091600160a060020a0384169163bb34534c9160248082019260209290919082900301818787803b158015611b1a57600080fd5b505af1158015611b2e573d6000803e3d6000fd5b505050506040513d6020811015611b4457600080fd5b5051600160a060020a03161415611ba5576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e56414c49445f5245474953545259000000000000000000000000604482015290519081900360640190fd5b6002805460038054600160a060020a03808416600160a060020a0319928316179092559091169216919091179055565b611bdd6136a6565b80611be781613753565b5060058054600160a060020a031916600160a060020a0392909216919091179055565b60175481565b602581565b6000806000806000611c25613d4c565b6003805460a860020a60ff02191660a860020a179055611c43613dae565b87611c4d81613627565b87611c5781613e0c565b87611c6181613e0c565b600160a060020a038b1660008051602061562d83398151915214611c86573415611c8a565b8934145b1515611ce0576040805160e560020a62461bcd02815260206004820152601760248201527f4552525f4554485f414d4f554e545f4d49534d41544348000000000000000000604482015290519081900360640190fd5b611ce8613e64565b600160a060020a038b1660008051602061562d8339815191521415611d8a5760008051602061562d83398151915260005260076020527fb2084a3e4595ccf007fb44245853374aaf0de960074375e8e0fb334712e94d0e54611d50903463ffffffff613ea616565b60008051602061562d83398151915260005260076020527fb2084a3e4595ccf007fb44245853374aaf0de960074375e8e0fb334712e94d0e555b600160a060020a038b166000908152600b602052604090205460155490975060ff1615611e5357600160a060020a038b166000908152601460205260409020541580611dfd5750600160a060020a038b16600090815260146020526040902054611dfa888c63ffffffff613c8116565b11155b1515611e53576040805160e560020a62461bcd02815260206004820152601e60248201527f4552525f4d41585f5354414b45445f42414c414e43455f524541434845440000604482015290519081900360640190fd5b600160a060020a03808c166000908152600c602090815260408083205481517f18160ddd00000000000000000000000000000000000000000000000000000000815291519416995089936318160ddd93600480840194938390030190829087803b158015611ec057600080fd5b505af1158015611ed4573d6000803e3d6000fd5b505050506040513d6020811015611eea57600080fd5b50519450600160a060020a038b1660008051602061562d83398151915214611f1857611f188b33308d613f06565b600160a060020a038b16600090815260076020526040902054611f41908b63ffffffff613c8116565b600160a060020a038c16600090815260076020526040902055611f6a878b63ffffffff613c8116565b600160a060020a038c166000908152600b60205260408120919091559350861580611f93575084155b15611fa057899350611fb7565b611fb4876117b88c8863ffffffff613bfd16565b93505b8884101561200f576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f52455455524e5f544f4f5f4c4f570000000000000000000000000000604482015290519081900360640190fd5b60048054604080517fc6c3bbe6000000000000000000000000000000000000000000000000000000008152600160a060020a038a811694820194909452336024820152604481018890529051929091169163c6c3bbe69160648082019260009290919082900301818387803b15801561208757600080fd5b505af115801561209b573d6000803e3d6000fd5b505050506120a7613aec565b600160a060020a038b16337f4a1a2a6176e9646d9e3157f7c2ab3c499f18337c0b0828cfb28e0a61de4a11f78c6120e48b8263ffffffff613c8116565b6120f48a8a63ffffffff613c8116565b60408051938452602084019290925282820152519081900360600190a361212b86612125878763ffffffff613c8116565b8d613fee565b6121806006600081548110151561213e57fe5b60009182526020909120015460068054600160a060020a0390921691600190811061216557fe5b6000918252602082200154600160a060020a0316908061404e565b50506003805460a860020a60ff021916905550979650505050505050565b600160a060020a039081166000908152600c60205260409020541690565b60085468010000000000000000900463ffffffff1681565b6121dc6136a6565b620f4240811115612237576040805160e560020a62461bcd02815260206004820181905260248201527f4552525f494e56414c49445f5745494748545f5350524541445f464143544f52604482015290519081900360640190fd5b601754604080519182526020820183905280517f3fa7cdc6478a15b3741de3ea89089f6889831a44e644fbd43b9cd48cc0cb08789281900390910190a1601755565b6000612283613d4c565b6003805460a860020a60ff02191660a860020a1790556122a16136a6565b6122b860008051602061564d833981519152613814565b600160a060020a0385166000908152600760205260409020600101549091506601000000000000900460ff1615806122f557506122f3611642565b155b8061230d5750600054600160a060020a038281169116145b1515612351576040805160e560020a62461bcd028152602060048201526011602482015260008051602061566d833981519152604482015290519081900360640190fd5b61235c8484846140ba565b600160a060020a0384166000908152600760205260409020600101546601000000000000900460ff161561239357612393846140eb565b50506003805460a860020a60ff02191690555050565b6123b16136a6565b601854604080519182526020820183905280517fb1d3d7d582c9ec9854586e485d8901ff3e43e8ecc470e334a6d7add349696a4b9281900390910190a1601855565b600354600160a060020a031681565b61240a6136a6565b60008051602061564d833981519152612422816141df565b60048054604080517ff2fde38b000000000000000000000000000000000000000000000000000000008152600160a060020a03868116948201949094529051929091169163f2fde38b9160248082019260009290919082900301818387803b15801561248d57600080fd5b505af11580156124a1573d6000803e3d6000fd5b505050505050565b6000806000806000806000806000808b600160a060020a03166318160ddd6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156124f657600080fd5b505af115801561250a573d6000803e3d6000fd5b505050506040513d602081101561252057600080fd5b5051600160a060020a03808e166000908152600d60209081526040808320549093168252600b905220549098509650878b10156125eb57600954600160a060020a03166000908152600b602052604090205461258390601463ffffffff613bfd16565b60095490965061259b90600160a060020a0316611696565b94508486106125ab5784866125ae565b85855b90945092506125c7886117b88d8a63ffffffff613bfd16565b91506125dd836117b8848763ffffffff613bfd16565b9950508881039750886125f5565b9598506000975088955b50505050505050509250929050565b600061260e613d4c565b6003805460a860020a60ff02191660a860020a17905561262c6136a6565b60008051602061562d83398151915261264481613627565b61265b60008051602061564d833981519152613814565b9150612665611642565b158061267e5750600054600160a060020a038381169116145b15156126c2576040805160e560020a62461bcd028152602060048201526011602482015260008051602061566d833981519152604482015290519081900360640190fd5b604051600160a060020a03841690303180156108fc02916000818181858888f193505050501580156126f8573d6000803e3d6000fd5b5061271060008051602061562d8339815191526140eb565b50506003805460a860020a60ff021916905550565b61272d6136a6565b620f4240811115612788576040805160e560020a62461bcd02815260206004820152601e60248201527f4552525f494e56414c49445f44594e414d49435f4645455f464143544f520000604482015290519081900360640190fd5b601654604080519182526020820183905280517f382fd3516344712a511dcd464ff8e6ab54139d6a28f64087a3253353ee7a56799281900390910190a1601655565b60026127d4612931565b61ffff161061281b576040805160e560020a62461bcd028152602060048201526019602482015260008051602061568d833981519152604482015290519081900360640190fd5b6128258282614235565b5050565b6000611672612931565b600154600160a060020a03163314612883576040805160e560020a62461bcd028152602060048201526011602482015260008051602061566d833981519152604482015290519081900360640190fd5b60015460008054604051600160a060020a0393841693909116917f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a91a36001805460008054600160a060020a0319908116600160a060020a03841617909155169055565b600254600160a060020a031681565b600054600160a060020a031681565b600854640100000000900463ffffffff1681565b60146020526000908152604090205481565b60185481565b60065490565b600f5460105482565b60008060008061294e6155f6565b60008060008061295c613dae565b6129658c613627565b61296e8b613627565b600160a060020a038c8116908c1614156129d2576040805160e560020a62461bcd02815260206004820152601660248201527f4552525f53414d455f534f555243455f54415247455400000000000000000000604482015290519081900360640190fd5b6129da613ae8565b6011541415612a8157600f604080519081016040529081600082015481526020016001820154815250509450600760008d600160a060020a0316600160a060020a0316815260200190815260200160002060010160009054906101000a900463ffffffff169650600760008c600160a060020a0316600160a060020a0316815260200190815260200160002060010160009054906101000a900463ffffffff169550612ac1565b612a89614467565b9450612a94856146bb565b6009549195509350600160a060020a038d811691161415612aba57839650829550612ac1565b8296508395505b612acf8c8c8989898f6147e5565b919e919d50909b505050505050505050505050565b612aec6136a6565b60035460028054600160a060020a031916600160a060020a03909216919091179055565b600181565b612b1d6136a6565b60008051602061564d833981519152612b35816141df565b82612b3f81613627565b5050600160a060020a039091166000908152600b6020526040902055565b60115481565b600554600160a060020a031681565b6001612b7c612931565b61ffff1611612bc3576040805160e560020a62461bcd028152602060048201526019602482015260008051602061568d833981519152604482015290519081900360640190fd5b61180861499b565b6006805482908110612bd957fe5b600091825260209091200154600160a060020a0316905081565b600190565b600454600160a060020a031681565b600154600160a060020a031681565b6000612c206136a6565b612c3760008051602061564d833981519152613814565b600454909150600090600160a060020a0316612c516118a9565b61ffff167f6b08c2e2c9969e55a647a764db9b554d64dc42f1a704da11a6d5b129ad163f2c60405160405180910390a4612c8a8161357f565b604080517f90f58c96000000000000000000000000000000000000000000000000000000008152602560048201529051600160a060020a038316916390f58c9691602480830192600092919082900301818387803b158015612ceb57600080fd5b505af1158015612cff573d6000803e3d6000fd5b5050505061163f612833565b601490565b6007602052600090815260409020805460019091015463ffffffff81169060ff640100000000820481169165010000000000810482169166010000000000009091041685565b612d5e6136a6565b60408051821515815290517fb22443976b3dec630abbac38db10e02ed2da230ccd77e0de871388f7f24417c19181900360200190a1600e805460ff1916911515919091179055565b6000612db182612deb565b92915050565b600080612dc26155f6565b612dca614467565b80516020909101519094909350915050565b600a54600160a060020a031681565b600081612df781613627565b5050600160a060020a031660009081526007602052604090205490565b600080600080600080612e25613d4c565b6003805460a860020a60ff02191660a860020a179055612e43613dae565b88612e4d81614a70565b88612e5781613e0c565b88612e6181613e0c565b612e69613e64565b8b600160a060020a03166318160ddd6040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015612ea757600080fd5b505af1158015612ebb573d6000803e3d6000fd5b505050506040513d6020811015612ed157600080fd5b50519750612edf8c8c6124a9565b50965089871015612f3a576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f52455455524e5f544f4f5f4c4f570000000000000000000000000000604482015290519081900360640190fd5b600d60008d600160a060020a0316600160a060020a0316815260200190815260200160002060009054906101000a9004600160a060020a03169550600460009054906101000a9004600160a060020a0316600160a060020a031663f6b911bc8d338e6040518463ffffffff1660e060020a0281526004018084600160a060020a0316600160a060020a0316815260200183600160a060020a0316600160a060020a031681526020018281526020019350505050600060405180830381600087803b15801561300757600080fd5b505af115801561301b573d6000803e3d6000fd5b505050600160a060020a03871660009081526007602052604090205461304891508863ffffffff613ea616565b600160a060020a038716600090815260076020908152604080832093909355600b9052205461307d908863ffffffff613ea616565b600160a060020a0387166000818152600b6020526040902082905590955060008051602061562d83398151915214156130e357604051339088156108fc029089906000818181858888f193505050501580156130dd573d6000803e3d6000fd5b506130ee565b6130ee863389614ae1565b6130f6613aec565b613106888c63ffffffff613ea616565b60408051898152602081018890528082018390529051919550600160a060020a0388169133917fbc7d19d505c7ec4db83f3b51f19fb98c4c8a99922e7839d1ee608dfbee29501b919081900360600190a36131628c8588613fee565b6131756006600081548110151561213e57fe5b50506003805460a860020a60ff0219169055509298975050505050505050565b60165481565b60006131a5613d4c565b6003805460a860020a60ff02191660a860020a1790557f42616e636f724e6574776f726b000000000000000000000000000000000000006131e5816141df565b600160a060020a038781169087161415613249576040805160e560020a62461bcd02815260206004820152601660248201527f4552525f53414d455f534f555243455f54415247455400000000000000000000604482015290519081900360640190fd5b600554600160a060020a0316158061338c5750600554604080517f3af32abf000000000000000000000000000000000000000000000000000000008152600160a060020a03878116600483015291519190921691633af32abf9160248083019260209291908290030181600087803b1580156132c457600080fd5b505af11580156132d8573d6000803e3d6000fd5b505050506040513d60208110156132ee57600080fd5b5051801561338c5750600554604080517f3af32abf000000000000000000000000000000000000000000000000000000008152600160a060020a03868116600483015291519190921691633af32abf9160248083019260209291908290030181600087803b15801561335f57600080fd5b505af1158015613373573d6000803e3d6000fd5b505050506040513d602081101561338957600080fd5b50515b15156133e2576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f4e4f545f57484954454c495354454400000000000000000000000000604482015290519081900360640190fd5b6133ef8787878787614b93565b6003805460a860020a60ff0219169055979650505050505050565b6000806134156155f6565b600080613420614467565b925061342b836146bb565b915091506006600081548110151561343f57fe5b600091825260209091200154600954600160a060020a03908116911614156134745763ffffffff808316955081169350613483565b63ffffffff8082169550821693505b5050509091565b6134926136a6565b60085463ffffffff640100000000909104811690821611156134fe576040805160e560020a62461bcd02815260206004820152601a60248201527f4552525f494e56414c49445f434f4e56455253494f4e5f464545000000000000604482015290519081900360640190fd5b6008546040805163ffffffff6801000000000000000090930483168152918316602083015280517f81cd2ffb37dd237c0e4e2a3de5265fcf9deb43d3e7801e80db9f1ccfba7ee6009281900390910190a16008805463ffffffff90921668010000000000000000026bffffffff000000000000000019909216919091179055565b6135876136a6565b600054600160a060020a03828116911614156135ed576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f53414d455f4f574e4552000000000000000000000000000000000000604482015290519081900360640190fd5b60018054600160a060020a031916600160a060020a0392909216919091179055565b60125460135482565b600454600160a060020a031690565b600160a060020a0381166000908152600760205260409020600101546601000000000000900460ff16151561163f576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f494e56414c49445f5245534552564500000000000000000000000000604482015290519081900360640190fd5b600054600160a060020a03163314611808576040805160e560020a62461bcd028152602060048201526011602482015260008051602061566d833981519152604482015290519081900360640190fd5b6136fe611642565b15611808576040805160e560020a62461bcd02815260206004820152600a60248201527f4552525f41435449564500000000000000000000000000000000000000000000604482015290519081900360640190fd5b600160a060020a03811630141561163f576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f414444524553535f49535f53454c4600000000000000000000000000604482015290519081900360640190fd5b600160a060020a038116151561163f576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f494e56414c49445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b600254604080517fbb34534c000000000000000000000000000000000000000000000000000000008152600481018490529051600092600160a060020a03169163bb34534c91602480830192602092919082900301818787803b15801561387a57600080fd5b505af115801561388e573d6000803e3d6000fd5b505050506040513d60208110156138a457600080fd5b505192915050565b60006060600080600080600460009054906101000a9004600160a060020a0316955085600160a060020a0316636d3e313e6040518163ffffffff1660e060020a028152600401600060405180830381600087803b15801561390c57600080fd5b505af1158015613920573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561394957600080fd5b81019080805164010000000081111561396157600080fd5b8201602081018481111561397457600080fd5b815185602082028301116401000000008211171561399157600080fd5b505080516006549199501597509550600094505050505b828210156124a1578315613a275785600160a060020a0316639cbf9e366040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156139f457600080fd5b505af1158015613a08573d6000803e3d6000fd5b505050506040513d6020811015613a1e57600080fd5b50519050613a42565b8482815181101515613a3557fe5b9060200190602002015190505b80600c6000600685815481101515613a5657fe5b600091825260208083209190910154600160a060020a03908116845290830193909352604090910190208054600160a060020a031916929091169190911790556006805483908110613aa457fe5b6000918252602080832090910154600160a060020a038481168452600d90925260409092208054600160a060020a03191691909216179055600191909101906139a8565b4290565b60408051808201909152600f54815260105460208201526000908190613b11906146bb565b600954600160a060020a039081166000908152600760205260408082206001908101805463ffffffff97881663ffffffff1991821617909155600a54909416835291200180549290931691161790555050565b60048054604080517f8da5cb5b00000000000000000000000000000000000000000000000000000000815290516000933093600160a060020a031692638da5cb5b928183019260209282900301818887803b158015613bc257600080fd5b505af1158015613bd6573d6000803e3d6000fd5b505050506040513d6020811015613bec57600080fd5b5051600160a060020a031614905090565b600080831515613c105760009150613c7a565b50828202828482811515613c2057fe5b0414613c76576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b8091505b5092915050565b600082820183811015613c76576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b600080808311613d38576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f4449564944455f42595f5a45524f0000000000000000000000000000604482015290519081900360640190fd5b8284811515613d4357fe5b04949350505050565b60035460a860020a900460ff1615611808576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f5245454e5452414e4359000000000000000000000000000000000000604482015290519081900360640190fd5b613db6611642565b1515611808576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f494e4143544956450000000000000000000000000000000000000000604482015290519081900360640190fd5b6000811161163f576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f5a45524f5f56414c5545000000000000000000000000000000000000604482015290519081900360640190fd5b60065460005b8181101561282557613e9e600682815481101515613e8457fe5b600091825260209091200154600160a060020a03166140eb565b600101613e6a565b600081831015613f00576040805160e560020a62461bcd02815260206004820152600d60248201527f4552525f554e444552464c4f5700000000000000000000000000000000000000604482015290519081900360640190fd5b50900390565b604080517f7472616e7366657246726f6d28616464726573732c616464726573732c75696e81527f74323536290000000000000000000000000000000000000000000000000000006020808301919091528251918290036025018220600160a060020a038088166024850152861660448401526064808401869052845180850390910181526084909301909352810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1990931692909217909152613fe8908590614c86565b50505050565b600160a060020a038082166000818152600b6020908152604091829020548251908152908101869052815192938716927f77f29993cf2c084e726f7e802da0719d6a0ade3e204badc7a3ffd57ecb768c24929181900390910190a3505050565b6140566155f6565b61406285858585614d14565b805160208083015160408051938452918301528051929350600160a060020a0380881693908916927f77f29993cf2c084e726f7e802da0719d6a0ade3e204badc7a3ffd57ecb768c2492908290030190a35050505050565b6140c26136a6565b826140cc816137b4565b826140d6816137b4565b836140e081613753565b6124a1868686614ae1565b806140f581613627565b600160a060020a03821660008051602061562d833981519152141561413557600160a060020a038216600090815260076020526040902030319055612825565b604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051600160a060020a038416916370a082319160248083019260209291908290030181600087803b15801561419657600080fd5b505af11580156141aa573d6000803e3d6000fd5b505050506040513d60208110156141c057600080fd5b5051600160a060020a0383166000908152600760205260409020555050565b6141e881613814565b600160a060020a0316331461163f576040805160e560020a62461bcd028152602060048201526011602482015260008051602061566d833981519152604482015290519081900360640190fd5b600061423f6136a6565b6142476136f6565b82614251816137b4565b8361425b81613753565b8361426581614ddc565b600454600160a060020a038781169116148015906142a95750600160a060020a0386166000908152600760205260409020600101546601000000000000900460ff16155b15156142ff576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f494e56414c49445f5245534552564500000000000000000000000000604482015290519081900360640190fd5b60085463ffffffff908116620f4240038116908616111561436a576040805160e560020a62461bcd02815260206004820152601a60248201527f4552525f494e56414c49445f524553455256455f574549474854000000000000604482015290519081900360640190fd5b61ffff614375612931565b61ffff16106143bc576040805160e560020a62461bcd028152602060048201526019602482015260008051602061568d833981519152604482015290519081900360640190fd5b505050600160a060020a0390921660008181526007602052604081208181556001908101805466ff0000000000001963ffffffff80881663ffffffff1993841617919091166601000000000000179092556006805493840181559093527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f9091018054600160a060020a03191690931790925560088054808416909401909216921691909117905550565b61446f6155f6565b60008060008061447d6155f6565b6144856155f6565b600854600954600a54604080517fb1772d7a000000000000000000000000000000000000000000000000000000008152600160a060020a0393841660048201529183166024830152516000938493849384936c010000000000000000000000009093049091169163b1772d7a9160448082019260609290919082900301818787803b15801561451357600080fd5b505af1158015614527573d6000803e3d6000fd5b505050506040513d606081101561453d57600080fd5b5080516020820151604090920151600e54919c50919a5090985060ff161580614567575060115488115b156145885760408051908101604052808b81526020018a8152509a506146ae565b601154614593613ae8565b0396508615156145bb5760408051808201909152600f54815260105460208201529a506146ae565b60185487106145e25760408051808201909152601254815260135460208201529a506146ae565b604080518082018252600f5481526010546020808301918252835180850190945260125480855260135491850191909152905191985091965061462a9163ffffffff613bfd16565b60208601518751919550614644919063ffffffff613bfd16565b9250614670614659858963ffffffff613bfd16565b6116d8896018540386613bfd90919063ffffffff16565b915061469f60185461469387602001518960200151613bfd90919063ffffffff16565b9063ffffffff613bfd16565b90506146ab8282614e51565b9a505b5050505050505050505090565b600954600160a060020a03166000818152600b60205260408120549091829190829081906146e890611696565b600a5490925061470090600160a060020a0316611696565b905061472b7f42616e636f72466f726d756c6100000000000000000000000000000000000000613814565b600160a060020a031663a11aa1b461474a85601463ffffffff613bfd16565b885160208a01516040805160e060020a63ffffffff87160281526004810194909452602484018890526044840187905260648401929092526084830152805160a4808401938290030181600087803b1580156147a557600080fd5b505af11580156147b9573d6000803e3d6000fd5b505050506040513d60408110156147cf57600080fd5b5080516020909101519095509350505050915091565b6000808080808063ffffffff8a16151561481e57600160a060020a038c1660009081526007602052604090206001015463ffffffff1699505b63ffffffff8916151561485057600160a060020a038b1660009081526007602052604090206001015463ffffffff1698505b6148598c611696565b92506148648b611696565b601754909250620f42409063ffffffff8c16020490506148a37f42616e636f72466f726d756c6100000000000000000000000000000000000000613814565b604080517f94491fab0000000000000000000000000000000000000000000000000000000081526004810186905263ffffffff848e0381166024830152604482018690528c8501166064820152608481018a90529051600160a060020a0392909216916394491fab9160a4808201926020929091908290030181600087803b15801561492e57600080fd5b505af1158015614942573d6000803e3d6000fd5b505050506040513d602081101561495857600080fd5b5051955061496586614ea6565b9450614978856116d88d8d8d8d8c614ed6565b935061498a868563ffffffff613ea616565b955050505096509650969350505050565b6149a36136a6565b60006149ad612931565b61ffff16116149f4576040805160e560020a62461bcd028152602060048201526019602482015260008051602061568d833981519152604482015290519081900360640190fd5b60048054604080517f79ba50970000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216926379ba509792828201926000929082900301818387803b158015614a5057600080fd5b505af1158015614a64573d6000803e3d6000fd5b50505050611808613e64565b600160a060020a038181166000908152600d602052604090205416151561163f576040805160e560020a62461bcd02815260206004820152601660248201527f4552525f494e56414c49445f504f4f4c5f544f4b454e00000000000000000000604482015290519081900360640190fd5b604080517f7472616e7366657228616464726573732c75696e74323536290000000000000081528151908190036019018120600160a060020a038516602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19909316929092179091526118ec908490614c86565b6000806000614ba0613dae565b87614baa81613627565b87614bb481613627565b614bbf8a8a8a614faf565b9094509250600160a060020a03891660008051602061562d8339815191521415614c1f57604051600160a060020a0387169085156108fc029086906000818181858888f19350505050158015614c19573d6000803e3d6000fd5b50614c2a565b614c2a898786614ae1565b614c388a8a898b88886152c4565b600160a060020a03808b16600090815260076020526040808220600190810154938d16835291200154614c78918c918c9163ffffffff9081169116615349565b509198975050505050505050565b614c8e61560d565b602060405190810160405280600181525090506020818351602085016000875af1801515614cbb57600080fd5b50805115156118ec576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f5452414e534645525f4641494c454400000000000000000000000000604482015290519081900360640190fd5b614d1c6155f6565b600080614d2887611696565b9150614d3386611696565b905063ffffffff85161515614d6757600160a060020a03871660009081526007602052604090206001015463ffffffff1694505b63ffffffff84161515614d9957600160a060020a03861660009081526007602052604090206001015463ffffffff1693505b6040805180820190915280614db78363ffffffff808a1690613bfd16565b8152602001614dcf8463ffffffff80891690613bfd16565b9052979650505050505050565b60008163ffffffff16118015614dfb5750620f424063ffffffff821611155b151561163f576040805160e560020a62461bcd02815260206004820152601a60248201527f4552525f494e56414c49445f524553455256455f574549474854000000000000604482015290519081900360640190fd5b614e596155f6565b614e616155f6565b828410614e7957614e7284846153da565b9150613c7a565b614e8383856153da565b604080518082019091526020808301518252825190820152925090505092915050565b600854600090612db190620f4240906117b890859068010000000000000000900463ffffffff90811690613bfd16565b600a546000908190600160a060020a0388811691161415614f4457600954600160a060020a039081166000908152600b6020908152604080832054600a54909416835290912054865191870151601654614f3d949363ffffffff808d1693908c1692615497565b9050614f93565b600954600160a060020a039081166000908152600b6020908152604080832054600a54909416835290912054865191870151601654614f90949363ffffffff808c1693908d1692615497565b90505b614fa4620f42406117b88584613bfd565b979650505050505050565b6000806000614fbc6155f6565b600080600080614fca615503565b95509550614fdd8b8b600080898e6147e5565b9195509350915083151561503b576040805160e560020a62461bcd02815260206004820152601660248201527f4552525f5a45524f5f5441524745545f414d4f554e5400000000000000000000604482015290519081900360640190fd5b6150448a612deb565b905080841061509d576040805160e560020a62461bcd02815260206004820152601a60248201527f4552525f5441524745545f414d4f554e545f544f4f5f48494748000000000000604482015290519081900360640190fd5b600160a060020a038b1660008051602061562d833981519152141561511857348914615113576040805160e560020a62461bcd02815260206004820152601760248201527f4552525f4554485f414d4f554e545f4d49534d41544348000000000000000000604482015290519081900360640190fd5b61521a565b341580156151c45750886151c161512e8d612deb565b8d600160a060020a03166370a08231306040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561518957600080fd5b505af115801561519d573d6000803e3d6000fd5b505050506040513d60208110156151b357600080fd5b50519063ffffffff613ea616565b10155b151561521a576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f494e56414c49445f414d4f554e540000000000000000000000000000604482015290519081900360640190fd5b6152238b6140eb565b615233818563ffffffff613ea616565b600160a060020a038b16600090815260076020908152604080832093909355600b90522054615268908463ffffffff613c8116565b600160a060020a038b166000908152600b602052604090205585156152b357600954600a546152a691600160a060020a039081169116600080614d14565b8051601255602001516013555b509199919850909650505050505050565b7f800000000000000000000000000000000000000000000000000000000000000081106152ed57fe5b60408051848152602081018490528082018390529051600160a060020a038087169288821692918a16917f276856b36cbc45526a0ba64f44611557a2a8b68662c5388e9fe6d72e86e1c8cb9181900360600190a4505050505050565b6000806153588686868661404e565b6153618561219e565b915081600160a060020a03166318160ddd6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156153a157600080fd5b505af11580156153b5573d6000803e3d6000fd5b505050506040513d60208110156153cb57600080fd5b505190506124a1828287613fee565b6153e26155f6565b7314484bfeebc29f863424b06f3529a051a31be59982111561543457604080518082019091526c0c9f2c9cd04674edea40000000808252602082019085048481151561542a57fe5b0490529050612db1565b6c0c9f2c9cd04674edea400000008311156154815760408051908101604052806c0c9f2c9cd04674edea400000008152602001846c0c9f2c9cd04674edea40000000850281151561542a57fe5b5060408051808201909152918252602082015290565b600080806154af876146938c8963ffffffff613bfd16565b91506154c5886146938b8863ffffffff613bfd16565b9050818111156154f1576154ea816117b860146146938684038963ffffffff613bfd16565b92506154f6565b600092505b5050979650505050505050565b600061550d6155f6565b60006155176155f6565b61551f6155f6565b615527613ae8565b92508260115414156155555760408051808201909152600f5481526010546020820152600095509350613483565b61555d614467565b60408051808201909152600f5480825260105460208301528251929450909250148015615591575080602001518260200151145b156155a25760008294509450613483565b8151600f55602082015160105560118390556155bc613aec565b50600194909350915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b604080518082019091526000808252602082015290565b60206040519081016040528060019060208202803883395091929150505600000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee42616e636f72436f6e76657274657255706772616465720000000000000000004552525f4143434553535f44454e4945440000000000000000000000000000004552525f494e56414c49445f524553455256455f434f554e5400000000000000a165627a7a72305820dc08c343fc5268506d4f52d859721ea486f0066b426f7c9120de91b127d345030029

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

OVERVIEW

Bancor converter address.

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.