Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
Loading...
Loading
Contract Name:
LiquidityPoolV1ConverterFactory
Compiler Version
v0.4.26+commit.4563c3fc
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-06-18 */ // File: 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: 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: 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: contracts/converter/interfaces/IConverterAnchor.sol pragma solidity 0.4.26; /* Converter Anchor interface */ contract IConverterAnchor is IOwned, ITokenHolder { } // File: contracts/utility/interfaces/IWhitelist.sol pragma solidity 0.4.26; /* Whitelist interface */ contract IWhitelist { function isWhitelisted(address _address) public view returns (bool); } // File: 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 rateAndFee(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: 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: contracts/converter/interfaces/IBancorFormula.sol pragma solidity 0.4.26; /* Bancor Formula interface */ contract IBancorFormula { function purchaseRate(uint256 _supply, uint256 _reserveBalance, uint32 _reserveWeight, uint256 _amount) public view returns (uint256); function saleRate(uint256 _supply, uint256 _reserveBalance, uint32 _reserveWeight, uint256 _amount) public view returns (uint256); function crossReserveRate(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 liquidateRate(uint256 _supply, uint256 _reserveBalance, uint32 _reserveRatio, uint256 _amount) public view returns (uint256); } // File: 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: 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: 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: 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: 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"; 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: 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: 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: 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: 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: 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: 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: 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; uint64 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 = 29; 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 _anchor converter anchor * @param _activated true if the converter was activated, false if it was deactivated */ event Activation(IConverterAnchor _anchor, bool _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 */ 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)); 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 return amount * * @param _amount return amount * * @return conversion fee */ function calculateFee(uint256 _amount) internal view returns (uint256) { return _amount.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 rateAndFee(_sourceToken, _targetToken, _amount); } } // File: 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 acceptTokenOwnership() public { // verify that the converter has at least 2 reserves require(reserveTokenCount() > 1, "ERR_INVALID_RESERVE_COUNT"); super.acceptTokenOwnership(); } } // File: contracts/converter/interfaces/ITypedConverterFactory.sol pragma solidity 0.4.26; /* Typed Converter Factory interface */ contract ITypedConverterFactory { function converterType() public pure returns (uint16); function createConverter(IConverterAnchor _anchor, IContractRegistry _registry, uint32 _maxConversionFee) public returns (IConverter); } // File: 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: contracts/converter/LiquidityPoolV1ConverterFactory.sol pragma solidity 0.4.26; /* LiquidityPoolV1Converter Factory */ contract LiquidityPoolV1ConverterFactory is ITypedConverterFactory { /** * @dev returns the converter type the factory is associated with * * @return converter type */ function converterType() public pure returns (uint16) { return 1; } /** * @dev creates a new converter with the given arguments and transfers * the ownership to the caller * * @param _anchor anchor governed by the converter * @param _registry address of a contract registry contract * @param _maxConversionFee maximum conversion fee, represented in ppm * * @return a new converter */ function createConverter(IConverterAnchor _anchor, IContractRegistry _registry, uint32 _maxConversionFee) public returns (IConverter) { ConverterBase converter = new LiquidityPoolV1Converter(ISmartToken(_anchor), _registry, _maxConversionFee); converter.transferOwnership(msg.sender); return converter; } } /** * @dev Liquidity Pool v1 Converter * * The liquidity pool v1 converter is a specialized version of a converter that manages * a classic bancor liquidity pool. * * Even though classic pools can have many reserves, the most common configuration of * the pool has 2 reserves with 50%/50% weights. */ contract LiquidityPoolV1Converter is LiquidityPoolConverter { IEtherToken internal etherToken = IEtherToken(0xc0829421C1d260BD3cB3E0F06cfE2D52db2cE315); /** * @dev triggered after a conversion with new price data * deprecated, use `TokenRateUpdate` from version 28 and up * * @param _connectorToken reserve token * @param _tokenSupply smart token supply * @param _connectorBalance reserve balance * @param _connectorWeight reserve weight */ event PriceDataUpdate( address indexed _connectorToken, uint256 _tokenSupply, uint256 _connectorBalance, uint32 _connectorWeight ); /** * @dev initializes a new LiquidityPoolV1Converter instance * * @param _token pool token governed by the converter * @param _registry address of a contract registry contract * @param _maxConversionFee maximum conversion fee, represented in ppm */ constructor( ISmartToken _token, IContractRegistry _registry, uint32 _maxConversionFee ) LiquidityPoolConverter(_token, _registry, _maxConversionFee) public { } /** * @dev returns the converter type * * @return see the converter types in the the main contract doc */ function converterType() public pure returns (uint16) { return 1; } /** * @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 ownerOnly { super.acceptAnchorOwnership(); emit Activation(anchor, true); } /** * @dev returns the expected rate 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 rate * @return expected fee */ function rateAndFee(IERC20Token _sourceToken, IERC20Token _targetToken, uint256 _amount) public view active validReserve(_sourceToken) validReserve(_targetToken) returns (uint256, uint256) { // validate input require(_sourceToken != _targetToken, "ERR_SAME_SOURCE_TARGET"); uint256 amount = IBancorFormula(addressOf(BANCOR_FORMULA)).crossReserveRate( reserveBalance(_sourceToken), reserves[_sourceToken].weight, reserveBalance(_targetToken), reserves[_targetToken].weight, _amount ); // return the amount minus the conversion fee and the conversion fee uint256 fee = calculateFee(amount); return (amount - fee, 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 returns (uint256) { // get expected rate and fee (uint256 amount, uint256 fee) = rateAndFee(_sourceToken, _targetToken, _amount); // ensure that the trade gives something in return require(amount != 0, "ERR_ZERO_RATE"); // ensure that the trade won't deplete the reserve balance uint256 targetReserveBalance = reserveBalance(_targetToken); assert(amount < targetReserveBalance); // 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 = reserves[_targetToken].balance.sub(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 dispatchRateEvents(_sourceToken, _targetToken); return amount; } /** * @dev increases the pool's liquidity and mints new shares in the pool to the caller * note that prior to version 28, you should use 'fund' instead * * @param _reserveTokens address of each reserve token * @param _reserveAmounts amount of each reserve token * @param _minReturn token minimum return-amount */ function addLiquidity(IERC20Token[] memory _reserveTokens, uint256[] memory _reserveAmounts, uint256 _minReturn) public payable protected active { // verify the user input verifyLiquidityInput(_reserveTokens, _reserveAmounts, _minReturn); // if one of the reserves is ETH, then verify that the input amount of ETH is equal to the input value of ETH for (uint256 i = 0; i < _reserveTokens.length; i++) if (_reserveTokens[i] == ETH_RESERVE_ADDRESS) require(_reserveAmounts[i] == msg.value, "ERR_ETH_AMOUNT_MISMATCH"); // if the input value of ETH is larger than zero, then verify that one of the reserves is ETH if (msg.value > 0) require(reserves[ETH_RESERVE_ADDRESS].isSet, "ERR_NO_ETH_RESERVE"); // get the total supply uint256 totalSupply = ISmartToken(anchor).totalSupply(); // transfer from the user an equally-worth amount of each one of the reserve tokens uint256 amount = addLiquidityToPool(_reserveTokens, _reserveAmounts, totalSupply); // verify that the equivalent amount of tokens is equal to or larger than the user's expectation require(amount >= _minReturn, "ERR_RETURN_TOO_LOW"); // issue the tokens to the user ISmartToken(anchor).issue(msg.sender, amount); } /** * @dev decreases the pool's liquidity and burns the caller's shares in the pool * note that prior to version 28, you should use 'liquidate' instead * * @param _amount token amount * @param _reserveTokens address of each reserve token * @param _reserveMinReturnAmounts minimum return-amount of each reserve token */ function removeLiquidity(uint256 _amount, IERC20Token[] memory _reserveTokens, uint256[] memory _reserveMinReturnAmounts) public protected active { // verify the user input verifyLiquidityInput(_reserveTokens, _reserveMinReturnAmounts, _amount); // get the total supply BEFORE destroying the user tokens uint256 totalSupply = ISmartToken(anchor).totalSupply(); // destroy the user tokens ISmartToken(anchor).destroy(msg.sender, _amount); // transfer to the user an equivalent amount of each one of the reserve tokens removeLiquidityFromPool(_reserveTokens, _reserveMinReturnAmounts, totalSupply, _amount); } /** * @dev increases the pool's liquidity and mints new shares in the pool to the caller * for example, if the caller increases the supply by 10%, * then it will cost an amount equal to 10% of each reserve token balance * note that starting from version 28, you should use 'addLiquidity' instead * * @param _amount amount to increase the supply by (in the pool token) */ function fund(uint256 _amount) public payable protected { syncReserveBalances(); reserves[ETH_RESERVE_ADDRESS].balance = reserves[ETH_RESERVE_ADDRESS].balance.sub(msg.value); uint256 supply = ISmartToken(anchor).totalSupply(); IBancorFormula formula = IBancorFormula(addressOf(BANCOR_FORMULA)); // iterate through the reserve tokens and transfer a percentage equal to the weight between // _amount and the total supply in each reserve from the caller to the converter uint256 reserveCount = reserveTokens.length; for (uint256 i = 0; i < reserveCount; i++) { IERC20Token reserveToken = reserveTokens[i]; uint256 rsvBalance = reserves[reserveToken].balance; uint256 reserveAmount = formula.fundCost(supply, rsvBalance, reserveRatio, _amount); // transfer funds from the caller in the reserve token if (reserveToken == ETH_RESERVE_ADDRESS) { if (msg.value > reserveAmount) { msg.sender.transfer(msg.value - reserveAmount); } else if (msg.value < reserveAmount) { require(msg.value == 0, "ERR_INVALID_ETH_VALUE"); safeTransferFrom(etherToken, msg.sender, this, reserveAmount); etherToken.withdraw(reserveAmount); } } else { safeTransferFrom(reserveToken, msg.sender, this, reserveAmount); } // sync the reserve balance uint256 newReserveBalance = rsvBalance.add(reserveAmount); reserves[reserveToken].balance = newReserveBalance; uint256 newPoolTokenSupply = supply.add(_amount); // dispatch liquidity update for the pool token/reserve emit LiquidityAdded(msg.sender, reserveToken, reserveAmount, newReserveBalance, newPoolTokenSupply); // dispatch the `TokenRateUpdate` event for the pool token uint32 reserveWeight = reserves[reserveToken].weight; dispatchPoolTokenRateEvent(newPoolTokenSupply, reserveToken, newReserveBalance, reserveWeight); } // issue new funds to the caller in the pool token ISmartToken(anchor).issue(msg.sender, _amount); } /** * @dev decreases the pool's liquidity and burns the caller's shares in the pool * for example, if the holder sells 10% of the supply, * then they will receive 10% of each reserve token balance in return * note that starting from version 28, you should use 'removeLiquidity' instead * * @param _amount amount to liquidate (in the pool token) */ function liquidate(uint256 _amount) public protected { require(_amount > 0, "ERR_ZERO_AMOUNT"); uint256 totalSupply = ISmartToken(anchor).totalSupply(); ISmartToken(anchor).destroy(msg.sender, _amount); uint256[] memory reserveMinReturnAmounts = new uint256[](reserveTokens.length); for (uint256 i = 0; i < reserveMinReturnAmounts.length; i++) reserveMinReturnAmounts[i] = 1; removeLiquidityFromPool(reserveTokens, reserveMinReturnAmounts, totalSupply, _amount); } /** * @dev verifies that a given array of tokens is identical to the converter's array of reserve tokens * we take this input in order to allow specifying the corresponding reserve amounts in any order * * @param _reserveTokens array of reserve tokens * @param _reserveAmounts array of reserve amounts * @param _amount token amount */ function verifyLiquidityInput(IERC20Token[] memory _reserveTokens, uint256[] memory _reserveAmounts, uint256 _amount) private view { uint256 i; uint256 j; uint256 length = reserveTokens.length; require(length == _reserveTokens.length, "ERR_INVALID_RESERVE"); require(length == _reserveAmounts.length, "ERR_INVALID_AMOUNT"); for (i = 0; i < length; i++) { // verify that every input reserve token is included in the reserve tokens require(reserves[_reserveTokens[i]].isSet, "ERR_INVALID_RESERVE"); for (j = 0; j < length; j++) { if (reserveTokens[i] == _reserveTokens[j]) break; } // verify that every reserve token is included in the input reserve tokens require(j < length, "ERR_INVALID_RESERVE"); // verify that every input reserve token amount is larger than zero require(_reserveAmounts[i] > 0, "ERR_INVALID_AMOUNT"); } // verify that the input token amount is larger than zero require(_amount > 0, "ERR_ZERO_AMOUNT"); } /** * @dev adds liquidity (reserve) to the pool * * @param _reserveTokens address of each reserve token * @param _reserveAmounts amount of each reserve token * @param _totalSupply token total supply */ function addLiquidityToPool(IERC20Token[] memory _reserveTokens, uint256[] memory _reserveAmounts, uint256 _totalSupply) private returns (uint256) { if (_totalSupply == 0) return addLiquidityToEmptyPool(_reserveTokens, _reserveAmounts); return addLiquidityToNonEmptyPool(_reserveTokens, _reserveAmounts, _totalSupply); } /** * @dev adds liquidity (reserve) to the pool when it's empty * * @param _reserveTokens address of each reserve token * @param _reserveAmounts amount of each reserve token */ function addLiquidityToEmptyPool(IERC20Token[] memory _reserveTokens, uint256[] memory _reserveAmounts) private returns (uint256) { // calculate the geometric-mean of the reserve amounts approved by the user uint256 amount = geometricMean(_reserveAmounts); // transfer each one of the reserve amounts from the user to the pool for (uint256 i = 0; i < _reserveTokens.length; i++) { if (_reserveTokens[i] != ETH_RESERVE_ADDRESS) // ETH has already been transferred as part of the transaction safeTransferFrom(_reserveTokens[i], msg.sender, this, _reserveAmounts[i]); reserves[_reserveTokens[i]].balance = _reserveAmounts[i]; emit LiquidityAdded(msg.sender, _reserveTokens[i], _reserveAmounts[i], _reserveAmounts[i], amount); // dispatch the `TokenRateUpdate` event for the pool token uint32 reserveWeight = reserves[_reserveTokens[i]].weight; dispatchPoolTokenRateEvent(amount, _reserveTokens[i], _reserveAmounts[i], reserveWeight); } return amount; } /** * @dev adds liquidity (reserve) to the pool when it's not empty * * @param _reserveTokens address of each reserve token * @param _reserveAmounts amount of each reserve token * @param _totalSupply token total supply */ function addLiquidityToNonEmptyPool(IERC20Token[] memory _reserveTokens, uint256[] memory _reserveAmounts, uint256 _totalSupply) private returns (uint256) { syncReserveBalances(); reserves[ETH_RESERVE_ADDRESS].balance = reserves[ETH_RESERVE_ADDRESS].balance.sub(msg.value); IBancorFormula formula = IBancorFormula(addressOf(BANCOR_FORMULA)); uint256 amount = getMinShare(_totalSupply, _reserveTokens, _reserveAmounts); for (uint256 i = 0; i < _reserveTokens.length; i++) { IERC20Token reserveToken = _reserveTokens[i]; uint256 rsvBalance = reserves[reserveToken].balance; uint256 reserveAmount = formula.fundCost(_totalSupply, rsvBalance, reserveRatio, amount); require(reserveAmount > 0, "ERR_ZERO_RATE"); assert(reserveAmount <= _reserveAmounts[i]); // transfer each one of the reserve amounts from the user to the pool if (reserveToken != ETH_RESERVE_ADDRESS) // ETH has already been transferred as part of the transaction safeTransferFrom(reserveToken, msg.sender, this, reserveAmount); else if (_reserveAmounts[i] > reserveAmount) // transfer the extra amount of ETH back to the user msg.sender.transfer(_reserveAmounts[i] - reserveAmount); uint256 newReserveBalance = rsvBalance.add(reserveAmount); reserves[reserveToken].balance = newReserveBalance; uint256 newPoolTokenSupply = _totalSupply.add(amount); emit LiquidityAdded(msg.sender, reserveToken, reserveAmount, newReserveBalance, newPoolTokenSupply); // dispatch the `TokenRateUpdate` event for the pool token uint32 reserveWeight = reserves[_reserveTokens[i]].weight; dispatchPoolTokenRateEvent(newPoolTokenSupply, _reserveTokens[i], newReserveBalance, reserveWeight); } return amount; } /** * @dev removes liquidity (reserve) from the pool * * @param _reserveTokens address of each reserve token * @param _reserveMinReturnAmounts minimum return-amount of each reserve token * @param _totalSupply token total supply * @param _amount token amount */ function removeLiquidityFromPool(IERC20Token[] memory _reserveTokens, uint256[] memory _reserveMinReturnAmounts, uint256 _totalSupply, uint256 _amount) private { syncReserveBalances(); IBancorFormula formula = IBancorFormula(addressOf(BANCOR_FORMULA)); for (uint256 i = 0; i < _reserveTokens.length; i++) { IERC20Token reserveToken = _reserveTokens[i]; uint256 rsvBalance = reserves[reserveToken].balance; uint256 reserveAmount = formula.liquidateRate(_totalSupply, rsvBalance, reserveRatio, _amount); require(reserveAmount >= _reserveMinReturnAmounts[i], "ERR_ZERO_RATE"); uint256 newReserveBalance = rsvBalance.sub(reserveAmount); reserves[reserveToken].balance = newReserveBalance; // transfer each one of the reserve amounts from the pool to the user if (reserveToken == ETH_RESERVE_ADDRESS) msg.sender.transfer(reserveAmount); else safeTransfer(reserveToken, msg.sender, reserveAmount); uint256 newPoolTokenSupply = _totalSupply.sub(_amount); emit LiquidityRemoved(msg.sender, reserveToken, reserveAmount, newReserveBalance, newPoolTokenSupply); // dispatch the `TokenRateUpdate` event for the pool token uint32 reserveWeight = reserves[reserveToken].weight; dispatchPoolTokenRateEvent(newPoolTokenSupply, reserveToken, newReserveBalance, reserveWeight); } } function getMinShare(uint256 _totalSupply, IERC20Token[] memory _reserveTokens, uint256[] memory _reserveAmounts) private view returns (uint256) { uint256 minShare = getShare(_totalSupply, reserves[_reserveTokens[0]].balance, _reserveAmounts[0]); for (uint256 i = 1; i < _reserveTokens.length; i++) { uint256 share = getShare(_totalSupply, reserves[_reserveTokens[i]].balance, _reserveAmounts[i]); if (minShare > share) minShare = share; } return minShare; } function getShare(uint256 _totalSupply, uint256 _reserveBalance, uint256 _reserveAmount) private view returns (uint256) { return _totalSupply.mul(_reserveAmount).mul(reserveRatio).div(_reserveBalance.add(_reserveAmount).mul(WEIGHT_RESOLUTION)); } /** * @dev calculates the number of decimal digits in a given value * * @param _x value (assumed positive) * @return the number of decimal digits in the given value */ function decimalLength(uint256 _x) public pure returns (uint256) { uint256 y = 0; for (uint256 x = _x; x > 0; x /= 10) y++; return y; } /** * @dev calculates the nearest integer to a given quotient * * @param _n quotient numerator * @param _d quotient denominator * @return the nearest integer to the given quotient */ function roundDiv(uint256 _n, uint256 _d) public pure returns (uint256) { return (_n + _d / 2) / _d; } /** * @dev calculates the average number of decimal digits in a given list of values * * @param _values list of values (each of which assumed positive) * @return the average number of decimal digits in the given list of values */ function geometricMean(uint256[] memory _values) public pure returns (uint256) { uint256 numOfDigits = 0; uint256 length = _values.length; for (uint256 i = 0; i < length; i++) numOfDigits += decimalLength(_values[i]); return uint256(10) ** (roundDiv(numOfDigits, length) - 1); } /** * @dev dispatches rate events for both reserves / pool tokens * only used to circumvent the `stack too deep` compiler error * * @param _sourceToken address of the source reserve token * @param _targetToken address of the target reserve token */ function dispatchRateEvents(IERC20Token _sourceToken, IERC20Token _targetToken) private { uint256 poolTokenSupply = ISmartToken(anchor).totalSupply(); uint256 sourceReserveBalance = reserveBalance(_sourceToken); uint256 targetReserveBalance = reserveBalance(_targetToken); uint32 sourceReserveWeight = reserves[_sourceToken].weight; uint32 targetReserveWeight = reserves[_targetToken].weight; // dispatch token rate update event uint256 rateN = targetReserveBalance.mul(sourceReserveWeight); uint256 rateD = sourceReserveBalance.mul(targetReserveWeight); emit TokenRateUpdate(_sourceToken, _targetToken, rateN, rateD); // dispatch the `TokenRateUpdate` event for the pool token dispatchPoolTokenRateEvent(poolTokenSupply, _sourceToken, sourceReserveBalance, sourceReserveWeight); dispatchPoolTokenRateEvent(poolTokenSupply, _targetToken, targetReserveBalance, targetReserveWeight); // dispatch price data update events (deprecated events) emit PriceDataUpdate(_sourceToken, poolTokenSupply, sourceReserveBalance, sourceReserveWeight); emit PriceDataUpdate(_targetToken, poolTokenSupply, targetReserveBalance, targetReserveWeight); } /** * @dev dispatches the `TokenRateUpdate` for the pool token * only used to circumvent the `stack too deep` compiler error * * @param _poolTokenSupply total pool token supply * @param _reserveToken address of the reserve token * @param _reserveBalance reserve balance * @param _reserveWeight reserve weight */ function dispatchPoolTokenRateEvent(uint256 _poolTokenSupply, IERC20Token _reserveToken, uint256 _reserveBalance, uint32 _reserveWeight) private { emit TokenRateUpdate(anchor, _reserveToken, _reserveBalance.mul(WEIGHT_RESOLUTION), _poolTokenSupply.mul(_reserveWeight)); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"constant":false,"inputs":[{"name":"_anchor","type":"address"},{"name":"_registry","type":"address"},{"name":"_maxConversionFee","type":"uint32"}],"name":"createConverter","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"converterType","outputs":[{"name":"","type":"uint16"}],"payable":false,"stateMutability":"pure","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50614d3e806100206000396000f30060806040526004361061004b5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631141395881146100505780633e8ff43f146100b6575b600080fd5b34801561005c57600080fd5b5061008d73ffffffffffffffffffffffffffffffffffffffff6004358116906024351663ffffffff604435166100e2565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b3480156100c257600080fd5b506100cb6101d5565b6040805161ffff9092168252519081900360200190f35b6000808484846100f06101da565b73ffffffffffffffffffffffffffffffffffffffff938416815291909216602082015263ffffffff9091166040808301919091525190819003606001906000f080158015610142573d6000803e3d6000fd5b50604080517ff2fde38b000000000000000000000000000000000000000000000000000000008152336004820152905191925073ffffffffffffffffffffffffffffffffffffffff83169163f2fde38b9160248082019260009290919082900301818387803b1580156101b457600080fd5b505af11580156101c8573d6000803e3d6000fd5b5092979650505050505050565b600190565b604051614b28806101eb83390190560060806040526003805460a860020a60ff02191690557fc0829421c1d260bd3cb3e0f06cfe2d52db2ce3150000000000000000000000006008553480156200004557600080fd5b5060405160608062004b2883398101604090815281516020830151919092015160008054600160a060020a031916331790558282828282828180620000938164010000000062000140810204565b5060028054600160a060020a03909216600160a060020a031992831681179091556003805490921617905582620000d38164010000000062000140810204565b81620000e881640100000000620001bb810204565b505060048054600160a060020a03909416600160a060020a031990941693909317909255506008805463ffffffff9092166401000000000267ffffffff00000000199092169190911790555062000234945050505050565b600160a060020a0381161515620001b857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4552525f494e56414c49445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b50565b620f424063ffffffff82161115620001b857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4552525f494e56414c49445f434f4e56455253494f4e5f464545000000000000604482015290519081900360640190fd5b6148e480620002446000396000f3006080604052600436106102585763ffffffff60e060020a600035041663024c7ec781146102e45780630c7d5cd8146102fe5780630e53aae91461032c57806312c2aca41461038157806319b64015146103aa5780631cfab290146103de5780631e1401f8146103ff57806321e6b53d1461044257806322f3e2d4146104635780632fe8a6ad1461047857806338a5e0161461048d578063395900d4146104a25780633e8ff43f146104cc578063415f1240146104f857806348dc399b1461051057806349d10b641461053a5780634af80f0e1461054f57806354fd4d5014610570578063579cd3ca146105855780635e35359e1461059a57806361cd756e146105c457806367b6d57c146105d9578063690d8320146105fa5780636a49d2c41461061b5780636aa5332c1461064557806371f52bf31461066f57806379ba5097146106845780637b103999146106995780637d8916bd146106ae5780638da5cb5b1461073157806394c275ad146107465780639b99a8e21461075b578063a60e772414610770578063b127c0a5146107c5578063b4a176d314610858578063bbb7e5d81461086d578063bf75455814610888578063c45d3d921461089d578063ca1d209d146108b2578063cdc91c69146108bd578063d031370b146108d2578063d260529c146108ea578063d3fb73b4146108ff578063d4ee1d9014610914578063d55ec69714610929578063d66bd5241461093e578063d89595121461095f578063dc8de37914610980578063e8dc12ff146109a1578063ecbca55d146109cb578063f2fde38b146109e9578063fc0c546a14610a0a575b60008051602061483983398151915260005260076020527fb2084a3e4595ccf007fb44245853374aaf0de960074375e8e0fb334712e94d0f546601000000000000900460ff1615156102e2576040805160e560020a62461bcd02815260206004820152601360248201526000805160206147f9833981519152604482015290519081900360640190fd5b005b3480156102f057600080fd5b506102e26004351515610a1f565b34801561030a57600080fd5b50610313610a67565b6040805163ffffffff9092168252519081900360200190f35b34801561033857600080fd5b5061034d600160a060020a0360043516610a73565b6040805195865263ffffffff9094166020860152911515848401521515606084015215156080830152519081900360a00190f35b34801561038d57600080fd5b50610396610b0e565b604080519115158252519081900360200190f35b3480156103b657600080fd5b506103c2600435610b57565b60408051600160a060020a039092168252519081900360200190f35b3480156103ea57600080fd5b50610313600160a060020a0360043516610b83565b34801561040b57600080fd5b50610429600160a060020a0360043581169060243516604435610bb5565b6040805192835260208301919091528051918290030190f35b34801561044e57600080fd5b506102e2600160a060020a0360043516610bcf565b34801561046f57600080fd5b50610396610be3565b34801561048457600080fd5b50610396610c7c565b34801561049957600080fd5b506102e2610c9d565b3480156104ae57600080fd5b506102e2600160a060020a0360043581169060243516604435610d0a565b3480156104d857600080fd5b506104e1610da9565b6040805161ffff9092168252519081900360200190f35b34801561050457600080fd5b506102e2600435610dae565b34801561051c57600080fd5b50610429600160a060020a0360043581169060243516604435611002565b34801561054657600080fd5b506102e26111a7565b34801561055b57600080fd5b506102e2600160a060020a0360043516611414565b34801561057c57600080fd5b506104e1611456565b34801561059157600080fd5b5061031361145b565b3480156105a657600080fd5b506102e2600160a060020a0360043581169060243516604435611473565b3480156105d057600080fd5b506103c261158d565b3480156105e557600080fd5b506102e2600160a060020a036004351661159c565b34801561060657600080fd5b506102e2600160a060020a0360043516611643565b34801561062757600080fd5b506102e2600160a060020a036004351663ffffffff60243516611764565b34801561065157600080fd5b5061065d6004356119a3565b60408051918252519081900360200190f35b34801561067b57600080fd5b506104e16119c8565b34801561069057600080fd5b506102e26119d7565b3480156106a557600080fd5b506103c2611a98565b604080516020600480358082013583810280860185019096528085526102e295369593946024949385019291829185019084908082843750506040805187358901803560208181028481018201909552818452989b9a9989019892975090820195509350839250850190849080828437509497505093359450611aa79350505050565b34801561073d57600080fd5b506103c2611db7565b34801561075257600080fd5b50610313611dc6565b34801561076757600080fd5b506104e1611dda565b34801561077c57600080fd5b506040805160206004803580820135838102808601850190965280855261065d95369593946024949385019291829185019084908082843750949750611de09650505050505050565b3480156107d157600080fd5b506040805160206004602480358281013584810280870186019097528086526102e296843596369660449591949091019291829185019084908082843750506040805187358901803560208181028481018201909552818452989b9a998901989297509082019550935083925085019084908082843750949750611e369650505050505050565b34801561086457600080fd5b506102e2611f6f565b34801561087957600080fd5b5061065d600435602435611fa8565b34801561089457600080fd5b50610396611fc2565b3480156108a957600080fd5b506103c2611fc7565b6102e2600435611fd6565b3480156108c957600080fd5b506102e26124ec565b3480156108de57600080fd5b506103c2600435612545565b3480156108f657600080fd5b50610396610da9565b34801561090b57600080fd5b506103c261256d565b34801561092057600080fd5b506103c261257c565b34801561093557600080fd5b506102e261258b565b34801561094a57600080fd5b5061034d600160a060020a0360043516612638565b34801561096b57600080fd5b5061065d600160a060020a036004351661267e565b34801561098c57600080fd5b5061065d600160a060020a036004351661268f565b61065d600160a060020a0360043581169060243581169060443590606435811690608435166126b8565b3480156109d757600080fd5b506102e263ffffffff60043516612927565b3480156109f557600080fd5b506102e2600160a060020a0360043516612a1c565b348015610a1657600080fd5b506103c2612ab9565b610a27612ac8565b60038054911515740100000000000000000000000000000000000000000274ff000000000000000000000000000000000000000019909216919091179055565b60085463ffffffff1681565b6000806000806000610a836147ab565b50505050600160a060020a03929092166000908152600760209081526040808320815160a081018352815480825260019092015463ffffffff811694820185905260ff64010000000082048116151594830194909452650100000000008104841615156060830152660100000000000090049092161515608090920182905295919450919250829190565b60008051602061483983398151915260005260076020527fb2084a3e4595ccf007fb44245853374aaf0de960074375e8e0fb334712e94d0f546601000000000000900460ff1690565b6000600682815481101515610b6857fe5b600091825260209091200154600160a060020a031692915050565b600081610b8f81612b18565b5050600160a060020a031660009081526007602052604090206001015463ffffffff1690565b600080610bc3858585611002565b91509150935093915050565b610bd7612ac8565b610be08161159c565b50565b60048054604080517f8da5cb5b00000000000000000000000000000000000000000000000000000000815290516000933093600160a060020a031692638da5cb5b928183019260209282900301818887803b158015610c4157600080fd5b505af1158015610c55573d6000803e3d6000fd5b505050506040513d6020811015610c6b57600080fd5b5051600160a060020a031614905090565b60035474010000000000000000000000000000000000000000900460ff1681565b6001610ca7611dda565b61ffff1611610d00576040805160e560020a62461bcd02815260206004820152601960248201527f4552525f494e56414c49445f524553455256455f434f554e5400000000000000604482015290519081900360640190fd5b610d08612b85565b565b610d12612ac8565b60048054604080517f5e35359e000000000000000000000000000000000000000000000000000000008152600160a060020a038781169482019490945285841660248201526044810185905290519290911691635e35359e9160648082019260009290919082900301818387803b158015610d8c57600080fd5b505af1158015610da0573d6000803e3d6000fd5b50505050505050565b600190565b600060606000610dbc612b95565b6003805460a860020a60ff02191660a860020a17905560008411610e2a576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f5a45524f5f414d4f554e540000000000000000000000000000000000604482015290519081900360640190fd5b600480546040805160e060020a6318160ddd0281529051600160a060020a03909216926318160ddd9282820192602092908290030181600087803b158015610e7157600080fd5b505af1158015610e85573d6000803e3d6000fd5b505050506040513d6020811015610e9b57600080fd5b505160048054604080517fa24835d100000000000000000000000000000000000000000000000000000000815233938101939093526024830188905251929550600160a060020a03169163a24835d19160448082019260009290919082900301818387803b158015610f0c57600080fd5b505af1158015610f20573d6000803e3d6000fd5b50505050600680549050604051908082528060200260200182016040528015610f53578160200160208202803883390190505b509150600090505b8151811015610f865760018282815181101515610f7457fe5b60209081029091010152600101610f5b565b610fec6006805480602002602001604051908101604052809291908181526020018280548015610fdf57602002820191906000526020600020905b8154600160a060020a03168152600190910190602001808311610fc1575b5050505050838587612bf7565b50506003805460a860020a60ff02191690555050565b600080600080611010612ebe565b8661101a81612b18565b8661102481612b18565b600160a060020a038981169089161415611088576040805160e560020a62461bcd02815260206004820152601660248201527f4552525f53414d455f534f555243455f54415247455400000000000000000000604482015290519081900360640190fd5b61109f600080516020614819833981519152612f1c565b600160a060020a0316639d1141086110b68b61268f565b600160a060020a038c1660009081526007602052604090206001015463ffffffff166110e18c61268f565b600160a060020a038d16600090815260076020908152604080832060010154815163ffffffff89811660e060020a028252600482019890985295871660248701526044860194909452949092166064840152608483018d9052925160a48084019492939192918390030190829087803b15801561115d57600080fd5b505af1158015611171573d6000803e3d6000fd5b505050506040513d602081101561118757600080fd5b5051935061119484612fb4565b9384900399939850929650505050505050565b60008054600160a060020a03163314806111dc575060035474010000000000000000000000000000000000000000900460ff16155b1515611220576040805160e560020a62461bcd0281526020600482015260116024820152600080516020614879833981519152604482015290519081900360640190fd5b6112497f436f6e7472616374526567697374727900000000000000000000000000000000612f1c565b600254909150600160a060020a038083169116148015906112725750600160a060020a03811615155b15156112c8576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e56414c49445f5245474953545259000000000000000000000000604482015290519081900360640190fd5b604080517fbb34534c0000000000000000000000000000000000000000000000000000000081527f436f6e747261637452656769737472790000000000000000000000000000000060048201529051600091600160a060020a0384169163bb34534c9160248082019260209290919082900301818787803b15801561134c57600080fd5b505af1158015611360573d6000803e3d6000fd5b505050506040513d602081101561137657600080fd5b5051600160a060020a031614156113d7576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e56414c49445f5245474953545259000000000000000000000000604482015290519081900360640190fd5b6002805460038054600160a060020a0380841673ffffffffffffffffffffffffffffffffffffffff19928316179092559091169216919091179055565b61141c612ac8565b8061142681612ff0565b506005805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b601d81565b60085468010000000000000000900463ffffffff1681565b600061147d612b95565b6003805460a860020a60ff02191660a860020a17905561149b612ac8565b6114b2600080516020614859833981519152612f1c565b600160a060020a0385166000908152600760205260409020600101549091506601000000000000900460ff1615806114ef57506114ed610be3565b155b806115075750600054600160a060020a038281169116145b151561154b576040805160e560020a62461bcd0281526020600482015260116024820152600080516020614879833981519152604482015290519081900360640190fd5b611556848484613051565b600160a060020a0384166000908152600760205260409020600101546601000000000000900460ff1615610fec57610fec84613082565b600354600160a060020a031681565b6115a4612ac8565b6000805160206148598339815191526115bc81613177565b60048054604080517ff2fde38b000000000000000000000000000000000000000000000000000000008152600160a060020a03868116948201949094529051929091169163f2fde38b9160248082019260009290919082900301818387803b15801561162757600080fd5b505af115801561163b573d6000803e3d6000fd5b505050505050565b600061164d612b95565b6003805460a860020a60ff02191660a860020a17905561166b612ac8565b60008051602061483983398151915261168381612b18565b61169a600080516020614859833981519152612f1c565b91506116a4610be3565b15806116bd5750600054600160a060020a038381169116145b1515611701576040805160e560020a62461bcd0281526020600482015260116024820152600080516020614879833981519152604482015290519081900360640190fd5b604051600160a060020a03841690303180156108fc02916000818181858888f19350505050158015611737573d6000803e3d6000fd5b5061174f600080516020614839833981519152613082565b50506003805460a860020a60ff021916905550565b600061176e612ac8565b6117766131cd565b826117808161322a565b8361178a81612ff0565b836117948161328a565b600454600160a060020a038781169116148015906117d85750600160a060020a0386166000908152600760205260409020600101546601000000000000900460ff16155b151561181c576040805160e560020a62461bcd02815260206004820152601360248201526000805160206147f9833981519152604482015290519081900360640190fd5b60085463ffffffff908116620f42400381169086161115611887576040805160e560020a62461bcd02815260206004820152601a60248201527f4552525f494e56414c49445f524553455256455f574549474854000000000000604482015290519081900360640190fd5b61ffff611892611dda565b61ffff16106118eb576040805160e560020a62461bcd02815260206004820152601960248201527f4552525f494e56414c49445f524553455256455f434f554e5400000000000000604482015290519081900360640190fd5b505050600160a060020a0390921660008181526007602052604081208181556001908101805466ff0000000000001963ffffffff80881663ffffffff1993841617919091166601000000000000179092556006805493840181559093527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f909101805473ffffffffffffffffffffffffffffffffffffffff191690931790925560088054808416909401909216921691909117905550565b600080825b60008111156119c15760019190910190600a90046119a8565b5092915050565b60006119d2611dda565b905090565b600154600160a060020a03163314611a27576040805160e560020a62461bcd0281526020600482015260116024820152600080516020614879833981519152604482015290519081900360640190fd5b60015460008054604051600160a060020a0393841693909116917f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a91a3600180546000805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a03841617909155169055565b600254600160a060020a031681565b6000806000611ab4612b95565b6003805460a860020a60ff02191660a860020a179055611ad2612ebe565b611add8686866132ff565b600092505b8551831015611b9b57855160008051602061483983398151915290879085908110611b0957fe5b90602001906020020151600160a060020a03161415611b9057348584815181101515611b3157fe5b6020908102909101015114611b90576040805160e560020a62461bcd02815260206004820152601760248201527f4552525f4554485f414d4f554e545f4d49534d41544348000000000000000000604482015290519081900360640190fd5b600190920191611ae2565b6000341115611c405760008051602061483983398151915260005260076020527fb2084a3e4595ccf007fb44245853374aaf0de960074375e8e0fb334712e94d0f546601000000000000900460ff161515611c40576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f4e4f5f4554485f524553455256450000000000000000000000000000604482015290519081900360640190fd5b600480546040805160e060020a6318160ddd0281529051600160a060020a03909216926318160ddd9282820192602092908290030181600087803b158015611c8757600080fd5b505af1158015611c9b573d6000803e3d6000fd5b505050506040513d6020811015611cb157600080fd5b50519150611cc08686846135bb565b905083811015611d1a576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f52455455524e5f544f4f5f4c4f570000000000000000000000000000604482015290519081900360640190fd5b60048054604080517f867904b400000000000000000000000000000000000000000000000000000000815233938101939093526024830184905251600160a060020a039091169163867904b491604480830192600092919082900301818387803b158015611d8757600080fd5b505af1158015611d9b573d6000803e3d6000fd5b50506003805460a860020a60ff02191690555050505050505050565b600054600160a060020a031681565b600854640100000000900463ffffffff1681565b60065490565b80516000908190815b81811015611e1d57611e118582815181101515611e0257fe5b906020019060200201516119a3565b90920191600101611de9565b6001611e298484611fa8565b03600a0a95945050505050565b6000611e40612b95565b6003805460a860020a60ff02191660a860020a179055611e5e612ebe565b611e698383866132ff565b600480546040805160e060020a6318160ddd0281529051600160a060020a03909216926318160ddd9282820192602092908290030181600087803b158015611eb057600080fd5b505af1158015611ec4573d6000803e3d6000fd5b505050506040513d6020811015611eda57600080fd5b505160048054604080517fa24835d100000000000000000000000000000000000000000000000000000000815233938101939093526024830188905251929350600160a060020a03169163a24835d19160448082019260009290919082900301818387803b158015611f4b57600080fd5b505af1158015611f5f573d6000803e3d6000fd5b50505050610fec83838387612bf7565b611f77612ac8565b6003546002805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03909216919091179055565b600081600281048401811515611fba57fe5b049392505050565b600181565b600554600160a060020a031681565b600080600080600080600080600080611fed612b95565b6003805460a860020a60ff02191660a860020a17905561200b6135ea565b600080516020614839833981519152600052600760205260008051602061489983398151915254612042903463ffffffff61362c16565b60008051602061483983398151915260009081526007602090815260008051602061489983398151915292909255600480546040805160e060020a6318160ddd0281529051600160a060020a03909216946318160ddd948285019491939283900390910190829087803b1580156120b857600080fd5b505af11580156120cc573d6000803e3d6000fd5b505050506040513d60208110156120e257600080fd5b505199506120fd600080516020614819833981519152612f1c565b6006549099509750600096505b8787101561244a57600680548890811061212057fe5b9060005260206000200160009054906101000a9004600160a060020a031695506007600087600160a060020a0316600160a060020a0316815260200190815260200160002060000154945088600160a060020a031663ebbb21588b87600860009054906101000a900463ffffffff168f6040518563ffffffff1660e060020a028152600401808581526020018481526020018363ffffffff1663ffffffff168152602001828152602001945050505050602060405180830381600087803b1580156121ea57600080fd5b505af11580156121fe573d6000803e3d6000fd5b505050506040513d602081101561221457600080fd5b50519350600160a060020a038616600080516020614839833981519152141561237657833411156122745760405133903486900380156108fc02916000818181858888f1935050505015801561226e573d6000803e3d6000fd5b50612371565b833410156123715734156122d2576040805160e560020a62461bcd02815260206004820152601560248201527f4552525f494e56414c49445f4554485f56414c55450000000000000000000000604482015290519081900360640190fd5b6008546122fa906c010000000000000000000000009004600160a060020a031633308761368c565b6008600c9054906101000a9004600160a060020a0316600160a060020a0316632e1a7d4d856040518263ffffffff1660e060020a02815260040180828152602001915050600060405180830381600087803b15801561235857600080fd5b505af115801561236c573d6000803e3d6000fd5b505050505b612382565b6123828633308761368c565b612392858563ffffffff61377416565b600160a060020a038716600090815260076020526040902081905592506123bf8a8c63ffffffff61377416565b60408051868152602081018690528082018390529051919350600160a060020a0388169133917f4a1a2a6176e9646d9e3157f7c2ab3c499f18337c0b0828cfb28e0a61de4a11f7919081900360600190a350600160a060020a03851660009081526007602052604090206001015463ffffffff1661243f828785846137d1565b60019096019561210a565b60048054604080517f867904b40000000000000000000000000000000000000000000000000000000081523393810193909352602483018e905251600160a060020a039091169163867904b491604480830192600092919082900301818387803b1580156124b757600080fd5b505af11580156124cb573d6000803e3d6000fd5b50506003805460a860020a60ff021916905550505050505050505050505050565b6124f4612ac8565b6124fc613840565b60045460408051600160a060020a0390921682526001602083015280517fa170412ae067fdeca19fd2204ce7eb66f723d827f4af15433b6f33f7fdc642bb9281900390910190a1565b600680548290811061255357fe5b600091825260209091200154600160a060020a0316905081565b600454600160a060020a031681565b600154600160a060020a031681565b6000612595612ac8565b6125ac600080516020614859833981519152612f1c565b90506125b781612a1c565b604080517f90f58c96000000000000000000000000000000000000000000000000000000008152601d60048201529051600160a060020a038316916390f58c9691602480830192600092919082900301818387803b15801561261857600080fd5b505af115801561262c573d6000803e3d6000fd5b50505050610be06119d7565b6007602052600090815260409020805460019091015463ffffffff81169060ff640100000000820481169165010000000000810482169166010000000000009091041685565b60006126898261268f565b92915050565b60008161269b81612b18565b5050600160a060020a031660009081526007602052604090205490565b60006126c2612b95565b6003805460a860020a60ff02191660a860020a1790557f42616e636f724e6574776f726b0000000000000000000000000000000000000061270281613177565b600160a060020a038781169087161415612766576040805160e560020a62461bcd02815260206004820152601660248201527f4552525f53414d455f534f555243455f54415247455400000000000000000000604482015290519081900360640190fd5b600554600160a060020a031615806128a95750600554604080517f3af32abf000000000000000000000000000000000000000000000000000000008152600160a060020a03878116600483015291519190921691633af32abf9160248083019260209291908290030181600087803b1580156127e157600080fd5b505af11580156127f5573d6000803e3d6000fd5b505050506040513d602081101561280b57600080fd5b505180156128a95750600554604080517f3af32abf000000000000000000000000000000000000000000000000000000008152600160a060020a03868116600483015291519190921691633af32abf9160248083019260209291908290030181600087803b15801561287c57600080fd5b505af1158015612890573d6000803e3d6000fd5b505050506040513d60208110156128a657600080fd5b50515b15156128ff576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f4e4f545f57484954454c495354454400000000000000000000000000604482015290519081900360640190fd5b61290c8787878787613927565b6003805460a860020a60ff0219169055979650505050505050565b61292f612ac8565b60085463ffffffff6401000000009091048116908216111561299b576040805160e560020a62461bcd02815260206004820152601a60248201527f4552525f494e56414c49445f434f4e56455253494f4e5f464545000000000000604482015290519081900360640190fd5b6008546040805163ffffffff6801000000000000000090930483168152918316602083015280517f81cd2ffb37dd237c0e4e2a3de5265fcf9deb43d3e7801e80db9f1ccfba7ee6009281900390910190a16008805463ffffffff90921668010000000000000000026bffffffff000000000000000019909216919091179055565b612a24612ac8565b600054600160a060020a0382811691161415612a8a576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f53414d455f4f574e4552000000000000000000000000000000000000604482015290519081900360640190fd5b6001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600454600160a060020a031690565b600054600160a060020a03163314610d08576040805160e560020a62461bcd0281526020600482015260116024820152600080516020614879833981519152604482015290519081900360640190fd5b600160a060020a0381166000908152600760205260409020600101546601000000000000900460ff161515610be0576040805160e560020a62461bcd02815260206004820152601360248201526000805160206147f9833981519152604482015290519081900360640190fd5b612b8d612ac8565b610d086124ec565b60035460a860020a900460ff1615610d08576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f5245454e5452414e4359000000000000000000000000000000000000604482015290519081900360640190fd5b600080600080600080600080612c0b6135ea565b612c22600080516020614819833981519152612f1c565b9750600096505b8b51871015612eb0578b87815181101515612c4057fe5b9060200190602002015195506007600087600160a060020a0316600160a060020a0316815260200190815260200160002060000154945087600160a060020a03166335b49af48b87600860009054906101000a900463ffffffff168d6040518563ffffffff1660e060020a028152600401808581526020018481526020018363ffffffff1663ffffffff168152602001828152602001945050505050602060405180830381600087803b158015612cf657600080fd5b505af1158015612d0a573d6000803e3d6000fd5b505050506040513d6020811015612d2057600080fd5b50518b519094508b9088908110612d3357fe5b60209081029091010151841015612d94576040805160e560020a62461bcd02815260206004820152600d60248201527f4552525f5a45524f5f5241544500000000000000000000000000000000000000604482015290519081900360640190fd5b612da4858563ffffffff61362c16565b600160a060020a03871660008181526007602052604090208290559093506000805160206148398339815191521415612e0a57604051339085156108fc029086906000818181858888f19350505050158015612e04573d6000803e3d6000fd5b50612e15565b612e15863386613bfa565b612e258a8a63ffffffff61362c16565b60408051868152602081018690528082018390529051919350600160a060020a0388169133917fbc7d19d505c7ec4db83f3b51f19fb98c4c8a99922e7839d1ee608dfbee29501b919081900360600190a350600160a060020a03851660009081526007602052604090206001015463ffffffff16612ea5828785846137d1565b600190960195612c29565b505050505050505050505050565b612ec6610be3565b1515610d08576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f494e4143544956450000000000000000000000000000000000000000604482015290519081900360640190fd5b600254604080517fbb34534c000000000000000000000000000000000000000000000000000000008152600481018490529051600092600160a060020a03169163bb34534c91602480830192602092919082900301818787803b158015612f8257600080fd5b505af1158015612f96573d6000803e3d6000fd5b505050506040513d6020811015612fac57600080fd5b505192915050565b60085460009061268990620f424090612fe490859063ffffffff68010000000000000000909104811690613cb116565b9063ffffffff613d2a16565b600160a060020a038116301415610be0576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f414444524553535f49535f53454c4600000000000000000000000000604482015290519081900360640190fd5b613059612ac8565b826130638161322a565b8261306d8161322a565b8361307781612ff0565b61163b868686613bfa565b8061308c81612b18565b600160a060020a03821660008051602061483983398151915214156130cc57600160a060020a038216600090815260076020526040902030319055613173565b604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051600160a060020a038416916370a082319160248083019260209291908290030181600087803b15801561312d57600080fd5b505af1158015613141573d6000803e3d6000fd5b505050506040513d602081101561315757600080fd5b5051600160a060020a0383166000908152600760205260409020555b5050565b61318081612f1c565b600160a060020a03163314610be0576040805160e560020a62461bcd0281526020600482015260116024820152600080516020614879833981519152604482015290519081900360640190fd5b6131d5610be3565b15610d08576040805160e560020a62461bcd02815260206004820152600a60248201527f4552525f41435449564500000000000000000000000000000000000000000000604482015290519081900360640190fd5b600160a060020a0381161515610be0576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f494e56414c49445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b60008163ffffffff161180156132a95750620f424063ffffffff821611155b1515610be0576040805160e560020a62461bcd02815260206004820152601a60248201527f4552525f494e56414c49445f524553455256455f574549474854000000000000604482015290519081900360640190fd5b60065483516000918291811461334d576040805160e560020a62461bcd02815260206004820152601360248201526000805160206147f9833981519152604482015290519081900360640190fd5b845181146133a5576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f494e56414c49445f414d4f554e540000000000000000000000000000604482015290519081900360640190fd5b600092505b80831015613563576007600087858151811015156133c457fe5b6020908102909101810151600160a060020a031682528101919091526040016000206001015460ff660100000000000090910416151561343c576040805160e560020a62461bcd02815260206004820152601360248201526000805160206147f9833981519152604482015290519081900360640190fd5b600091505b808210156134a457858281518110151561345757fe5b90602001906020020151600160a060020a031660068481548110151561347957fe5b600091825260209091200154600160a060020a03161415613499576134a4565b600190910190613441565b8082106134e9576040805160e560020a62461bcd02815260206004820152601360248201526000805160206147f9833981519152604482015290519081900360640190fd5b600085848151811015156134f957fe5b6020908102909101015111613558576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f494e56414c49445f414d4f554e540000000000000000000000000000604482015290519081900360640190fd5b6001909201916133aa565b6000841161163b576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f5a45524f5f414d4f554e540000000000000000000000000000000000604482015290519081900360640190fd5b60008115156135d5576135ce8484613d98565b90506135e3565b6135e0848484613f9f565b90505b9392505050565b60065460005b818110156131735761362460068281548110151561360a57fe5b600091825260209091200154600160a060020a0316613082565b6001016135f0565b600081831015613686576040805160e560020a62461bcd02815260206004820152600d60248201527f4552525f554e444552464c4f5700000000000000000000000000000000000000604482015290519081900360640190fd5b50900390565b604080517f7472616e7366657246726f6d28616464726573732c616464726573732c75696e81527f74323536290000000000000000000000000000000000000000000000000000006020808301919091528251918290036025018220600160a060020a038088166024850152861660448401526064808401869052845180850390910181526084909301909352810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff199093169290921790915261376e908590614366565b50505050565b6000828201838110156135e3576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b600454600160a060020a0380851691167f77f29993cf2c084e726f7e802da0719d6a0ade3e204badc7a3ffd57ecb768c2461380f85620f4240613cb1565b6138228863ffffffff80881690613cb116565b6040805192835260208301919091528051918290030190a350505050565b613848612ac8565b6000613852611dda565b61ffff16116138ab576040805160e560020a62461bcd02815260206004820152601960248201527f4552525f494e56414c49445f524553455256455f434f554e5400000000000000604482015290519081900360640190fd5b60048054604080517f79ba50970000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216926379ba509792828201926000929082900301818387803b15801561390757600080fd5b505af115801561391b573d6000803e3d6000fd5b50505050610d086135ea565b600080600080613938898989611002565b9093509150821515613994576040805160e560020a62461bcd02815260206004820152600d60248201527f4552525f5a45524f5f5241544500000000000000000000000000000000000000604482015290519081900360640190fd5b61399d8861268f565b90508083106139a857fe5b600160a060020a0389166000805160206148398339815191521415613a2357348714613a1e576040805160e560020a62461bcd02815260206004820152601760248201527f4552525f4554485f414d4f554e545f4d49534d41544348000000000000000000604482015290519081900360640190fd5b613b2b565b34158015613ad5575086613ad2613a398b61268f565b604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051600160a060020a038e16916370a082319160248083019260209291908290030181600087803b158015613a9a57600080fd5b505af1158015613aae573d6000803e3d6000fd5b505050506040513d6020811015613ac457600080fd5b50519063ffffffff61362c16565b10155b1515613b2b576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f494e56414c49445f414d4f554e540000000000000000000000000000604482015290519081900360640190fd5b613b3489613082565b600160a060020a038816600090815260076020526040902054613b5d908463ffffffff61362c16565b600160a060020a0389166000818152600760205260409020919091556000805160206148398339815191521415613bca57604051600160a060020a0386169084156108fc029085906000818181858888f19350505050158015613bc4573d6000803e3d6000fd5b50613bd5565b613bd5888685613bfa565b613be38989888a87876143f4565b613bed8989614479565b5090979650505050505050565b604080517f7472616e7366657228616464726573732c75696e74323536290000000000000081528151908190036019018120600160a060020a038516602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1990931692909217909152613cac908490614366565b505050565b600080831515613cc457600091506119c1565b50828202828482811515613cd457fe5b04146135e3576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b600080808311613d84576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f4449564944455f42595f5a45524f0000000000000000000000000000604482015290519081900360640190fd5b8284811515613d8f57fe5b04949350505050565b600080600080613da785611de0565b9250600091505b8551821015613f9557855160008051602061483983398151915290879084908110613dd557fe5b60209081029091010151600160a060020a031614613e2757613e278683815181101515613dfe57fe5b9060200190602002015133308886815181101515613e1857fe5b9060200190602002015161368c565b8482815181101515613e3557fe5b90602001906020020151600760008885815181101515613e5157fe5b6020908102909101810151600160a060020a03168252810191909152604001600020558551869083908110613e8257fe5b90602001906020020151600160a060020a031633600160a060020a03167f4a1a2a6176e9646d9e3157f7c2ab3c499f18337c0b0828cfb28e0a61de4a11f78785815181101515613ece57fe5b906020019060200201518886815181101515613ee657fe5b60209081029091018101516040805193845291830152818101889052519081900360600190a3600760008784815181101515613f1e57fe5b6020908102909101810151600160a060020a0316825281019190915260400160002060010154865163ffffffff9091169150613f8a908490889085908110613f6257fe5b906020019060200201518785815181101515613f7a57fe5b90602001906020020151846137d1565b600190910190613dae565b5090949350505050565b600080600080600080600080600080613fb66135ea565b600080516020614839833981519152600052600760205260008051602061489983398151915254613fed903463ffffffff61362c16565b60008051602061483983398151915260005260076020526000805160206148998339815191525561402b600080516020614819833981519152612f1c565b98506140388b8e8e614687565b9750600096505b8c51871015614355578c8781518110151561405657fe5b9060200190602002015195506007600087600160a060020a0316600160a060020a0316815260200190815260200160002060000154945088600160a060020a031663ebbb21588c87600860009054906101000a900463ffffffff168c6040518563ffffffff1660e060020a028152600401808581526020018481526020018363ffffffff1663ffffffff168152602001828152602001945050505050602060405180830381600087803b15801561410c57600080fd5b505af1158015614120573d6000803e3d6000fd5b505050506040513d602081101561413657600080fd5b5051935060008411614192576040805160e560020a62461bcd02815260206004820152600d60248201527f4552525f5a45524f5f5241544500000000000000000000000000000000000000604482015290519081900360640190fd5b8b878151811015156141a057fe5b602090810290910101518411156141b357fe5b600160a060020a038616600080516020614839833981519152146141e2576141dd8633308761368c565b614255565b838c888151811015156141f157fe5b9060200190602002015111156142555733600160a060020a03166108fc858e8a81518110151561421d57fe5b90602001906020020151039081150290604051600060405180830381858888f19350505050158015614253573d6000803e3d6000fd5b505b614265858563ffffffff61377416565b600160a060020a038716600090815260076020526040902081905592506142928b8963ffffffff61377416565b60408051868152602081018690528082018390529051919350600160a060020a0388169133917f4a1a2a6176e9646d9e3157f7c2ab3c499f18337c0b0828cfb28e0a61de4a11f7919081900360600190a3600760008e898151811015156142f557fe5b6020908102909101810151600160a060020a03168252810191909152604001600020600101548d5163ffffffff909116915061434a9083908f908a90811061433957fe5b9060200190602002015185846137d1565b60019096019561403f565b50959b9a5050505050505050505050565b61436e6147d9565b602060405190810160405280600181525090506020818351602085016000875af180151561439b57600080fd5b5080511515613cac576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f5452414e534645525f4641494c454400000000000000000000000000604482015290519081900360640190fd5b7f8000000000000000000000000000000000000000000000000000000000000000811061441d57fe5b60408051848152602081018490528082018390529051600160a060020a038087169288821692918a16917f276856b36cbc45526a0ba64f44611557a2a8b68662c5388e9fe6d72e86e1c8cb9181900360600190a4505050505050565b6000806000806000806000600460009054906101000a9004600160a060020a0316600160a060020a03166318160ddd6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156144d757600080fd5b505af11580156144eb573d6000803e3d6000fd5b505050506040513d602081101561450157600080fd5b5051965061450e8961268f565b95506145198861268f565b600160a060020a03808b16600090815260076020526040808220600190810154938d1683529120015491965063ffffffff908116955090811693506145629086908690613cb116565b91506145778663ffffffff80861690613cb116565b60408051848152602081018390528151929350600160a060020a03808c1693908d16927f77f29993cf2c084e726f7e802da0719d6a0ade3e204badc7a3ffd57ecb768c24928290030190a36145ce878a88876137d1565b6145da878987866137d1565b604080518881526020810188905263ffffffff8616818301529051600160a060020a038b16917f8a6a7f53b3c8fa1dc4b83e3f1be668c1b251ff8d44cdcb83eb3acec3fec6a788919081900360600190a2604080518881526020810187905263ffffffff8516818301529051600160a060020a038a16917f8a6a7f53b3c8fa1dc4b83e3f1be668c1b251ff8d44cdcb83eb3acec3fec6a788919081900360600190a2505050505050505050565b6000806000806146f087600760008960008151811015156146a457fe5b90602001906020020151600160a060020a0316600160a060020a03168152602001908152602001600020600001548760008151811015156146e157fe5b9060200190602002015161476b565b9250600191505b8551821015614760576147478760076000898681518110151561471657fe5b6020908102909101810151600160a060020a031682528101919091526040016000205487518890869081106146e157fe5b905080831115614755578092505b6001909101906146f7565b509095945050505050565b60006135e061478d620f42406147818686613774565b9063ffffffff613cb116565b600854612fe49063ffffffff908116906147819089908890613cb116565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b602060405190810160405280600190602082028038833950919291505056004552525f494e56414c49445f524553455256450000000000000000000000000042616e636f72466f726d756c6100000000000000000000000000000000000000000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee42616e636f72436f6e76657274657255706772616465720000000000000000004552525f4143434553535f44454e494544000000000000000000000000000000b2084a3e4595ccf007fb44245853374aaf0de960074375e8e0fb334712e94d0ea165627a7a7230582059c0b8af441dae51deb14e69367acf01fff003f2840aadf572e285e1d480403a0029a165627a7a7230582014b18720e70deb2ab87954abe96c4a85ea61b0d8f9d1dd08be84a10fa8952cb10029
Deployed Bytecode
0x60806040526004361061004b5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631141395881146100505780633e8ff43f146100b6575b600080fd5b34801561005c57600080fd5b5061008d73ffffffffffffffffffffffffffffffffffffffff6004358116906024351663ffffffff604435166100e2565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b3480156100c257600080fd5b506100cb6101d5565b6040805161ffff9092168252519081900360200190f35b6000808484846100f06101da565b73ffffffffffffffffffffffffffffffffffffffff938416815291909216602082015263ffffffff9091166040808301919091525190819003606001906000f080158015610142573d6000803e3d6000fd5b50604080517ff2fde38b000000000000000000000000000000000000000000000000000000008152336004820152905191925073ffffffffffffffffffffffffffffffffffffffff83169163f2fde38b9160248082019260009290919082900301818387803b1580156101b457600080fd5b505af11580156101c8573d6000803e3d6000fd5b5092979650505050505050565b600190565b604051614b28806101eb83390190560060806040526003805460a860020a60ff02191690557fc0829421c1d260bd3cb3e0f06cfe2d52db2ce3150000000000000000000000006008553480156200004557600080fd5b5060405160608062004b2883398101604090815281516020830151919092015160008054600160a060020a031916331790558282828282828180620000938164010000000062000140810204565b5060028054600160a060020a03909216600160a060020a031992831681179091556003805490921617905582620000d38164010000000062000140810204565b81620000e881640100000000620001bb810204565b505060048054600160a060020a03909416600160a060020a031990941693909317909255506008805463ffffffff9092166401000000000267ffffffff00000000199092169190911790555062000234945050505050565b600160a060020a0381161515620001b857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4552525f494e56414c49445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b50565b620f424063ffffffff82161115620001b857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4552525f494e56414c49445f434f4e56455253494f4e5f464545000000000000604482015290519081900360640190fd5b6148e480620002446000396000f3006080604052600436106102585763ffffffff60e060020a600035041663024c7ec781146102e45780630c7d5cd8146102fe5780630e53aae91461032c57806312c2aca41461038157806319b64015146103aa5780631cfab290146103de5780631e1401f8146103ff57806321e6b53d1461044257806322f3e2d4146104635780632fe8a6ad1461047857806338a5e0161461048d578063395900d4146104a25780633e8ff43f146104cc578063415f1240146104f857806348dc399b1461051057806349d10b641461053a5780634af80f0e1461054f57806354fd4d5014610570578063579cd3ca146105855780635e35359e1461059a57806361cd756e146105c457806367b6d57c146105d9578063690d8320146105fa5780636a49d2c41461061b5780636aa5332c1461064557806371f52bf31461066f57806379ba5097146106845780637b103999146106995780637d8916bd146106ae5780638da5cb5b1461073157806394c275ad146107465780639b99a8e21461075b578063a60e772414610770578063b127c0a5146107c5578063b4a176d314610858578063bbb7e5d81461086d578063bf75455814610888578063c45d3d921461089d578063ca1d209d146108b2578063cdc91c69146108bd578063d031370b146108d2578063d260529c146108ea578063d3fb73b4146108ff578063d4ee1d9014610914578063d55ec69714610929578063d66bd5241461093e578063d89595121461095f578063dc8de37914610980578063e8dc12ff146109a1578063ecbca55d146109cb578063f2fde38b146109e9578063fc0c546a14610a0a575b60008051602061483983398151915260005260076020527fb2084a3e4595ccf007fb44245853374aaf0de960074375e8e0fb334712e94d0f546601000000000000900460ff1615156102e2576040805160e560020a62461bcd02815260206004820152601360248201526000805160206147f9833981519152604482015290519081900360640190fd5b005b3480156102f057600080fd5b506102e26004351515610a1f565b34801561030a57600080fd5b50610313610a67565b6040805163ffffffff9092168252519081900360200190f35b34801561033857600080fd5b5061034d600160a060020a0360043516610a73565b6040805195865263ffffffff9094166020860152911515848401521515606084015215156080830152519081900360a00190f35b34801561038d57600080fd5b50610396610b0e565b604080519115158252519081900360200190f35b3480156103b657600080fd5b506103c2600435610b57565b60408051600160a060020a039092168252519081900360200190f35b3480156103ea57600080fd5b50610313600160a060020a0360043516610b83565b34801561040b57600080fd5b50610429600160a060020a0360043581169060243516604435610bb5565b6040805192835260208301919091528051918290030190f35b34801561044e57600080fd5b506102e2600160a060020a0360043516610bcf565b34801561046f57600080fd5b50610396610be3565b34801561048457600080fd5b50610396610c7c565b34801561049957600080fd5b506102e2610c9d565b3480156104ae57600080fd5b506102e2600160a060020a0360043581169060243516604435610d0a565b3480156104d857600080fd5b506104e1610da9565b6040805161ffff9092168252519081900360200190f35b34801561050457600080fd5b506102e2600435610dae565b34801561051c57600080fd5b50610429600160a060020a0360043581169060243516604435611002565b34801561054657600080fd5b506102e26111a7565b34801561055b57600080fd5b506102e2600160a060020a0360043516611414565b34801561057c57600080fd5b506104e1611456565b34801561059157600080fd5b5061031361145b565b3480156105a657600080fd5b506102e2600160a060020a0360043581169060243516604435611473565b3480156105d057600080fd5b506103c261158d565b3480156105e557600080fd5b506102e2600160a060020a036004351661159c565b34801561060657600080fd5b506102e2600160a060020a0360043516611643565b34801561062757600080fd5b506102e2600160a060020a036004351663ffffffff60243516611764565b34801561065157600080fd5b5061065d6004356119a3565b60408051918252519081900360200190f35b34801561067b57600080fd5b506104e16119c8565b34801561069057600080fd5b506102e26119d7565b3480156106a557600080fd5b506103c2611a98565b604080516020600480358082013583810280860185019096528085526102e295369593946024949385019291829185019084908082843750506040805187358901803560208181028481018201909552818452989b9a9989019892975090820195509350839250850190849080828437509497505093359450611aa79350505050565b34801561073d57600080fd5b506103c2611db7565b34801561075257600080fd5b50610313611dc6565b34801561076757600080fd5b506104e1611dda565b34801561077c57600080fd5b506040805160206004803580820135838102808601850190965280855261065d95369593946024949385019291829185019084908082843750949750611de09650505050505050565b3480156107d157600080fd5b506040805160206004602480358281013584810280870186019097528086526102e296843596369660449591949091019291829185019084908082843750506040805187358901803560208181028481018201909552818452989b9a998901989297509082019550935083925085019084908082843750949750611e369650505050505050565b34801561086457600080fd5b506102e2611f6f565b34801561087957600080fd5b5061065d600435602435611fa8565b34801561089457600080fd5b50610396611fc2565b3480156108a957600080fd5b506103c2611fc7565b6102e2600435611fd6565b3480156108c957600080fd5b506102e26124ec565b3480156108de57600080fd5b506103c2600435612545565b3480156108f657600080fd5b50610396610da9565b34801561090b57600080fd5b506103c261256d565b34801561092057600080fd5b506103c261257c565b34801561093557600080fd5b506102e261258b565b34801561094a57600080fd5b5061034d600160a060020a0360043516612638565b34801561096b57600080fd5b5061065d600160a060020a036004351661267e565b34801561098c57600080fd5b5061065d600160a060020a036004351661268f565b61065d600160a060020a0360043581169060243581169060443590606435811690608435166126b8565b3480156109d757600080fd5b506102e263ffffffff60043516612927565b3480156109f557600080fd5b506102e2600160a060020a0360043516612a1c565b348015610a1657600080fd5b506103c2612ab9565b610a27612ac8565b60038054911515740100000000000000000000000000000000000000000274ff000000000000000000000000000000000000000019909216919091179055565b60085463ffffffff1681565b6000806000806000610a836147ab565b50505050600160a060020a03929092166000908152600760209081526040808320815160a081018352815480825260019092015463ffffffff811694820185905260ff64010000000082048116151594830194909452650100000000008104841615156060830152660100000000000090049092161515608090920182905295919450919250829190565b60008051602061483983398151915260005260076020527fb2084a3e4595ccf007fb44245853374aaf0de960074375e8e0fb334712e94d0f546601000000000000900460ff1690565b6000600682815481101515610b6857fe5b600091825260209091200154600160a060020a031692915050565b600081610b8f81612b18565b5050600160a060020a031660009081526007602052604090206001015463ffffffff1690565b600080610bc3858585611002565b91509150935093915050565b610bd7612ac8565b610be08161159c565b50565b60048054604080517f8da5cb5b00000000000000000000000000000000000000000000000000000000815290516000933093600160a060020a031692638da5cb5b928183019260209282900301818887803b158015610c4157600080fd5b505af1158015610c55573d6000803e3d6000fd5b505050506040513d6020811015610c6b57600080fd5b5051600160a060020a031614905090565b60035474010000000000000000000000000000000000000000900460ff1681565b6001610ca7611dda565b61ffff1611610d00576040805160e560020a62461bcd02815260206004820152601960248201527f4552525f494e56414c49445f524553455256455f434f554e5400000000000000604482015290519081900360640190fd5b610d08612b85565b565b610d12612ac8565b60048054604080517f5e35359e000000000000000000000000000000000000000000000000000000008152600160a060020a038781169482019490945285841660248201526044810185905290519290911691635e35359e9160648082019260009290919082900301818387803b158015610d8c57600080fd5b505af1158015610da0573d6000803e3d6000fd5b50505050505050565b600190565b600060606000610dbc612b95565b6003805460a860020a60ff02191660a860020a17905560008411610e2a576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f5a45524f5f414d4f554e540000000000000000000000000000000000604482015290519081900360640190fd5b600480546040805160e060020a6318160ddd0281529051600160a060020a03909216926318160ddd9282820192602092908290030181600087803b158015610e7157600080fd5b505af1158015610e85573d6000803e3d6000fd5b505050506040513d6020811015610e9b57600080fd5b505160048054604080517fa24835d100000000000000000000000000000000000000000000000000000000815233938101939093526024830188905251929550600160a060020a03169163a24835d19160448082019260009290919082900301818387803b158015610f0c57600080fd5b505af1158015610f20573d6000803e3d6000fd5b50505050600680549050604051908082528060200260200182016040528015610f53578160200160208202803883390190505b509150600090505b8151811015610f865760018282815181101515610f7457fe5b60209081029091010152600101610f5b565b610fec6006805480602002602001604051908101604052809291908181526020018280548015610fdf57602002820191906000526020600020905b8154600160a060020a03168152600190910190602001808311610fc1575b5050505050838587612bf7565b50506003805460a860020a60ff02191690555050565b600080600080611010612ebe565b8661101a81612b18565b8661102481612b18565b600160a060020a038981169089161415611088576040805160e560020a62461bcd02815260206004820152601660248201527f4552525f53414d455f534f555243455f54415247455400000000000000000000604482015290519081900360640190fd5b61109f600080516020614819833981519152612f1c565b600160a060020a0316639d1141086110b68b61268f565b600160a060020a038c1660009081526007602052604090206001015463ffffffff166110e18c61268f565b600160a060020a038d16600090815260076020908152604080832060010154815163ffffffff89811660e060020a028252600482019890985295871660248701526044860194909452949092166064840152608483018d9052925160a48084019492939192918390030190829087803b15801561115d57600080fd5b505af1158015611171573d6000803e3d6000fd5b505050506040513d602081101561118757600080fd5b5051935061119484612fb4565b9384900399939850929650505050505050565b60008054600160a060020a03163314806111dc575060035474010000000000000000000000000000000000000000900460ff16155b1515611220576040805160e560020a62461bcd0281526020600482015260116024820152600080516020614879833981519152604482015290519081900360640190fd5b6112497f436f6e7472616374526567697374727900000000000000000000000000000000612f1c565b600254909150600160a060020a038083169116148015906112725750600160a060020a03811615155b15156112c8576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e56414c49445f5245474953545259000000000000000000000000604482015290519081900360640190fd5b604080517fbb34534c0000000000000000000000000000000000000000000000000000000081527f436f6e747261637452656769737472790000000000000000000000000000000060048201529051600091600160a060020a0384169163bb34534c9160248082019260209290919082900301818787803b15801561134c57600080fd5b505af1158015611360573d6000803e3d6000fd5b505050506040513d602081101561137657600080fd5b5051600160a060020a031614156113d7576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e56414c49445f5245474953545259000000000000000000000000604482015290519081900360640190fd5b6002805460038054600160a060020a0380841673ffffffffffffffffffffffffffffffffffffffff19928316179092559091169216919091179055565b61141c612ac8565b8061142681612ff0565b506005805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b601d81565b60085468010000000000000000900463ffffffff1681565b600061147d612b95565b6003805460a860020a60ff02191660a860020a17905561149b612ac8565b6114b2600080516020614859833981519152612f1c565b600160a060020a0385166000908152600760205260409020600101549091506601000000000000900460ff1615806114ef57506114ed610be3565b155b806115075750600054600160a060020a038281169116145b151561154b576040805160e560020a62461bcd0281526020600482015260116024820152600080516020614879833981519152604482015290519081900360640190fd5b611556848484613051565b600160a060020a0384166000908152600760205260409020600101546601000000000000900460ff1615610fec57610fec84613082565b600354600160a060020a031681565b6115a4612ac8565b6000805160206148598339815191526115bc81613177565b60048054604080517ff2fde38b000000000000000000000000000000000000000000000000000000008152600160a060020a03868116948201949094529051929091169163f2fde38b9160248082019260009290919082900301818387803b15801561162757600080fd5b505af115801561163b573d6000803e3d6000fd5b505050505050565b600061164d612b95565b6003805460a860020a60ff02191660a860020a17905561166b612ac8565b60008051602061483983398151915261168381612b18565b61169a600080516020614859833981519152612f1c565b91506116a4610be3565b15806116bd5750600054600160a060020a038381169116145b1515611701576040805160e560020a62461bcd0281526020600482015260116024820152600080516020614879833981519152604482015290519081900360640190fd5b604051600160a060020a03841690303180156108fc02916000818181858888f19350505050158015611737573d6000803e3d6000fd5b5061174f600080516020614839833981519152613082565b50506003805460a860020a60ff021916905550565b600061176e612ac8565b6117766131cd565b826117808161322a565b8361178a81612ff0565b836117948161328a565b600454600160a060020a038781169116148015906117d85750600160a060020a0386166000908152600760205260409020600101546601000000000000900460ff16155b151561181c576040805160e560020a62461bcd02815260206004820152601360248201526000805160206147f9833981519152604482015290519081900360640190fd5b60085463ffffffff908116620f42400381169086161115611887576040805160e560020a62461bcd02815260206004820152601a60248201527f4552525f494e56414c49445f524553455256455f574549474854000000000000604482015290519081900360640190fd5b61ffff611892611dda565b61ffff16106118eb576040805160e560020a62461bcd02815260206004820152601960248201527f4552525f494e56414c49445f524553455256455f434f554e5400000000000000604482015290519081900360640190fd5b505050600160a060020a0390921660008181526007602052604081208181556001908101805466ff0000000000001963ffffffff80881663ffffffff1993841617919091166601000000000000179092556006805493840181559093527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f909101805473ffffffffffffffffffffffffffffffffffffffff191690931790925560088054808416909401909216921691909117905550565b600080825b60008111156119c15760019190910190600a90046119a8565b5092915050565b60006119d2611dda565b905090565b600154600160a060020a03163314611a27576040805160e560020a62461bcd0281526020600482015260116024820152600080516020614879833981519152604482015290519081900360640190fd5b60015460008054604051600160a060020a0393841693909116917f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a91a3600180546000805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a03841617909155169055565b600254600160a060020a031681565b6000806000611ab4612b95565b6003805460a860020a60ff02191660a860020a179055611ad2612ebe565b611add8686866132ff565b600092505b8551831015611b9b57855160008051602061483983398151915290879085908110611b0957fe5b90602001906020020151600160a060020a03161415611b9057348584815181101515611b3157fe5b6020908102909101015114611b90576040805160e560020a62461bcd02815260206004820152601760248201527f4552525f4554485f414d4f554e545f4d49534d41544348000000000000000000604482015290519081900360640190fd5b600190920191611ae2565b6000341115611c405760008051602061483983398151915260005260076020527fb2084a3e4595ccf007fb44245853374aaf0de960074375e8e0fb334712e94d0f546601000000000000900460ff161515611c40576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f4e4f5f4554485f524553455256450000000000000000000000000000604482015290519081900360640190fd5b600480546040805160e060020a6318160ddd0281529051600160a060020a03909216926318160ddd9282820192602092908290030181600087803b158015611c8757600080fd5b505af1158015611c9b573d6000803e3d6000fd5b505050506040513d6020811015611cb157600080fd5b50519150611cc08686846135bb565b905083811015611d1a576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f52455455524e5f544f4f5f4c4f570000000000000000000000000000604482015290519081900360640190fd5b60048054604080517f867904b400000000000000000000000000000000000000000000000000000000815233938101939093526024830184905251600160a060020a039091169163867904b491604480830192600092919082900301818387803b158015611d8757600080fd5b505af1158015611d9b573d6000803e3d6000fd5b50506003805460a860020a60ff02191690555050505050505050565b600054600160a060020a031681565b600854640100000000900463ffffffff1681565b60065490565b80516000908190815b81811015611e1d57611e118582815181101515611e0257fe5b906020019060200201516119a3565b90920191600101611de9565b6001611e298484611fa8565b03600a0a95945050505050565b6000611e40612b95565b6003805460a860020a60ff02191660a860020a179055611e5e612ebe565b611e698383866132ff565b600480546040805160e060020a6318160ddd0281529051600160a060020a03909216926318160ddd9282820192602092908290030181600087803b158015611eb057600080fd5b505af1158015611ec4573d6000803e3d6000fd5b505050506040513d6020811015611eda57600080fd5b505160048054604080517fa24835d100000000000000000000000000000000000000000000000000000000815233938101939093526024830188905251929350600160a060020a03169163a24835d19160448082019260009290919082900301818387803b158015611f4b57600080fd5b505af1158015611f5f573d6000803e3d6000fd5b50505050610fec83838387612bf7565b611f77612ac8565b6003546002805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03909216919091179055565b600081600281048401811515611fba57fe5b049392505050565b600181565b600554600160a060020a031681565b600080600080600080600080600080611fed612b95565b6003805460a860020a60ff02191660a860020a17905561200b6135ea565b600080516020614839833981519152600052600760205260008051602061489983398151915254612042903463ffffffff61362c16565b60008051602061483983398151915260009081526007602090815260008051602061489983398151915292909255600480546040805160e060020a6318160ddd0281529051600160a060020a03909216946318160ddd948285019491939283900390910190829087803b1580156120b857600080fd5b505af11580156120cc573d6000803e3d6000fd5b505050506040513d60208110156120e257600080fd5b505199506120fd600080516020614819833981519152612f1c565b6006549099509750600096505b8787101561244a57600680548890811061212057fe5b9060005260206000200160009054906101000a9004600160a060020a031695506007600087600160a060020a0316600160a060020a0316815260200190815260200160002060000154945088600160a060020a031663ebbb21588b87600860009054906101000a900463ffffffff168f6040518563ffffffff1660e060020a028152600401808581526020018481526020018363ffffffff1663ffffffff168152602001828152602001945050505050602060405180830381600087803b1580156121ea57600080fd5b505af11580156121fe573d6000803e3d6000fd5b505050506040513d602081101561221457600080fd5b50519350600160a060020a038616600080516020614839833981519152141561237657833411156122745760405133903486900380156108fc02916000818181858888f1935050505015801561226e573d6000803e3d6000fd5b50612371565b833410156123715734156122d2576040805160e560020a62461bcd02815260206004820152601560248201527f4552525f494e56414c49445f4554485f56414c55450000000000000000000000604482015290519081900360640190fd5b6008546122fa906c010000000000000000000000009004600160a060020a031633308761368c565b6008600c9054906101000a9004600160a060020a0316600160a060020a0316632e1a7d4d856040518263ffffffff1660e060020a02815260040180828152602001915050600060405180830381600087803b15801561235857600080fd5b505af115801561236c573d6000803e3d6000fd5b505050505b612382565b6123828633308761368c565b612392858563ffffffff61377416565b600160a060020a038716600090815260076020526040902081905592506123bf8a8c63ffffffff61377416565b60408051868152602081018690528082018390529051919350600160a060020a0388169133917f4a1a2a6176e9646d9e3157f7c2ab3c499f18337c0b0828cfb28e0a61de4a11f7919081900360600190a350600160a060020a03851660009081526007602052604090206001015463ffffffff1661243f828785846137d1565b60019096019561210a565b60048054604080517f867904b40000000000000000000000000000000000000000000000000000000081523393810193909352602483018e905251600160a060020a039091169163867904b491604480830192600092919082900301818387803b1580156124b757600080fd5b505af11580156124cb573d6000803e3d6000fd5b50506003805460a860020a60ff021916905550505050505050505050505050565b6124f4612ac8565b6124fc613840565b60045460408051600160a060020a0390921682526001602083015280517fa170412ae067fdeca19fd2204ce7eb66f723d827f4af15433b6f33f7fdc642bb9281900390910190a1565b600680548290811061255357fe5b600091825260209091200154600160a060020a0316905081565b600454600160a060020a031681565b600154600160a060020a031681565b6000612595612ac8565b6125ac600080516020614859833981519152612f1c565b90506125b781612a1c565b604080517f90f58c96000000000000000000000000000000000000000000000000000000008152601d60048201529051600160a060020a038316916390f58c9691602480830192600092919082900301818387803b15801561261857600080fd5b505af115801561262c573d6000803e3d6000fd5b50505050610be06119d7565b6007602052600090815260409020805460019091015463ffffffff81169060ff640100000000820481169165010000000000810482169166010000000000009091041685565b60006126898261268f565b92915050565b60008161269b81612b18565b5050600160a060020a031660009081526007602052604090205490565b60006126c2612b95565b6003805460a860020a60ff02191660a860020a1790557f42616e636f724e6574776f726b0000000000000000000000000000000000000061270281613177565b600160a060020a038781169087161415612766576040805160e560020a62461bcd02815260206004820152601660248201527f4552525f53414d455f534f555243455f54415247455400000000000000000000604482015290519081900360640190fd5b600554600160a060020a031615806128a95750600554604080517f3af32abf000000000000000000000000000000000000000000000000000000008152600160a060020a03878116600483015291519190921691633af32abf9160248083019260209291908290030181600087803b1580156127e157600080fd5b505af11580156127f5573d6000803e3d6000fd5b505050506040513d602081101561280b57600080fd5b505180156128a95750600554604080517f3af32abf000000000000000000000000000000000000000000000000000000008152600160a060020a03868116600483015291519190921691633af32abf9160248083019260209291908290030181600087803b15801561287c57600080fd5b505af1158015612890573d6000803e3d6000fd5b505050506040513d60208110156128a657600080fd5b50515b15156128ff576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f4e4f545f57484954454c495354454400000000000000000000000000604482015290519081900360640190fd5b61290c8787878787613927565b6003805460a860020a60ff0219169055979650505050505050565b61292f612ac8565b60085463ffffffff6401000000009091048116908216111561299b576040805160e560020a62461bcd02815260206004820152601a60248201527f4552525f494e56414c49445f434f4e56455253494f4e5f464545000000000000604482015290519081900360640190fd5b6008546040805163ffffffff6801000000000000000090930483168152918316602083015280517f81cd2ffb37dd237c0e4e2a3de5265fcf9deb43d3e7801e80db9f1ccfba7ee6009281900390910190a16008805463ffffffff90921668010000000000000000026bffffffff000000000000000019909216919091179055565b612a24612ac8565b600054600160a060020a0382811691161415612a8a576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f53414d455f4f574e4552000000000000000000000000000000000000604482015290519081900360640190fd5b6001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600454600160a060020a031690565b600054600160a060020a03163314610d08576040805160e560020a62461bcd0281526020600482015260116024820152600080516020614879833981519152604482015290519081900360640190fd5b600160a060020a0381166000908152600760205260409020600101546601000000000000900460ff161515610be0576040805160e560020a62461bcd02815260206004820152601360248201526000805160206147f9833981519152604482015290519081900360640190fd5b612b8d612ac8565b610d086124ec565b60035460a860020a900460ff1615610d08576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f5245454e5452414e4359000000000000000000000000000000000000604482015290519081900360640190fd5b600080600080600080600080612c0b6135ea565b612c22600080516020614819833981519152612f1c565b9750600096505b8b51871015612eb0578b87815181101515612c4057fe5b9060200190602002015195506007600087600160a060020a0316600160a060020a0316815260200190815260200160002060000154945087600160a060020a03166335b49af48b87600860009054906101000a900463ffffffff168d6040518563ffffffff1660e060020a028152600401808581526020018481526020018363ffffffff1663ffffffff168152602001828152602001945050505050602060405180830381600087803b158015612cf657600080fd5b505af1158015612d0a573d6000803e3d6000fd5b505050506040513d6020811015612d2057600080fd5b50518b519094508b9088908110612d3357fe5b60209081029091010151841015612d94576040805160e560020a62461bcd02815260206004820152600d60248201527f4552525f5a45524f5f5241544500000000000000000000000000000000000000604482015290519081900360640190fd5b612da4858563ffffffff61362c16565b600160a060020a03871660008181526007602052604090208290559093506000805160206148398339815191521415612e0a57604051339085156108fc029086906000818181858888f19350505050158015612e04573d6000803e3d6000fd5b50612e15565b612e15863386613bfa565b612e258a8a63ffffffff61362c16565b60408051868152602081018690528082018390529051919350600160a060020a0388169133917fbc7d19d505c7ec4db83f3b51f19fb98c4c8a99922e7839d1ee608dfbee29501b919081900360600190a350600160a060020a03851660009081526007602052604090206001015463ffffffff16612ea5828785846137d1565b600190960195612c29565b505050505050505050505050565b612ec6610be3565b1515610d08576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f494e4143544956450000000000000000000000000000000000000000604482015290519081900360640190fd5b600254604080517fbb34534c000000000000000000000000000000000000000000000000000000008152600481018490529051600092600160a060020a03169163bb34534c91602480830192602092919082900301818787803b158015612f8257600080fd5b505af1158015612f96573d6000803e3d6000fd5b505050506040513d6020811015612fac57600080fd5b505192915050565b60085460009061268990620f424090612fe490859063ffffffff68010000000000000000909104811690613cb116565b9063ffffffff613d2a16565b600160a060020a038116301415610be0576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f414444524553535f49535f53454c4600000000000000000000000000604482015290519081900360640190fd5b613059612ac8565b826130638161322a565b8261306d8161322a565b8361307781612ff0565b61163b868686613bfa565b8061308c81612b18565b600160a060020a03821660008051602061483983398151915214156130cc57600160a060020a038216600090815260076020526040902030319055613173565b604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051600160a060020a038416916370a082319160248083019260209291908290030181600087803b15801561312d57600080fd5b505af1158015613141573d6000803e3d6000fd5b505050506040513d602081101561315757600080fd5b5051600160a060020a0383166000908152600760205260409020555b5050565b61318081612f1c565b600160a060020a03163314610be0576040805160e560020a62461bcd0281526020600482015260116024820152600080516020614879833981519152604482015290519081900360640190fd5b6131d5610be3565b15610d08576040805160e560020a62461bcd02815260206004820152600a60248201527f4552525f41435449564500000000000000000000000000000000000000000000604482015290519081900360640190fd5b600160a060020a0381161515610be0576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f494e56414c49445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b60008163ffffffff161180156132a95750620f424063ffffffff821611155b1515610be0576040805160e560020a62461bcd02815260206004820152601a60248201527f4552525f494e56414c49445f524553455256455f574549474854000000000000604482015290519081900360640190fd5b60065483516000918291811461334d576040805160e560020a62461bcd02815260206004820152601360248201526000805160206147f9833981519152604482015290519081900360640190fd5b845181146133a5576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f494e56414c49445f414d4f554e540000000000000000000000000000604482015290519081900360640190fd5b600092505b80831015613563576007600087858151811015156133c457fe5b6020908102909101810151600160a060020a031682528101919091526040016000206001015460ff660100000000000090910416151561343c576040805160e560020a62461bcd02815260206004820152601360248201526000805160206147f9833981519152604482015290519081900360640190fd5b600091505b808210156134a457858281518110151561345757fe5b90602001906020020151600160a060020a031660068481548110151561347957fe5b600091825260209091200154600160a060020a03161415613499576134a4565b600190910190613441565b8082106134e9576040805160e560020a62461bcd02815260206004820152601360248201526000805160206147f9833981519152604482015290519081900360640190fd5b600085848151811015156134f957fe5b6020908102909101015111613558576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f494e56414c49445f414d4f554e540000000000000000000000000000604482015290519081900360640190fd5b6001909201916133aa565b6000841161163b576040805160e560020a62461bcd02815260206004820152600f60248201527f4552525f5a45524f5f414d4f554e540000000000000000000000000000000000604482015290519081900360640190fd5b60008115156135d5576135ce8484613d98565b90506135e3565b6135e0848484613f9f565b90505b9392505050565b60065460005b818110156131735761362460068281548110151561360a57fe5b600091825260209091200154600160a060020a0316613082565b6001016135f0565b600081831015613686576040805160e560020a62461bcd02815260206004820152600d60248201527f4552525f554e444552464c4f5700000000000000000000000000000000000000604482015290519081900360640190fd5b50900390565b604080517f7472616e7366657246726f6d28616464726573732c616464726573732c75696e81527f74323536290000000000000000000000000000000000000000000000000000006020808301919091528251918290036025018220600160a060020a038088166024850152861660448401526064808401869052845180850390910181526084909301909352810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff199093169290921790915261376e908590614366565b50505050565b6000828201838110156135e3576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b600454600160a060020a0380851691167f77f29993cf2c084e726f7e802da0719d6a0ade3e204badc7a3ffd57ecb768c2461380f85620f4240613cb1565b6138228863ffffffff80881690613cb116565b6040805192835260208301919091528051918290030190a350505050565b613848612ac8565b6000613852611dda565b61ffff16116138ab576040805160e560020a62461bcd02815260206004820152601960248201527f4552525f494e56414c49445f524553455256455f434f554e5400000000000000604482015290519081900360640190fd5b60048054604080517f79ba50970000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216926379ba509792828201926000929082900301818387803b15801561390757600080fd5b505af115801561391b573d6000803e3d6000fd5b50505050610d086135ea565b600080600080613938898989611002565b9093509150821515613994576040805160e560020a62461bcd02815260206004820152600d60248201527f4552525f5a45524f5f5241544500000000000000000000000000000000000000604482015290519081900360640190fd5b61399d8861268f565b90508083106139a857fe5b600160a060020a0389166000805160206148398339815191521415613a2357348714613a1e576040805160e560020a62461bcd02815260206004820152601760248201527f4552525f4554485f414d4f554e545f4d49534d41544348000000000000000000604482015290519081900360640190fd5b613b2b565b34158015613ad5575086613ad2613a398b61268f565b604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051600160a060020a038e16916370a082319160248083019260209291908290030181600087803b158015613a9a57600080fd5b505af1158015613aae573d6000803e3d6000fd5b505050506040513d6020811015613ac457600080fd5b50519063ffffffff61362c16565b10155b1515613b2b576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f494e56414c49445f414d4f554e540000000000000000000000000000604482015290519081900360640190fd5b613b3489613082565b600160a060020a038816600090815260076020526040902054613b5d908463ffffffff61362c16565b600160a060020a0389166000818152600760205260409020919091556000805160206148398339815191521415613bca57604051600160a060020a0386169084156108fc029085906000818181858888f19350505050158015613bc4573d6000803e3d6000fd5b50613bd5565b613bd5888685613bfa565b613be38989888a87876143f4565b613bed8989614479565b5090979650505050505050565b604080517f7472616e7366657228616464726573732c75696e74323536290000000000000081528151908190036019018120600160a060020a038516602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1990931692909217909152613cac908490614366565b505050565b600080831515613cc457600091506119c1565b50828202828482811515613cd457fe5b04146135e3576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b600080808311613d84576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f4449564944455f42595f5a45524f0000000000000000000000000000604482015290519081900360640190fd5b8284811515613d8f57fe5b04949350505050565b600080600080613da785611de0565b9250600091505b8551821015613f9557855160008051602061483983398151915290879084908110613dd557fe5b60209081029091010151600160a060020a031614613e2757613e278683815181101515613dfe57fe5b9060200190602002015133308886815181101515613e1857fe5b9060200190602002015161368c565b8482815181101515613e3557fe5b90602001906020020151600760008885815181101515613e5157fe5b6020908102909101810151600160a060020a03168252810191909152604001600020558551869083908110613e8257fe5b90602001906020020151600160a060020a031633600160a060020a03167f4a1a2a6176e9646d9e3157f7c2ab3c499f18337c0b0828cfb28e0a61de4a11f78785815181101515613ece57fe5b906020019060200201518886815181101515613ee657fe5b60209081029091018101516040805193845291830152818101889052519081900360600190a3600760008784815181101515613f1e57fe5b6020908102909101810151600160a060020a0316825281019190915260400160002060010154865163ffffffff9091169150613f8a908490889085908110613f6257fe5b906020019060200201518785815181101515613f7a57fe5b90602001906020020151846137d1565b600190910190613dae565b5090949350505050565b600080600080600080600080600080613fb66135ea565b600080516020614839833981519152600052600760205260008051602061489983398151915254613fed903463ffffffff61362c16565b60008051602061483983398151915260005260076020526000805160206148998339815191525561402b600080516020614819833981519152612f1c565b98506140388b8e8e614687565b9750600096505b8c51871015614355578c8781518110151561405657fe5b9060200190602002015195506007600087600160a060020a0316600160a060020a0316815260200190815260200160002060000154945088600160a060020a031663ebbb21588c87600860009054906101000a900463ffffffff168c6040518563ffffffff1660e060020a028152600401808581526020018481526020018363ffffffff1663ffffffff168152602001828152602001945050505050602060405180830381600087803b15801561410c57600080fd5b505af1158015614120573d6000803e3d6000fd5b505050506040513d602081101561413657600080fd5b5051935060008411614192576040805160e560020a62461bcd02815260206004820152600d60248201527f4552525f5a45524f5f5241544500000000000000000000000000000000000000604482015290519081900360640190fd5b8b878151811015156141a057fe5b602090810290910101518411156141b357fe5b600160a060020a038616600080516020614839833981519152146141e2576141dd8633308761368c565b614255565b838c888151811015156141f157fe5b9060200190602002015111156142555733600160a060020a03166108fc858e8a81518110151561421d57fe5b90602001906020020151039081150290604051600060405180830381858888f19350505050158015614253573d6000803e3d6000fd5b505b614265858563ffffffff61377416565b600160a060020a038716600090815260076020526040902081905592506142928b8963ffffffff61377416565b60408051868152602081018690528082018390529051919350600160a060020a0388169133917f4a1a2a6176e9646d9e3157f7c2ab3c499f18337c0b0828cfb28e0a61de4a11f7919081900360600190a3600760008e898151811015156142f557fe5b6020908102909101810151600160a060020a03168252810191909152604001600020600101548d5163ffffffff909116915061434a9083908f908a90811061433957fe5b9060200190602002015185846137d1565b60019096019561403f565b50959b9a5050505050505050505050565b61436e6147d9565b602060405190810160405280600181525090506020818351602085016000875af180151561439b57600080fd5b5080511515613cac576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f5452414e534645525f4641494c454400000000000000000000000000604482015290519081900360640190fd5b7f8000000000000000000000000000000000000000000000000000000000000000811061441d57fe5b60408051848152602081018490528082018390529051600160a060020a038087169288821692918a16917f276856b36cbc45526a0ba64f44611557a2a8b68662c5388e9fe6d72e86e1c8cb9181900360600190a4505050505050565b6000806000806000806000600460009054906101000a9004600160a060020a0316600160a060020a03166318160ddd6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156144d757600080fd5b505af11580156144eb573d6000803e3d6000fd5b505050506040513d602081101561450157600080fd5b5051965061450e8961268f565b95506145198861268f565b600160a060020a03808b16600090815260076020526040808220600190810154938d1683529120015491965063ffffffff908116955090811693506145629086908690613cb116565b91506145778663ffffffff80861690613cb116565b60408051848152602081018390528151929350600160a060020a03808c1693908d16927f77f29993cf2c084e726f7e802da0719d6a0ade3e204badc7a3ffd57ecb768c24928290030190a36145ce878a88876137d1565b6145da878987866137d1565b604080518881526020810188905263ffffffff8616818301529051600160a060020a038b16917f8a6a7f53b3c8fa1dc4b83e3f1be668c1b251ff8d44cdcb83eb3acec3fec6a788919081900360600190a2604080518881526020810187905263ffffffff8516818301529051600160a060020a038a16917f8a6a7f53b3c8fa1dc4b83e3f1be668c1b251ff8d44cdcb83eb3acec3fec6a788919081900360600190a2505050505050505050565b6000806000806146f087600760008960008151811015156146a457fe5b90602001906020020151600160a060020a0316600160a060020a03168152602001908152602001600020600001548760008151811015156146e157fe5b9060200190602002015161476b565b9250600191505b8551821015614760576147478760076000898681518110151561471657fe5b6020908102909101810151600160a060020a031682528101919091526040016000205487518890869081106146e157fe5b905080831115614755578092505b6001909101906146f7565b509095945050505050565b60006135e061478d620f42406147818686613774565b9063ffffffff613cb116565b600854612fe49063ffffffff908116906147819089908890613cb116565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b602060405190810160405280600190602082028038833950919291505056004552525f494e56414c49445f524553455256450000000000000000000000000042616e636f72466f726d756c6100000000000000000000000000000000000000000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee42616e636f72436f6e76657274657255706772616465720000000000000000004552525f4143434553535f44454e494544000000000000000000000000000000b2084a3e4595ccf007fb44245853374aaf0de960074375e8e0fb334712e94d0ea165627a7a7230582059c0b8af441dae51deb14e69367acf01fff003f2840aadf572e285e1d480403a0029a165627a7a7230582014b18720e70deb2ab87954abe96c4a85ea61b0d8f9d1dd08be84a10fa8952cb10029
Deployed Bytecode Sourcemap
48544:1035:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;49240:336;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;49240:336:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48748:81;;8:9:-1;5:2;;;30:1;27;20:12;5:2;48748:81:0;;;;;;;;;;;;;;;;;;;;;;;49240:336;49362:10;49385:23;49452:7;49462:9;49473:17;49411:80;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;49411:80:0;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;49502:39:0;;;;;;49530:10;49502:39;;;;;;49385:106;;-1:-1:-1;49502:27:0;;;;;;:39;;;;;-1:-1:-1;;49502:39:0;;;;;;;;-1:-1:-1;49502:27:0;:39;;;5:2:-1;;;;30:1;27;20:12;5:2;49502:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;49559:9:0;;49240:336;-1:-1:-1;;;;;;;49240:336:0:o;48748:81::-;48820:1;48748:81;:::o;48544:1035::-;;;;;;;;;;:::o
Swarm Source
bzzr://14b18720e70deb2ab87954abe96c4a85ea61b0d8f9d1dd08be84a10fa8952cb1
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.