Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 603 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Trade | 15834279 | 570 days ago | IN | 0 ETH | 0.00068467 | ||||
Trade | 15834266 | 570 days ago | IN | 0 ETH | 0.00068248 | ||||
Trade | 10163917 | 1450 days ago | IN | 0 ETH | 0.00204183 | ||||
Trade | 10149982 | 1452 days ago | IN | 0 ETH | 0.00515483 | ||||
Trade | 10120959 | 1457 days ago | IN | 0 ETH | 0.00256568 | ||||
Remove Liquidity | 10117065 | 1457 days ago | IN | 0 ETH | 0.00380171 | ||||
Trade | 10103267 | 1459 days ago | IN | 0 ETH | 0.00643913 | ||||
Trade | 10062032 | 1466 days ago | IN | 0 ETH | 0.00283061 | ||||
Trade | 10051985 | 1467 days ago | IN | 0 ETH | 0.00439831 | ||||
Remove Liquidity | 10042587 | 1469 days ago | IN | 0 ETH | 0.00175214 | ||||
Remove Liquidity | 10036040 | 1470 days ago | IN | 0 ETH | 0.00573933 | ||||
Remove Liquidity | 10035413 | 1470 days ago | IN | 0 ETH | 0.0075152 | ||||
Trade | 10023463 | 1472 days ago | IN | 0 ETH | 0.00190149 | ||||
Trade | 9982054 | 1478 days ago | IN | 0 ETH | 0.00062816 | ||||
Trade | 9943253 | 1484 days ago | IN | 0 ETH | 0.00031421 | ||||
Trade | 9941184 | 1484 days ago | IN | 0 ETH | 0.00036839 | ||||
Trade | 9936947 | 1485 days ago | IN | 0 ETH | 0.00046878 | ||||
Trade | 9928701 | 1486 days ago | IN | 0 ETH | 0.00158616 | ||||
Trade | 9924139 | 1487 days ago | IN | 0 ETH | 0.00078574 | ||||
Trade | 9921384 | 1488 days ago | IN | 0 ETH | 0.00109928 | ||||
Trade | 9917576 | 1488 days ago | IN | 0 ETH | 0.00031565 | ||||
Trade | 9917562 | 1488 days ago | IN | 0 ETH | 0.00043619 | ||||
Trade | 9916814 | 1488 days ago | IN | 0 ETH | 0.00122339 | ||||
Trade | 9916778 | 1488 days ago | IN | 0 ETH | 0.00152924 | ||||
Trade | 9916715 | 1488 days ago | IN | 0 ETH | 0.00109358 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
DEXAdapter
Compiler Version
v0.5.12+commit.7709ece9
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2019-10-31 */ /** Deployed by Ren Project, https://renproject.io Commit hash: 272d917 Repository: https://github.com/renproject/darknode-sol Issues: https://github.com/renproject/darknode-sol/issues Licenses openzeppelin-solidity: (MIT) https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/LICENSE darknode-sol: (GNU GPL V3) https://github.com/renproject/darknode-sol/blob/master/LICENSE */ pragma solidity ^0.5.12; /** * @title Claimable * @dev Extension for the Ownable contract, where the ownership needs to be claimed. * This allows the new owner to accept the transfer. */ contract Claimable { address private _pendingOwner; address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor () internal { _owner = msg.sender; emit OwnershipTransferred(address(0), _owner); } /** * @return the address of the owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Claimable: caller is not the owner"); _; } /** * @dev Modifier throws if called by any account other than the pendingOwner. */ modifier onlyPendingOwner() { require(msg.sender == _pendingOwner, "Claimable: caller is not the pending owner"); _; } /** * @return true if `msg.sender` is the owner of the contract. */ function isOwner() public view returns (bool) { return msg.sender == _owner; } /** * @dev Allows the current owner to relinquish control of the contract. * It will not be possible to call the functions with the `onlyOwner` * modifier anymore. * @notice Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Allows the current owner to set the pendingOwner address. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { _pendingOwner = newOwner; } /** * @dev Allows the pendingOwner address to finalize the transfer. */ function claimOwnership() public onlyPendingOwner { emit OwnershipTransferred(_owner, _pendingOwner); _owner = _pendingOwner; _pendingOwner = address(0); } } /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { _owner = _msgSender(); emit OwnershipTransferred(address(0), _owner); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _owner; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * NOTE: This call _does not revert_ if the signature is invalid, or * if the signer is otherwise unable to be retrieved. In those scenarios, * the zero address is returned. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { revert("signature's length is invalid"); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { revert("signature's s is in the wrong range"); } if (v != 27 && v != 28) { revert("signature's v is in the wrong range"); } // If the signature is valid (and not malleable), return the signer address return ecrecover(hash, v, r, s); } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } } library String { /// @notice Convert a uint value to its decimal string representation // solium-disable-next-line security/no-assign-params function fromUint(uint _i) internal pure returns (string memory) { if (_i == 0) { return "0"; } uint j = _i; uint len; while (j != 0) { len++; j /= 10; } bytes memory bstr = new bytes(len); uint k = len - 1; while (_i != 0) { bstr[k--] = byte(uint8(48 + _i % 10)); _i /= 10; } return string(bstr); } /// @notice Convert a bytes32 value to its hex string representation function fromBytes32(bytes32 _value) internal pure returns(string memory) { bytes32 value = bytes32(uint256(_value)); bytes memory alphabet = "0123456789abcdef"; bytes memory str = new bytes(32 * 2 + 2); str[0] = '0'; str[1] = 'x'; for (uint i = 0; i < 32; i++) { str[2+i*2] = alphabet[uint(uint8(value[i] >> 4))]; str[3+i*2] = alphabet[uint(uint8(value[i] & 0x0f))]; } return string(str); } /// @notice Convert an address to its hex string representation function fromAddress(address _addr) internal pure returns(string memory) { bytes32 value = bytes32(uint256(_addr)); bytes memory alphabet = "0123456789abcdef"; bytes memory str = new bytes(20 * 2 + 2); str[0] = '0'; str[1] = 'x'; for (uint i = 0; i < 20; i++) { str[2+i*2] = alphabet[uint(uint8(value[i + 12] >> 4))]; str[3+i*2] = alphabet[uint(uint8(value[i + 12] & 0x0f))]; } return string(str); } /// @notice Append four strings function add4(string memory a, string memory b, string memory c, string memory d) internal pure returns (string memory) { return string(abi.encodePacked(a, b, c, d)); } } /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20Mintable}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal { require(account != address(0), "ERC20: burn from the zero address"); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Destroys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See {_burn} and {_approve}. */ function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } } /** * @dev Optional functions from the ERC20 standard. */ contract ERC20Detailed is IERC20 { string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of * these values are immutable: they can only be set once during * construction. */ constructor (string memory name, string memory symbol, uint8 decimals) public { _name = name; _symbol = symbol; _decimals = decimals; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } } /// @notice ERC20Shifted represents a digital asset that has been bridged on to /// the Ethereum ledger. It exposes mint and burn functions that can only be /// called by it's associated Shifter. contract ERC20Shifted is ERC20, ERC20Detailed, Claimable { /* solium-disable-next-line no-empty-blocks */ constructor(string memory _name, string memory _symbol, uint8 _decimals) public ERC20Detailed(_name, _symbol, _decimals) {} /// @notice Allow the owner of the contract to recover funds accidentally /// sent to the contract. To withdraw ETH, the token should be set to `0x0`. function recoverTokens(address _token) external onlyOwner { if (_token == address(0x0)) { msg.sender.transfer(address(this).balance); } else { ERC20(_token).transfer(msg.sender, ERC20(_token).balanceOf(address(this))); } } function burn(address _from, uint256 _amount) public onlyOwner { _burn(_from, _amount); } function mint(address _to, uint256 _amount) public onlyOwner { _mint(_to, _amount); } } /// @dev The following are not necessary for deploying zBTC or zZEC contracts, /// but are used to track deployments. /* solium-disable-next-line no-empty-blocks */ contract zBTC is ERC20Shifted("Shifted BTC", "zBTC", 8) {} /* solium-disable-next-line no-empty-blocks */ contract zZEC is ERC20Shifted("Shifted ZEC", "zZEC", 8) {} /* solium-disable-next-line no-empty-blocks */ contract zBCH is ERC20Shifted("Shifted BCH", "zBCH", 8) {} /// @notice Shifter handles verifying mint and burn requests. A mintAuthority /// approves new assets to be minted by providing a digital signature. An owner /// of an asset can request for it to be burnt. contract Shifter is Claimable { using SafeMath for uint256; uint8 public version = 2; uint256 constant BIPS_DENOMINATOR = 10000; uint256 public minShiftAmount; /// @notice Each Shifter token is tied to a specific shifted token. ERC20Shifted public token; /// @notice The mintAuthority is an address that can sign mint requests. address public mintAuthority; /// @dev feeRecipient is assumed to be an address (or a contract) that can /// accept erc20 payments it cannot be 0x0. /// @notice When tokens are mint or burnt, a portion of the tokens are /// forwarded to a fee recipient. address public feeRecipient; /// @notice The shiftIn fee in bips. uint16 public shiftInFee; /// @notice The shiftOut fee in bips. uint16 public shiftOutFee; /// @notice Each nHash can only be seen once. mapping (bytes32=>bool) public status; // LogShiftIn and LogShiftOut contain a unique `shiftID` that identifies // the mint or burn event. uint256 public nextShiftID = 0; event LogShiftIn( address indexed _to, uint256 _amount, uint256 indexed _shiftID, bytes32 indexed _signedMessageHash ); event LogShiftOut( bytes _to, uint256 _amount, uint256 indexed _shiftID, bytes indexed _indexedTo ); /// @param _token The ERC20Shifted this Shifter is responsible for. /// @param _feeRecipient The recipient of burning and minting fees. /// @param _mintAuthority The address of the key that can sign mint /// requests. /// @param _shiftInFee The amount subtracted each shiftIn request and /// forwarded to the feeRecipient. In BIPS. /// @param _shiftOutFee The amount subtracted each shiftOut request and /// forwarded to the feeRecipient. In BIPS. constructor(ERC20Shifted _token, address _feeRecipient, address _mintAuthority, uint16 _shiftInFee, uint16 _shiftOutFee, uint256 _minShiftOutAmount) public { minShiftAmount = _minShiftOutAmount; token = _token; mintAuthority = _mintAuthority; shiftInFee = _shiftInFee; shiftOutFee = _shiftOutFee; updateFeeRecipient(_feeRecipient); } /// @notice Allow the owner of the contract to recover funds accidentally /// sent to the contract. To withdraw ETH, the token should be set to `0x0`. function recoverTokens(address _token) external onlyOwner { if (_token == address(0x0)) { msg.sender.transfer(address(this).balance); } else { ERC20(_token).transfer(msg.sender, ERC20(_token).balanceOf(address(this))); } } // Public functions //////////////////////////////////////////////////////// /// @notice Claims ownership of the token passed in to the constructor. /// `transferStoreOwnership` must have previously been called. /// Anyone can call this function. function claimTokenOwnership() public { token.claimOwnership(); } /// @notice Allow the owner to update the owner of the ERC20Shifted token. function transferTokenOwnership(Shifter _nextTokenOwner) public onlyOwner { token.transferOwnership(address(_nextTokenOwner)); _nextTokenOwner.claimTokenOwnership(); } /// @notice Allow the owner to update the fee recipient. /// /// @param _nextMintAuthority The address to start paying fees to. function updateMintAuthority(address _nextMintAuthority) public onlyOwner { mintAuthority = _nextMintAuthority; } /// @notice Allow the owner to update the minimum shiftOut amount. /// /// @param _minShiftOutAmount The new min shiftOut amount. function updateMinimumShiftOutAmount(uint256 _minShiftOutAmount) public onlyOwner { minShiftAmount = _minShiftOutAmount; } /// @notice Allow the owner to update the fee recipient. /// /// @param _nextFeeRecipient The address to start paying fees to. function updateFeeRecipient(address _nextFeeRecipient) public onlyOwner { // ShiftIn and ShiftOut will fail if the feeRecipient is 0x0 require(_nextFeeRecipient != address(0x0), "Shifter: fee recipient cannot be 0x0"); feeRecipient = _nextFeeRecipient; } /// @notice Allow the owner to update the shiftIn fee. /// /// @param _nextFee The new fee for minting and burning. function updateShiftInFee(uint16 _nextFee) public onlyOwner { shiftInFee = _nextFee; } /// @notice Allow the owner to update the shiftOut fee. /// /// @param _nextFee The new fee for minting and burning. function updateShiftOutFee(uint16 _nextFee) public onlyOwner { shiftOutFee = _nextFee; } /// @notice shiftIn mints tokens after taking a fee for the `_feeRecipient`. /// /// @param _pHash (payload hash) The hash of the payload associated with the /// shift. /// @param _amount The amount of the token being shifted int, in its /// smallest value. (e.g. satoshis for BTC) /// @param _nHash (nonce hash) The hash of the nonce, amount and pHash. /// @param _sig The signature of the hash of the following values: /// (pHash, amount, msg.sender, nHash), signed by the mintAuthority. function shiftIn(bytes32 _pHash, uint256 _amount, bytes32 _nHash, bytes memory _sig) public returns (uint256) { // Verify signature bytes32 signedMessageHash = hashForSignature(_pHash, _amount, msg.sender, _nHash); require(status[signedMessageHash] == false, "Shifter: nonce hash already spent"); if (!verifySignature(signedMessageHash, _sig)) { // Return a detailed string containing the hash and recovered // signer. This is a costly operation but is only run in the revert // branch. revert( String.add4( "Shifter: invalid signature - hash: ", String.fromBytes32(signedMessageHash), ", signer: ", String.fromAddress(ECDSA.recover(signedMessageHash, _sig)) ) ); } status[signedMessageHash] = true; // Mint `amount - fee` for the recipient and mint `fee` for the minter uint256 absoluteFee = (_amount.mul(shiftInFee)).div(BIPS_DENOMINATOR); uint256 receivedAmount = _amount.sub(absoluteFee); token.mint(msg.sender, receivedAmount); token.mint(feeRecipient, absoluteFee); // Emit a log with a unique shift ID emit LogShiftIn(msg.sender, receivedAmount, nextShiftID, signedMessageHash); nextShiftID += 1; return receivedAmount; } /// @notice shiftOut burns tokens after taking a fee for the `_feeRecipient`. /// /// @param _to The address to receive the unshifted digital asset. The /// format of this address should be of the destination chain. /// For example, when shifting out to Bitcoin, _to should be a /// Bitcoin address. /// @param _amount The amount of the token being shifted out, in its /// smallest value. (e.g. satoshis for BTC) function shiftOut(bytes memory _to, uint256 _amount) public returns (uint256) { // The recipient must not be empty. Better validation is possible, // but would need to be customized for each destination ledger. require(_to.length != 0, "Shifter: to address is empty"); require(_amount >= minShiftAmount, "Shifter: amount is less than the minimum shiftOut amount"); // Burn full amount and mint fee uint256 absoluteFee = (_amount.mul(shiftOutFee)).div(BIPS_DENOMINATOR); token.burn(msg.sender, _amount); token.mint(feeRecipient, absoluteFee); // Emit a log with a unique shift ID uint256 receivedValue = _amount.sub(absoluteFee); emit LogShiftOut(_to, receivedValue, nextShiftID, _to); nextShiftID += 1; return receivedValue; } /// @notice verifySignature checks the the provided signature matches the provided /// parameters. function verifySignature(bytes32 _signedMessageHash, bytes memory _sig) public view returns (bool) { return mintAuthority == ECDSA.recover(_signedMessageHash, _sig); } /// @notice hashForSignature hashes the parameters so that they can be signed. function hashForSignature(bytes32 _pHash, uint256 _amount, address _to, bytes32 _nHash) public view returns (bytes32) { return keccak256(abi.encode(_pHash, _amount, address(token), _to, _nHash)); } } /// @dev The following are not necessary for deploying BTCShifter or ZECShifter /// contracts, but are used to track deployments. contract BTCShifter is Shifter { constructor(ERC20Shifted _token, address _feeRecipient, address _mintAuthority, uint16 _shiftInFee, uint16 _shiftOutFee, uint256 _minShiftOutAmount) Shifter(_token, _feeRecipient, _mintAuthority, _shiftInFee, _shiftOutFee, _minShiftOutAmount) public { } } contract ZECShifter is Shifter { constructor(ERC20Shifted _token, address _feeRecipient, address _mintAuthority, uint16 _shiftInFee, uint16 _shiftOutFee, uint256 _minShiftOutAmount) Shifter(_token, _feeRecipient, _mintAuthority, _shiftInFee, _shiftOutFee, _minShiftOutAmount) public { } } contract BCHShifter is Shifter { constructor(ERC20Shifted _token, address _feeRecipient, address _mintAuthority, uint16 _shiftInFee, uint16 _shiftOutFee, uint256 _minShiftOutAmount) Shifter(_token, _feeRecipient, _mintAuthority, _shiftInFee, _shiftOutFee, _minShiftOutAmount) public { } } /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * This test is non-exhaustive, and there may be false-negatives: during the * execution of a contract's constructor, its address will be reported as * not containing a contract. * * IMPORTANT: It is unsafe to assume that an address for which this * function returns false is an externally-owned account (EOA) and not a * contract. */ function isContract(address account) internal view returns (bool) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != 0x0 && codehash != accountHash); } /** * @dev Converts an `address` into `address payable`. Note that this is * simply a type cast: the actual underlying value is not changed. * * _Available since v2.4.0._ */ function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. * * _Available since v2.4.0._ */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-call-value (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } } /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } /// @title DEXReserve /// @notice The DEX Reserve holds the liquidity for a single token pair for the /// DEX. Anyone can add liquidity, receiving in return a token representing /// a share in the funds held by the reserve. contract DEXReserve is ERC20, ERC20Detailed, Ownable { using SafeMath for uint256; using SafeERC20 for ERC20; uint256 public feeInBIPS; uint256 public pendingFeeInBIPS; uint256 public feeChangeBlock; ERC20 public baseToken; ERC20 public token; event LogAddLiquidity(address _liquidityProvider, uint256 _tokenAmount, uint256 _baseTokenAmount); event LogDebug(uint256 _rcvAmount); event LogFeesChanged(uint256 _previousFeeInBIPS, uint256 _newFeeInBIPS); constructor (string memory _name, string memory _symbol, uint8 _decimals, ERC20 _baseToken, ERC20 _token, uint256 _feeInBIPS) public ERC20Detailed(_name, _symbol, _decimals) { baseToken = _baseToken; token = _token; feeInBIPS = _feeInBIPS; pendingFeeInBIPS = _feeInBIPS; } /// @notice Allow anyone to recover funds accidentally sent to the contract. function recoverTokens(address _token) external onlyOwner { require(ERC20(_token) != baseToken && ERC20(_token) != token, "not allowed to recover reserve tokens"); ERC20(_token).transfer(msg.sender, ERC20(_token).balanceOf(address(this))); } /// @notice Allow the reserve manager too update the contract fees. /// There is a 10 block delay to reduce the chance of front-running trades. function updateFee(uint256 _pendingFeeInBIPS) external onlyOwner { if (_pendingFeeInBIPS == pendingFeeInBIPS) { require(block.number >= feeChangeBlock, "must wait 100 blocks before updating the fee"); emit LogFeesChanged(feeInBIPS, pendingFeeInBIPS); feeInBIPS = pendingFeeInBIPS; } else { // @dev 500 was chosen as an arbitrary limit - the fee should be // well below that. require(_pendingFeeInBIPS < 500, "fee must not exceed hard-coded limit"); feeChangeBlock = block.number + 100; pendingFeeInBIPS = _pendingFeeInBIPS; } } function buy(address _to, address _from, uint256 _baseTokenAmount) external returns (uint256) { require(totalSupply() != 0, "reserve has no funds"); uint256 rcvAmount = calculateBuyRcvAmt(_baseTokenAmount); baseToken.safeTransferFrom(_from, address(this), _baseTokenAmount); token.safeTransfer(_to, rcvAmount); return rcvAmount; } function sell(address _to, address _from, uint256 _tokenAmount) external returns (uint256) { require(totalSupply() != 0, "reserve has no funds"); uint256 rcvAmount = calculateSellRcvAmt(_tokenAmount); token.safeTransferFrom(_from, address(this), _tokenAmount); baseToken.safeTransfer(_to, rcvAmount); return rcvAmount; } function calculateBuyRcvAmt(uint256 _sendAmt) public view returns (uint256) { uint256 baseReserve = baseToken.balanceOf(address(this)); uint256 tokenReserve = token.balanceOf(address(this)); uint256 finalQuoteTokenAmount = (baseReserve.mul(tokenReserve)).div(baseReserve.add(_sendAmt)); uint256 rcvAmt = tokenReserve.sub(finalQuoteTokenAmount); return _removeFees(rcvAmt); } function calculateSellRcvAmt(uint256 _sendAmt) public view returns (uint256) { uint256 baseReserve = baseToken.balanceOf(address(this)); uint256 tokenReserve = token.balanceOf(address(this)); uint256 finalBaseTokenAmount = (baseReserve.mul(tokenReserve)).div(tokenReserve.add(_sendAmt)); uint256 rcvAmt = baseReserve.sub(finalBaseTokenAmount); return _removeFees(rcvAmt); } function removeLiquidity(uint256 _liquidity) external returns (uint256, uint256) { require(balanceOf(msg.sender) >= _liquidity, "insufficient balance"); uint256 baseTokenAmount = calculateBaseTokenValue(_liquidity); uint256 quoteTokenAmount = calculateQuoteTokenValue(_liquidity); _burn(msg.sender, _liquidity); baseToken.safeTransfer(msg.sender, baseTokenAmount); token.safeTransfer(msg.sender, quoteTokenAmount); return (baseTokenAmount, quoteTokenAmount); } function addLiquidity( address _liquidityProvider, uint256 _maxBaseToken, uint256 _tokenAmount, uint256 _deadline ) external returns (uint256) { require(block.number <= _deadline, "addLiquidity request expired"); uint256 liquidity = calculateExpectedLiquidity(_tokenAmount); if (totalSupply() > 0) { require(_tokenAmount > 0, "token amount is less than allowed min amount"); uint256 baseAmount = expectedBaseTokenAmount(_tokenAmount); require(baseAmount <= _maxBaseToken, "calculated base amount exceeds the maximum amount set"); baseToken.safeTransferFrom(_liquidityProvider, address(this), baseAmount); emit LogAddLiquidity(_liquidityProvider, _tokenAmount, baseAmount); } else { baseToken.safeTransferFrom(_liquidityProvider, address(this), _maxBaseToken); emit LogAddLiquidity(_liquidityProvider, _tokenAmount, _maxBaseToken); } token.safeTransferFrom(msg.sender, address(this), _tokenAmount); _mint(_liquidityProvider, liquidity); return liquidity; } function calculateBaseTokenValue(uint256 _liquidity) public view returns (uint256) { require(totalSupply() != 0, "division by zero"); uint256 baseReserve = baseToken.balanceOf(address(this)); return (_liquidity * baseReserve)/totalSupply(); } function calculateQuoteTokenValue(uint256 _liquidity) public view returns (uint256) { require(totalSupply() != 0, "division by zero"); uint256 tokenReserve = token.balanceOf(address(this)); return (_liquidity * tokenReserve)/totalSupply(); } function expectedBaseTokenAmount(uint256 _quoteTokenAmount) public view returns (uint256) { uint256 baseReserve = baseToken.balanceOf(address(this)); uint256 tokenReserve = token.balanceOf(address(this)); return (_quoteTokenAmount * baseReserve)/tokenReserve; } function calculateExpectedLiquidity(uint256 _tokenAmount) public view returns (uint256) { if (totalSupply() == 0) { return _tokenAmount*2; } return ((totalSupply()*_tokenAmount)/token.balanceOf(address(this))); } function _removeFees(uint256 _amount) internal view returns (uint256) { return (_amount * (10000 - feeInBIPS))/10000; } } /* solhint-disable-next-line */ /* solium-disable-next-line */ contract BTC_DAI_Reserve is DEXReserve { constructor (ERC20 _baseToken, ERC20 _token, uint256 _feeInBIPS) public DEXReserve("Bitcoin Liquidity Token", "BTCLT", 8, _baseToken, _token, _feeInBIPS) { } } /* solhint-disable-next-line */ /* solium-disable-next-line */ contract ZEC_DAI_Reserve is DEXReserve { constructor (ERC20 _baseToken, ERC20 _token, uint256 _feeInBIPS) public DEXReserve("ZCash Liquidity Token", "ZECLT", 8, _baseToken, _token, _feeInBIPS) { } } /* solhint-disable-next-line */ /* solium-disable-next-line */ contract BCH_DAI_Reserve is DEXReserve { constructor (ERC20 _baseToken, ERC20 _token, uint256 _feeInBIPS) public DEXReserve("BitcoinCash Liquidity Token", "BCHLT", 8, _baseToken, _token, _feeInBIPS) { } } /// @title DEX /// @notice The DEX contract stores the reserves for each token pair and /// provides functions for interacting with them: /// 1) the view-function `calculateReceiveAmount` for calculating how much /// the user will receive in exchange for their tokens /// 2) the function `trade` for executing a swap. If one of the tokens is the /// base token, this will only talk to one reserve. If neither of the /// tokens are, then the trade will settle across two reserves. /// /// The DEX is ownable, allowing a DEX operator to register new reserves. /// Once a reserve has been registered, it can't be updated. contract DEX is Claimable { mapping (address=>DEXReserve) public reserves; address public baseToken; event LogTrade(address _src, address _dst, uint256 _sendAmount, uint256 _recvAmount); /// @param _baseToken The reserves must all have a common base token. constructor(address _baseToken) public { baseToken = _baseToken; } /// @notice Allow the owner to recover funds accidentally sent to the /// contract. To withdraw ETH, the token should be set to `0x0`. function recoverTokens(address _token) external onlyOwner { if (_token == address(0x0)) { msg.sender.transfer(address(this).balance); } else { ERC20(_token).transfer(msg.sender, ERC20(_token).balanceOf(address(this))); } } /// @notice The DEX operator is able to register new reserves. /// @param _erc20 The token that can be traded against the base token. /// @param _reserve The address of the reserve contract. It must follow the /// DEXReserve interface. function registerReserve(address _erc20, DEXReserve _reserve) external onlyOwner { require(reserves[_erc20] == DEXReserve(0x0), "token reserve already registered"); reserves[_erc20] = _reserve; } /// @notice The main trade function to execute swaps. /// @param _to The address at which the DST tokens should be sent to. /// @param _src The address of the token being spent. /// @param _dst The address of the token being received. /// @param _sendAmount The amount of the source token being traded. function trade(address _to, address _src, address _dst, uint256 _sendAmount) public returns (uint256) { uint256 recvAmount; if (_src == baseToken) { require(reserves[_dst] != DEXReserve(0x0), "unsupported token"); recvAmount = reserves[_dst].buy(_to, msg.sender, _sendAmount); } else if (_dst == baseToken) { require(reserves[_src] != DEXReserve(0x0), "unsupported token"); recvAmount = reserves[_src].sell(_to, msg.sender, _sendAmount); } else { require(reserves[_src] != DEXReserve(0x0) && reserves[_dst] != DEXReserve(0x0), "unsupported token"); uint256 intermediteAmount = reserves[_src].sell(address(this), msg.sender, _sendAmount); ERC20(baseToken).approve(address(reserves[_dst]), intermediteAmount); recvAmount = reserves[_dst].buy(_to, address(this), intermediteAmount); } emit LogTrade(_src, _dst, _sendAmount, recvAmount); return recvAmount; } /// @notice A read-only function to estimate the amount of DST tokens the /// trader would receive for the send amount. /// @param _src The address of the token being spent. /// @param _dst The address of the token being received. /// @param _sendAmount The amount of the source token being traded. function calculateReceiveAmount(address _src, address _dst, uint256 _sendAmount) public view returns (uint256) { if (_src == baseToken) { return reserves[_dst].calculateBuyRcvAmt(_sendAmount); } if (_dst == baseToken) { return reserves[_src].calculateSellRcvAmt(_sendAmount); } return reserves[_dst].calculateBuyRcvAmt(reserves[_src].calculateSellRcvAmt(_sendAmount)); } } /** * @notice LinkedList is a library for a circular double linked list. */ library LinkedList { /* * @notice A permanent NULL node (0x0) in the circular double linked list. * NULL.next is the head, and NULL.previous is the tail. */ address public constant NULL = address(0); /** * @notice A node points to the node before it, and the node after it. If * node.previous = NULL, then the node is the head of the list. If * node.next = NULL, then the node is the tail of the list. */ struct Node { bool inList; address previous; address next; } /** * @notice LinkedList uses a mapping from address to nodes. Each address * uniquely identifies a node, and in this way they are used like pointers. */ struct List { mapping (address => Node) list; } /** * @notice Insert a new node before an existing node. * * @param self The list being used. * @param target The existing node in the list. * @param newNode The next node to insert before the target. */ function insertBefore(List storage self, address target, address newNode) internal { require(!isInList(self, newNode), "LinkedList: already in list"); require(isInList(self, target) || target == NULL, "LinkedList: not in list"); // It is expected that this value is sometimes NULL. address prev = self.list[target].previous; self.list[newNode].next = target; self.list[newNode].previous = prev; self.list[target].previous = newNode; self.list[prev].next = newNode; self.list[newNode].inList = true; } /** * @notice Insert a new node after an existing node. * * @param self The list being used. * @param target The existing node in the list. * @param newNode The next node to insert after the target. */ function insertAfter(List storage self, address target, address newNode) internal { require(!isInList(self, newNode), "LinkedList: already in list"); require(isInList(self, target) || target == NULL, "LinkedList: not in list"); // It is expected that this value is sometimes NULL. address n = self.list[target].next; self.list[newNode].previous = target; self.list[newNode].next = n; self.list[target].next = newNode; self.list[n].previous = newNode; self.list[newNode].inList = true; } /** * @notice Remove a node from the list, and fix the previous and next * pointers that are pointing to the removed node. Removing anode that is not * in the list will do nothing. * * @param self The list being using. * @param node The node in the list to be removed. */ function remove(List storage self, address node) internal { require(isInList(self, node), "LinkedList: not in list"); if (node == NULL) { return; } address p = self.list[node].previous; address n = self.list[node].next; self.list[p].next = n; self.list[n].previous = p; // Deleting the node should set this value to false, but we set it here for // explicitness. self.list[node].inList = false; delete self.list[node]; } /** * @notice Insert a node at the beginning of the list. * * @param self The list being used. * @param node The node to insert at the beginning of the list. */ function prepend(List storage self, address node) internal { // isInList(node) is checked in insertBefore insertBefore(self, begin(self), node); } /** * @notice Insert a node at the end of the list. * * @param self The list being used. * @param node The node to insert at the end of the list. */ function append(List storage self, address node) internal { // isInList(node) is checked in insertBefore insertAfter(self, end(self), node); } function swap(List storage self, address left, address right) internal { // isInList(left) and isInList(right) are checked in remove address previousRight = self.list[right].previous; remove(self, right); insertAfter(self, left, right); remove(self, left); insertAfter(self, previousRight, left); } function isInList(List storage self, address node) internal view returns (bool) { return self.list[node].inList; } /** * @notice Get the node at the beginning of a double linked list. * * @param self The list being used. * * @return A address identifying the node at the beginning of the double * linked list. */ function begin(List storage self) internal view returns (address) { return self.list[NULL].next; } /** * @notice Get the node at the end of a double linked list. * * @param self The list being used. * * @return A address identifying the node at the end of the double linked * list. */ function end(List storage self) internal view returns (address) { return self.list[NULL].previous; } function next(List storage self, address node) internal view returns (address) { require(isInList(self, node), "LinkedList: not in list"); return self.list[node].next; } function previous(List storage self, address node) internal view returns (address) { require(isInList(self, node), "LinkedList: not in list"); return self.list[node].previous; } } interface IShifter { function shiftIn(bytes32 _pHash, uint256 _amount, bytes32 _nHash, bytes calldata _sig) external returns (uint256); function shiftOut(bytes calldata _to, uint256 _amount) external returns (uint256); function shiftInFee() external view returns (uint256); function shiftOutFee() external view returns (uint256); } /// @notice ShifterRegistry is a mapping from assets to their associated /// ERC20Shifted and Shifter contracts. contract ShifterRegistry is Claimable { /// @dev The symbol is included twice because strings have to be hashed /// first in order to be used as a log index/topic. event LogShifterRegistered(string _symbol, string indexed _indexedSymbol, address indexed _tokenAddress, address indexed _shifterAddress); event LogShifterDeregistered(string _symbol, string indexed _indexedSymbol, address indexed _tokenAddress, address indexed _shifterAddress); event LogShifterUpdated(address indexed _tokenAddress, address indexed _currentShifterAddress, address indexed _newShifterAddress); /// @notice The number of shifters registered uint256 numShifters = 0; /// @notice A list of shifter contracts LinkedList.List private shifterList; /// @notice A list of shifted token contracts LinkedList.List private shiftedTokenList; /// @notice A map of token addresses to canonical shifter addresses mapping (address=>address) private shifterByToken; /// @notice A map of token symbols to canonical shifter addresses mapping (string=>address) private tokenBySymbol; /// @notice Allow the owner of the contract to recover funds accidentally /// sent to the contract. To withdraw ETH, the token should be set to `0x0`. function recoverTokens(address _token) external onlyOwner { if (_token == address(0x0)) { msg.sender.transfer(address(this).balance); } else { ERC20(_token).transfer(msg.sender, ERC20(_token).balanceOf(address(this))); } } /// @notice Allow the owner to set the shifter address for a given /// ERC20Shifted token contract. /// /// @param _tokenAddress The address of the ERC20Shifted token contract. /// @param _shifterAddress The address of the Shifter contract. function setShifter(address _tokenAddress, address _shifterAddress) external onlyOwner { // Check that token, shifter and symbol haven't already been registered require(!LinkedList.isInList(shifterList, _shifterAddress), "ShifterRegistry: shifter already registered"); require(shifterByToken[_tokenAddress] == address(0x0), "ShifterRegistry: token already registered"); string memory symbol = ERC20Shifted(_tokenAddress).symbol(); require(tokenBySymbol[symbol] == address(0x0), "ShifterRegistry: symbol already registered"); // Add to list of shifters LinkedList.append(shifterList, _shifterAddress); // Add to list of shifted tokens LinkedList.append(shiftedTokenList, _tokenAddress); tokenBySymbol[symbol] = _tokenAddress; shifterByToken[_tokenAddress] = _shifterAddress; numShifters += 1; emit LogShifterRegistered(symbol, symbol, _tokenAddress, _shifterAddress); } /// @notice Allow the owner to update the shifter address for a given /// ERC20Shifted token contract. /// /// @param _tokenAddress The address of the ERC20Shifted token contract. /// @param _newShifterAddress The updated address of the Shifter contract. function updateShifter(address _tokenAddress, address _newShifterAddress) external onlyOwner { // Check that token, shifter are registered address currentShifter = shifterByToken[_tokenAddress]; require(shifterByToken[_tokenAddress] != address(0x0), "ShifterRegistry: token not registered"); // Remove to list of shifters LinkedList.remove(shifterList, currentShifter); // Add to list of shifted tokens LinkedList.append(shifterList, _newShifterAddress); shifterByToken[_tokenAddress] = _newShifterAddress; emit LogShifterUpdated(_tokenAddress, currentShifter, _newShifterAddress); } /// @notice Allows the owner to remove the shifter address for a given /// ERC20shifter token contract. /// /// @param _symbol The symbol of the token to deregister. function removeShifter(string calldata _symbol) external onlyOwner { // Look up token address address tokenAddress = tokenBySymbol[_symbol]; require(tokenAddress != address(0x0), "ShifterRegistry: symbol not registered"); // Look up shifter address address shifterAddress = shifterByToken[tokenAddress]; // Remove token and shifter shifterByToken[tokenAddress] = address(0x0); tokenBySymbol[_symbol] = address(0x0); LinkedList.remove(shifterList, shifterAddress); LinkedList.remove(shiftedTokenList, tokenAddress); numShifters -= 1; emit LogShifterDeregistered(_symbol, _symbol, tokenAddress, shifterAddress); } /// @dev To get all the registered shifters use count = 0. function getShifters(address _start, uint256 _count) external view returns (address[] memory) { uint256 count; if (_count == 0) { count = numShifters; } else { count = _count; } address[] memory shifters = new address[](count); // Begin with the first node in the list uint256 n = 0; address next = _start; if (next == address(0)) { next = LinkedList.begin(shifterList); } while (n < count) { if (next == address(0)) { break; } shifters[n] = next; next = LinkedList.next(shifterList, next); n += 1; } return shifters; } /// @dev To get all the registered shifted tokens use count = 0. function getShiftedTokens(address _start, uint256 _count) external view returns (address[] memory) { uint256 count; if (_count == 0) { count = numShifters; } else { count = _count; } address[] memory shiftedTokens = new address[](count); // Begin with the first node in the list uint256 n = 0; address next = _start; if (next == address(0)) { next = LinkedList.begin(shiftedTokenList); } while (n < count) { if (next == address(0)) { break; } shiftedTokens[n] = next; next = LinkedList.next(shiftedTokenList, next); n += 1; } return shiftedTokens; } /// @notice Returns the Shifter address for the given ERC20Shifted token /// contract address. /// /// @param _tokenAddress The address of the ERC20Shifted token contract. function getShifterByToken(address _tokenAddress) external view returns (IShifter) { return IShifter(shifterByToken[_tokenAddress]); } /// @notice Returns the Shifter address for the given ERC20Shifted token /// symbol. /// /// @param _tokenSymbol The symbol of the ERC20Shifted token contract. function getShifterBySymbol(string calldata _tokenSymbol) external view returns (IShifter) { return IShifter(shifterByToken[tokenBySymbol[_tokenSymbol]]); } /// @notice Returns the ERC20Shifted address for the given token symbol. /// /// @param _tokenSymbol The symbol of the ERC20Shifted token contract to /// lookup. function getTokenBySymbol(string calldata _tokenSymbol) external view returns (address) { return tokenBySymbol[_tokenSymbol]; } } contract DEXAdapter { using SafeERC20 for ERC20; DEX public dex; ShifterRegistry public shifterRegistry; event LogTransferIn(address src, uint256 amount); event LogTransferOut(address dst, uint256 amount); constructor(DEX _dex, ShifterRegistry _shifterRegistry) public { shifterRegistry = _shifterRegistry; dex = _dex; } /// @notice Allow anyone to recover funds accidentally sent to the contract. /// To withdraw ETH, the token should be set to `0x0`. function recoverTokens(address _token) external { if (_token == address(0x0)) { msg.sender.transfer(address(this).balance); } else { ERC20(_token).transfer(msg.sender, ERC20(_token).balanceOf(address(this))); } } // TODO: Fix "Stack too deep" error! uint256 transferredAmt; function trade( // Payload /*uint256 _relayerFee,*/ address _src, address _dst, uint256 _minDstAmt, bytes calldata _to, uint256 _refundBN, bytes calldata _refundAddress, // Required uint256 _amount, bytes32 _nHash, bytes calldata _sig ) external { transferredAmt; bytes32 pHash = hashTradePayload(_src, _dst, _minDstAmt, _to, _refundBN, _refundAddress); // Handle refunds if the refund block number has passed if (block.number >= _refundBN) { IShifter shifter = shifterRegistry.getShifterByToken(address(_src)); if (shifter != IShifter(0x0)) { transferredAmt = shifter.shiftIn(pHash, _amount, _nHash, _sig); shifter.shiftOut(_refundAddress, transferredAmt); } return; } transferredAmt = _transferIn(_src, _amount, _nHash, pHash, _sig); emit LogTransferIn(_src, transferredAmt); _doTrade(_src, _dst, _minDstAmt, _to, transferredAmt); } function hashTradePayload( /*uint256 _relayerFee,*/ address _src, address _dst, uint256 _minDstAmt, bytes memory _to, uint256 _refundBN, bytes memory _refundAddress ) public pure returns (bytes32) { return keccak256(abi.encode(_src, _dst, _minDstAmt, _to, _refundBN, _refundAddress)); } function hashLiquidityPayload( address _liquidityProvider, uint256 _maxBaseToken, address _token, uint256 _refundBN, bytes memory _refundAddress ) public pure returns (bytes32) { return keccak256(abi.encode(_liquidityProvider, _maxBaseToken, _token, _refundBN, _refundAddress)); } function addLiquidity( address _liquidityProvider, uint256 _maxBaseToken, address _token, uint256 _deadline, bytes calldata _refundAddress, uint256 _amount, bytes32 _nHash, bytes calldata _sig ) external returns (uint256) { DEXReserve reserve = dex.reserves(_token); require(reserve != DEXReserve(0x0), "unsupported token"); bytes32 lpHash = hashLiquidityPayload(_liquidityProvider, _maxBaseToken, _token, _deadline, _refundAddress); if (block.number > _deadline) { uint256 shiftedAmount = shifterRegistry.getShifterByToken(_token).shiftIn(lpHash, _amount, _nHash, _sig); shifterRegistry.getShifterByToken(_token).shiftOut(_refundAddress, shiftedAmount); return 0; } require(ERC20(dex.baseToken()).allowance(_liquidityProvider, address(reserve)) >= _maxBaseToken, "insufficient base token allowance"); uint256 transferredAmount = _transferIn(_token, _amount, _nHash, lpHash, _sig); ERC20(_token).approve(address(reserve), transferredAmount); return reserve.addLiquidity(_liquidityProvider, _maxBaseToken, transferredAmount, _deadline); } function removeLiquidity(address _token, uint256 _liquidity, bytes calldata _tokenAddress) external { DEXReserve reserve = dex.reserves(_token); require(reserve != DEXReserve(0x0), "unsupported token"); ERC20(reserve).safeTransferFrom(msg.sender, address(this), _liquidity); (uint256 baseTokenAmount, uint256 quoteTokenAmount) = reserve.removeLiquidity(_liquidity); reserve.baseToken().safeTransfer(msg.sender, baseTokenAmount); shifterRegistry.getShifterByToken(address(reserve.token())).shiftOut(_tokenAddress, quoteTokenAmount); } function _doTrade( address _src, address _dst, uint256 _minDstAmt, bytes memory _to, uint256 _amount ) internal { uint256 recvAmt; address to; IShifter shifter = shifterRegistry.getShifterByToken(address(_dst)); if (shifter != IShifter(0x0)) { to = address(this); } else { to = _bytesToAddress(_to); } if (_src == dex.baseToken()) { ERC20(_src).approve(address(dex.reserves(_dst)), _amount); } else { ERC20(_src).approve(address(dex.reserves(_src)), _amount); } recvAmt = dex.trade(to, _src, _dst, _amount); require(recvAmt > 0 && recvAmt >= _minDstAmt, "invalid receive amount"); if (shifter != IShifter(0x0)) { shifter.shiftOut(_to, recvAmt); } emit LogTransferOut(_dst, recvAmt); } function _transferIn( /*uint256 _relayerFee,*/ address _src, uint256 _amount, bytes32 _nHash, bytes32 _pHash, bytes memory _sig ) internal returns (uint256) { IShifter shifter = shifterRegistry.getShifterByToken(address(_src)); if (shifter != IShifter(0x0)) { return shifter.shiftIn(_pHash, _amount, _nHash, _sig); } else { ERC20(_src).safeTransferFrom(msg.sender, address(this), _amount); return _amount; } } function _bytesToAddress(bytes memory _addr) internal pure returns (address) { address addr; /* solhint-disable-next-line */ /* solium-disable-next-line */ assembly { addr := mload(add(_addr, 20)) } return addr; } function calculateReceiveAmount(address _src, address _dst, uint256 _sendAmount) public view returns (uint256) { uint256 sendAmount = _sendAmount; // Remove shift-in fees IShifter srcShifter = shifterRegistry.getShifterByToken(_dst); if (srcShifter != IShifter(0x0)) { sendAmount = removeFee(_sendAmount, srcShifter.shiftInFee()); } uint256 receiveAmount = dex.calculateReceiveAmount(_src, _dst, sendAmount); // Remove shift-out fees IShifter dstShifter = shifterRegistry.getShifterByToken(_dst); if (dstShifter != IShifter(0x0)) { receiveAmount = removeFee(receiveAmount, dstShifter.shiftOutFee()); } return receiveAmount; } function removeFee(uint256 _amount, uint256 _feeInBips) private view returns (uint256) { return _amount - (_amount * _feeInBips)/10000; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract DEX","name":"_dex","type":"address"},{"internalType":"contract ShifterRegistry","name":"_shifterRegistry","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"src","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LogTransferIn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LogTransferOut","type":"event"},{"constant":false,"inputs":[{"internalType":"address","name":"_liquidityProvider","type":"address"},{"internalType":"uint256","name":"_maxBaseToken","type":"uint256"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_refundAddress","type":"bytes"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32","name":"_nHash","type":"bytes32"},{"internalType":"bytes","name":"_sig","type":"bytes"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_src","type":"address"},{"internalType":"address","name":"_dst","type":"address"},{"internalType":"uint256","name":"_sendAmount","type":"uint256"}],"name":"calculateReceiveAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"dex","outputs":[{"internalType":"contract DEX","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_liquidityProvider","type":"address"},{"internalType":"uint256","name":"_maxBaseToken","type":"uint256"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_refundBN","type":"uint256"},{"internalType":"bytes","name":"_refundAddress","type":"bytes"}],"name":"hashLiquidityPayload","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_src","type":"address"},{"internalType":"address","name":"_dst","type":"address"},{"internalType":"uint256","name":"_minDstAmt","type":"uint256"},{"internalType":"bytes","name":"_to","type":"bytes"},{"internalType":"uint256","name":"_refundBN","type":"uint256"},{"internalType":"bytes","name":"_refundAddress","type":"bytes"}],"name":"hashTradePayload","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"recoverTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_liquidity","type":"uint256"},{"internalType":"bytes","name":"_tokenAddress","type":"bytes"}],"name":"removeLiquidity","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"shifterRegistry","outputs":[{"internalType":"contract ShifterRegistry","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_src","type":"address"},{"internalType":"address","name":"_dst","type":"address"},{"internalType":"uint256","name":"_minDstAmt","type":"uint256"},{"internalType":"bytes","name":"_to","type":"bytes"},{"internalType":"uint256","name":"_refundBN","type":"uint256"},{"internalType":"bytes","name":"_refundAddress","type":"bytes"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32","name":"_nHash","type":"bytes32"},{"internalType":"bytes","name":"_sig","type":"bytes"}],"name":"trade","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5060405161245c38038061245c8339818101604052604081101561003357600080fd5b508051602090910151600180546001600160a01b039283166001600160a01b031991821617909155600080549290931691161790556123e5806100776000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063692058c211610066578063692058c2146103385780637813e50a1461035c578063863cb94e14610426578063a1f419c9146104a9578063e6a12ca9146105fa57610093565b806316114acd1461009857806333da59af146100c0578063590ba492146101c35780635fb31d7714610302575b600080fd5b6100be600480360360208110156100ae57600080fd5b50356001600160a01b0316610602565b005b6101b160048036036101008110156100d757600080fd5b6001600160a01b0382358116926020810135926040820135909216916060820135919081019060a081016080820135600160201b81111561011757600080fd5b82018360208201111561012957600080fd5b803590602001918460018302840111600160201b8311171561014a57600080fd5b919390928235926020810135929190606081019060400135600160201b81111561017357600080fd5b82018360208201111561018557600080fd5b803590602001918460018302840111600160201b831117156101a657600080fd5b50909250905061073f565b60408051918252519081900360200190f35b6100be60048036036101208110156101da57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561021457600080fd5b82018360208201111561022657600080fd5b803590602001918460018302840111600160201b8311171561024757600080fd5b91939092823592604081019060200135600160201b81111561026857600080fd5b82018360208201111561027a57600080fd5b803590602001918460018302840111600160201b8311171561029b57600080fd5b919390928235926020810135929190606081019060400135600160201b8111156102c457600080fd5b8201836020820111156102d657600080fd5b803590602001918460018302840111600160201b831117156102f757600080fd5b509092509050610ddf565b6101b16004803603606081101561031857600080fd5b506001600160a01b03813581169160208101359091169060400135611179565b6103406113de565b604080516001600160a01b039092168252519081900360200190f35b6101b1600480360360a081101561037257600080fd5b6001600160a01b0382358116926020810135926040820135909216916060820135919081019060a081016080820135600160201b8111156103b257600080fd5b8201836020820111156103c457600080fd5b803590602001918460018302840111600160201b831117156103e557600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506113ed945050505050565b6100be6004803603606081101561043c57600080fd5b6001600160a01b0382351691602081013591810190606081016040820135600160201b81111561046b57600080fd5b82018360208201111561047d57600080fd5b803590602001918460018302840111600160201b8311171561049e57600080fd5b5090925090506114c8565b6101b1600480360360c08110156104bf57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b8111156104f957600080fd5b82018360208201111561050b57600080fd5b803590602001918460018302840111600160201b8311171561052c57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092958435959094909350604081019250602001359050600160201b81111561058657600080fd5b82018360208201111561059857600080fd5b803590602001918460018302840111600160201b831117156105b957600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611860945050505050565b6103406119a2565b6001600160a01b038116610643576040513390303180156108fc02916000818181858888f1935050505015801561063d573d6000803e3d6000fd5b5061073c565b604080516370a0823160e01b815230600482015290516001600160a01b0383169163a9059cbb91339184916370a0823191602480820192602092909190829003018186803b15801561069457600080fd5b505afa1580156106a8573d6000803e3d6000fd5b505050506040513d60208110156106be57600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091525160448083019260209291908290030181600087803b15801561070f57600080fd5b505af1158015610723573d6000803e3d6000fd5b505050506040513d602081101561073957600080fd5b50505b50565b600080546040805163359af54960e21b81526001600160a01b038c8116600483015291518493929092169163d66bd52491602480820192602092909190829003018186803b15801561079057600080fd5b505afa1580156107a4573d6000803e3d6000fd5b505050506040513d60208110156107ba57600080fd5b505190506001600160a01b03811661080d576040805162461bcd60e51b81526020600482015260116024820152703ab739bab83837b93a32b2103a37b5b2b760791b604482015290519081900360640190fd5b60006108528d8d8d8d8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113ed92505050565b905089431115610af5576001546040805163028c4f4160e41b81526001600160a01b038e81166004830152915160009392909216916328c4f41091602480820192602092909190829003018186803b1580156108ad57600080fd5b505afa1580156108c1573d6000803e3d6000fd5b505050506040513d60208110156108d757600080fd5b5051604051632ed2876360e21b815260048101848152602482018b9052604482018a9052608060648301908152608483018990526001600160a01b039093169263bb4a1d8c9286928d928d928d928d92909160a401848480828437600081840152601f19601f8201169050808301925050509650505050505050602060405180830381600087803b15801561096b57600080fd5b505af115801561097f573d6000803e3d6000fd5b505050506040513d602081101561099557600080fd5b81019080805190602001909291905050509050600160009054906101000a90046001600160a01b03166001600160a01b03166328c4f4108d6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610a1357600080fd5b505afa158015610a27573d6000803e3d6000fd5b505050506040513d6020811015610a3d57600080fd5b505160408051638723c37760e01b81526024810184905260048101918252604481018c90526001600160a01b0390921691638723c377918d918d9186918190606401858580828437600081840152601f19601f820116905080830192505050945050505050602060405180830381600087803b158015610abc57600080fd5b505af1158015610ad0573d6000803e3d6000fd5b505050506040513d6020811015610ae657600080fd5b5060009450610dd19350505050565b6000546040805163c55dae6360e01b815290518e926001600160a01b03169163c55dae63916004808301926020929190829003018186803b158015610b3957600080fd5b505afa158015610b4d573d6000803e3d6000fd5b505050506040513d6020811015610b6357600080fd5b81019080805190602001909291905050506001600160a01b031663dd62ed3e8f856040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b031681526020019250505060206040518083038186803b158015610be357600080fd5b505afa158015610bf7573d6000803e3d6000fd5b505050506040513d6020811015610c0d57600080fd5b50511015610c4c5760405162461bcd60e51b81526004018080602001828103825260218152602001806123666021913960400191505060405180910390fd5b6000610c918c8989858a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506119b192505050565b90508b6001600160a01b031663095ea7b384836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015610cf357600080fd5b505af1158015610d07573d6000803e3d6000fd5b505050506040513d6020811015610d1d57600080fd5b810190808051906020019092919050505050826001600160a01b0316631ece366a8f8f848f6040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b03168152602001848152602001838152602001828152602001945050505050602060405180830381600087803b158015610d9f57600080fd5b505af1158015610db3573d6000803e3d6000fd5b505050506040513d6020811015610dc957600080fd5b505193505050505b9a9950505050505050505050565b6000610e698d8d8d8d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508c8c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061186092505050565b9050874310611087576000600160009054906101000a90046001600160a01b03166001600160a01b03166328c4f4108f6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610edf57600080fd5b505afa158015610ef3573d6000803e3d6000fd5b505050506040513d6020811015610f0957600080fd5b505190506001600160a01b0381161561108057806001600160a01b031663bb4a1d8c83888888886040518663ffffffff1660e01b815260040180868152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050602060405180830381600087803b158015610fa657600080fd5b505af1158015610fba573d6000803e3d6000fd5b505050506040513d6020811015610fd057600080fd5b5051600281905560408051638723c37760e01b81526024810183905260048101918252604481018a90526001600160a01b03841692638723c377928c928c9291908190606401858580828437600081840152601f19601f820116905080830192505050945050505050602060405180830381600087803b15801561105357600080fd5b505af1158015611067573d6000803e3d6000fd5b505050506040513d602081101561107d57600080fd5b50505b505061116b565b6110ca8d86868487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506119b192505050565b6002819055507ff9a8a6f3535e914cfd5fef422f9f604a324554db59d703e57cf12e77139140e38d60025460405180836001600160a01b03166001600160a01b031681526020018281526020019250505060405180910390a16111698d8d8d8d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506002549150611b569050565b505b505050505050505050505050565b6001546040805163028c4f4160e41b81526001600160a01b0385811660048301529151600093859385939116916328c4f41091602480820192602092909190829003018186803b1580156111cc57600080fd5b505afa1580156111e0573d6000803e3d6000fd5b505050506040513d60208110156111f657600080fd5b505190506001600160a01b0381161561127a5761127784826001600160a01b031663dfe03d326040518163ffffffff1660e01b815260040160206040518083038186803b15801561124657600080fd5b505afa15801561125a573d6000803e3d6000fd5b505050506040513d602081101561127057600080fd5b50516120ac565b91505b6000805460408051635fb31d7760e01b81526001600160a01b038a8116600483015289811660248301526044820187905291519190921691635fb31d77916064808301926020929190829003018186803b1580156112d757600080fd5b505afa1580156112eb573d6000803e3d6000fd5b505050506040513d602081101561130157600080fd5b50516001546040805163028c4f4160e41b81526001600160a01b038a81166004830152915193945060009391909216916328c4f410916024808301926020929190829003018186803b15801561135657600080fd5b505afa15801561136a573d6000803e3d6000fd5b505050506040513d602081101561138057600080fd5b505190506001600160a01b038116156113d3576113d082826001600160a01b0316639d5d4cd86040518163ffffffff1660e01b815260040160206040518083038186803b15801561124657600080fd5b91505b509695505050505050565b6000546001600160a01b031681565b6000858585858560405160200180866001600160a01b03166001600160a01b03168152602001858152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611470578181015183820152602001611458565b50505050905090810190601f16801561149d5780820380516001836020036101000a031916815260200191505b5096505050505050506040516020818303038152906040528051906020012090505b95945050505050565b600080546040805163359af54960e21b81526001600160a01b0388811660048301529151919092169163d66bd524916024808301926020929190829003018186803b15801561151657600080fd5b505afa15801561152a573d6000803e3d6000fd5b505050506040513d602081101561154057600080fd5b505190506001600160a01b038116611593576040805162461bcd60e51b81526020600482015260116024820152703ab739bab83837b93a32b2103a37b5b2b760791b604482015290519081900360640190fd5b6115ae6001600160a01b03821633308763ffffffff6120b816565b600080826001600160a01b0316639c8f9f23876040518263ffffffff1660e01b8152600401808281526020019150506040805180830381600087803b1580156115f657600080fd5b505af115801561160a573d6000803e3d6000fd5b505050506040513d604081101561162057600080fd5b5080516020918201516040805163c55dae6360e01b815290519295509093506116b492339286926001600160a01b0389169263c55dae6392600480840193829003018186803b15801561167257600080fd5b505afa158015611686573d6000803e3d6000fd5b505050506040513d602081101561169c57600080fd5b50516001600160a01b0316919063ffffffff61211816565b600160009054906101000a90046001600160a01b03166001600160a01b03166328c4f410846001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561171157600080fd5b505afa158015611725573d6000803e3d6000fd5b505050506040513d602081101561173b57600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b039092166004830152516024808301926020929190829003018186803b15801561178257600080fd5b505afa158015611796573d6000803e3d6000fd5b505050506040513d60208110156117ac57600080fd5b505160408051638723c37760e01b81526024810184905260048101918252604481018790526001600160a01b0390921691638723c377918891889186918190606401858580828437600081840152601f19601f820116905080830192505050945050505050602060405180830381600087803b15801561182b57600080fd5b505af115801561183f573d6000803e3d6000fd5b505050506040513d602081101561185557600080fd5b505050505050505050565b600086868686868660405160200180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b031681526020018581526020018060200184815260200180602001838103835286818151815260200191508051906020019080838360005b838110156118e85781810151838201526020016118d0565b50505050905090810190601f1680156119155780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b83811015611948578181015183820152602001611930565b50505050905090810190601f1680156119755780820380516001836020036101000a031916815260200191505b50985050505050505050506040516020818303038152906040528051906020012090509695505050505050565b6001546001600160a01b031681565b6001546040805163028c4f4160e41b81526001600160a01b0388811660048301529151600093849316916328c4f410916024808301926020929190829003018186803b158015611a0057600080fd5b505afa158015611a14573d6000803e3d6000fd5b505050506040513d6020811015611a2a57600080fd5b505190506001600160a01b03811615611b3257806001600160a01b031663bb4a1d8c858888876040518563ffffffff1660e01b81526004018085815260200184815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611aae578181015183820152602001611a96565b50505050905090810190601f168015611adb5780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015611afd57600080fd5b505af1158015611b11573d6000803e3d6000fd5b505050506040513d6020811015611b2757600080fd5b505191506114bf9050565b611b4d6001600160a01b03881633308963ffffffff6120b816565b859150506114bf565b6001546040805163028c4f4160e41b81526001600160a01b0387811660048301529151600093849384939116916328c4f41091602480820192602092909190829003018186803b158015611ba957600080fd5b505afa158015611bbd573d6000803e3d6000fd5b505050506040513d6020811015611bd357600080fd5b505190506001600160a01b03811615611bee57309150611bfa565b611bf78561216a565b91505b6000809054906101000a90046001600160a01b03166001600160a01b031663c55dae636040518163ffffffff1660e01b815260040160206040518083038186803b158015611c4757600080fd5b505afa158015611c5b573d6000803e3d6000fd5b505050506040513d6020811015611c7157600080fd5b50516001600160a01b0389811691161415611d86576000546040805163359af54960e21b81526001600160a01b038a811660048301529151828c169363095ea7b393169163d66bd524916024808301926020929190829003018186803b158015611cda57600080fd5b505afa158015611cee573d6000803e3d6000fd5b505050506040513d6020811015611d0457600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482018890525160448083019260209291908290030181600087803b158015611d5457600080fd5b505af1158015611d68573d6000803e3d6000fd5b505050506040513d6020811015611d7e57600080fd5b50611e829050565b6000546040805163359af54960e21b81526001600160a01b03808c16600483018190529251929363095ea7b39391169163d66bd524916024808301926020929190829003018186803b158015611ddb57600080fd5b505afa158015611def573d6000803e3d6000fd5b505050506040513d6020811015611e0557600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482018890525160448083019260209291908290030181600087803b158015611e5557600080fd5b505af1158015611e69573d6000803e3d6000fd5b505050506040513d6020811015611e7f57600080fd5b50505b6000805460408051636e53a8d360e11b81526001600160a01b0386811660048301528c811660248301528b81166044830152606482018990529151919092169263dca751a692608480820193602093909283900390910190829087803b158015611eeb57600080fd5b505af1158015611eff573d6000803e3d6000fd5b505050506040513d6020811015611f1557600080fd5b505192508215801590611f285750858310155b611f72576040805162461bcd60e51b81526020600482015260166024820152751a5b9d985b1a59081c9958d95a5d9948185b5bdd5b9d60521b604482015290519081900360640190fd5b6001600160a01b0381161561205e57806001600160a01b0316638723c37786856040518363ffffffff1660e01b81526004018080602001838152602001828103825284818151815260200191508051906020019080838360005b83811015611fe4578181015183820152602001611fcc565b50505050905090810190601f1680156120115780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b15801561203157600080fd5b505af1158015612045573d6000803e3d6000fd5b505050506040513d602081101561205b57600080fd5b50505b604080516001600160a01b03891681526020810185905281517f44e2ab5a6cfe856e15b49f53aec49ff1d9d164735554befaac76ac4dec58af93929181900390910190a15050505050505050565b61271090820204900390565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612112908590612171565b50505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610739908490612171565b6014015190565b612183826001600160a01b0316612329565b6121d4576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106122125780518252601f1990920191602091820191016121f3565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612274576040519150601f19603f3d011682016040523d82523d6000602084013e612279565b606091505b5091509150816122d0576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115612112578080602001905160208110156122ec57600080fd5b50516121125760405162461bcd60e51b815260040180806020018281038252602a815260200180612387602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470811580159061235d5750808214155b94935050505056fe696e73756666696369656e74206261736520746f6b656e20616c6c6f77616e63655361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a265627a7a723158203129de11953014b9d1ea7c745e60d4f6de0bc1558b484a846a8c938a5a7cddb564736f6c634300050c0032000000000000000000000000f65d91333b1d4d3887016b17741ad602d77685940000000000000000000000005d9bf2bad3dd710e4d533681ed16ed1cfeac9e6f
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100935760003560e01c8063692058c211610066578063692058c2146103385780637813e50a1461035c578063863cb94e14610426578063a1f419c9146104a9578063e6a12ca9146105fa57610093565b806316114acd1461009857806333da59af146100c0578063590ba492146101c35780635fb31d7714610302575b600080fd5b6100be600480360360208110156100ae57600080fd5b50356001600160a01b0316610602565b005b6101b160048036036101008110156100d757600080fd5b6001600160a01b0382358116926020810135926040820135909216916060820135919081019060a081016080820135600160201b81111561011757600080fd5b82018360208201111561012957600080fd5b803590602001918460018302840111600160201b8311171561014a57600080fd5b919390928235926020810135929190606081019060400135600160201b81111561017357600080fd5b82018360208201111561018557600080fd5b803590602001918460018302840111600160201b831117156101a657600080fd5b50909250905061073f565b60408051918252519081900360200190f35b6100be60048036036101208110156101da57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561021457600080fd5b82018360208201111561022657600080fd5b803590602001918460018302840111600160201b8311171561024757600080fd5b91939092823592604081019060200135600160201b81111561026857600080fd5b82018360208201111561027a57600080fd5b803590602001918460018302840111600160201b8311171561029b57600080fd5b919390928235926020810135929190606081019060400135600160201b8111156102c457600080fd5b8201836020820111156102d657600080fd5b803590602001918460018302840111600160201b831117156102f757600080fd5b509092509050610ddf565b6101b16004803603606081101561031857600080fd5b506001600160a01b03813581169160208101359091169060400135611179565b6103406113de565b604080516001600160a01b039092168252519081900360200190f35b6101b1600480360360a081101561037257600080fd5b6001600160a01b0382358116926020810135926040820135909216916060820135919081019060a081016080820135600160201b8111156103b257600080fd5b8201836020820111156103c457600080fd5b803590602001918460018302840111600160201b831117156103e557600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506113ed945050505050565b6100be6004803603606081101561043c57600080fd5b6001600160a01b0382351691602081013591810190606081016040820135600160201b81111561046b57600080fd5b82018360208201111561047d57600080fd5b803590602001918460018302840111600160201b8311171561049e57600080fd5b5090925090506114c8565b6101b1600480360360c08110156104bf57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b8111156104f957600080fd5b82018360208201111561050b57600080fd5b803590602001918460018302840111600160201b8311171561052c57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092958435959094909350604081019250602001359050600160201b81111561058657600080fd5b82018360208201111561059857600080fd5b803590602001918460018302840111600160201b831117156105b957600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611860945050505050565b6103406119a2565b6001600160a01b038116610643576040513390303180156108fc02916000818181858888f1935050505015801561063d573d6000803e3d6000fd5b5061073c565b604080516370a0823160e01b815230600482015290516001600160a01b0383169163a9059cbb91339184916370a0823191602480820192602092909190829003018186803b15801561069457600080fd5b505afa1580156106a8573d6000803e3d6000fd5b505050506040513d60208110156106be57600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091525160448083019260209291908290030181600087803b15801561070f57600080fd5b505af1158015610723573d6000803e3d6000fd5b505050506040513d602081101561073957600080fd5b50505b50565b600080546040805163359af54960e21b81526001600160a01b038c8116600483015291518493929092169163d66bd52491602480820192602092909190829003018186803b15801561079057600080fd5b505afa1580156107a4573d6000803e3d6000fd5b505050506040513d60208110156107ba57600080fd5b505190506001600160a01b03811661080d576040805162461bcd60e51b81526020600482015260116024820152703ab739bab83837b93a32b2103a37b5b2b760791b604482015290519081900360640190fd5b60006108528d8d8d8d8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113ed92505050565b905089431115610af5576001546040805163028c4f4160e41b81526001600160a01b038e81166004830152915160009392909216916328c4f41091602480820192602092909190829003018186803b1580156108ad57600080fd5b505afa1580156108c1573d6000803e3d6000fd5b505050506040513d60208110156108d757600080fd5b5051604051632ed2876360e21b815260048101848152602482018b9052604482018a9052608060648301908152608483018990526001600160a01b039093169263bb4a1d8c9286928d928d928d928d92909160a401848480828437600081840152601f19601f8201169050808301925050509650505050505050602060405180830381600087803b15801561096b57600080fd5b505af115801561097f573d6000803e3d6000fd5b505050506040513d602081101561099557600080fd5b81019080805190602001909291905050509050600160009054906101000a90046001600160a01b03166001600160a01b03166328c4f4108d6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610a1357600080fd5b505afa158015610a27573d6000803e3d6000fd5b505050506040513d6020811015610a3d57600080fd5b505160408051638723c37760e01b81526024810184905260048101918252604481018c90526001600160a01b0390921691638723c377918d918d9186918190606401858580828437600081840152601f19601f820116905080830192505050945050505050602060405180830381600087803b158015610abc57600080fd5b505af1158015610ad0573d6000803e3d6000fd5b505050506040513d6020811015610ae657600080fd5b5060009450610dd19350505050565b6000546040805163c55dae6360e01b815290518e926001600160a01b03169163c55dae63916004808301926020929190829003018186803b158015610b3957600080fd5b505afa158015610b4d573d6000803e3d6000fd5b505050506040513d6020811015610b6357600080fd5b81019080805190602001909291905050506001600160a01b031663dd62ed3e8f856040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b031681526020019250505060206040518083038186803b158015610be357600080fd5b505afa158015610bf7573d6000803e3d6000fd5b505050506040513d6020811015610c0d57600080fd5b50511015610c4c5760405162461bcd60e51b81526004018080602001828103825260218152602001806123666021913960400191505060405180910390fd5b6000610c918c8989858a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506119b192505050565b90508b6001600160a01b031663095ea7b384836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015610cf357600080fd5b505af1158015610d07573d6000803e3d6000fd5b505050506040513d6020811015610d1d57600080fd5b810190808051906020019092919050505050826001600160a01b0316631ece366a8f8f848f6040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b03168152602001848152602001838152602001828152602001945050505050602060405180830381600087803b158015610d9f57600080fd5b505af1158015610db3573d6000803e3d6000fd5b505050506040513d6020811015610dc957600080fd5b505193505050505b9a9950505050505050505050565b6000610e698d8d8d8d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508c8c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061186092505050565b9050874310611087576000600160009054906101000a90046001600160a01b03166001600160a01b03166328c4f4108f6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610edf57600080fd5b505afa158015610ef3573d6000803e3d6000fd5b505050506040513d6020811015610f0957600080fd5b505190506001600160a01b0381161561108057806001600160a01b031663bb4a1d8c83888888886040518663ffffffff1660e01b815260040180868152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050602060405180830381600087803b158015610fa657600080fd5b505af1158015610fba573d6000803e3d6000fd5b505050506040513d6020811015610fd057600080fd5b5051600281905560408051638723c37760e01b81526024810183905260048101918252604481018a90526001600160a01b03841692638723c377928c928c9291908190606401858580828437600081840152601f19601f820116905080830192505050945050505050602060405180830381600087803b15801561105357600080fd5b505af1158015611067573d6000803e3d6000fd5b505050506040513d602081101561107d57600080fd5b50505b505061116b565b6110ca8d86868487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506119b192505050565b6002819055507ff9a8a6f3535e914cfd5fef422f9f604a324554db59d703e57cf12e77139140e38d60025460405180836001600160a01b03166001600160a01b031681526020018281526020019250505060405180910390a16111698d8d8d8d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506002549150611b569050565b505b505050505050505050505050565b6001546040805163028c4f4160e41b81526001600160a01b0385811660048301529151600093859385939116916328c4f41091602480820192602092909190829003018186803b1580156111cc57600080fd5b505afa1580156111e0573d6000803e3d6000fd5b505050506040513d60208110156111f657600080fd5b505190506001600160a01b0381161561127a5761127784826001600160a01b031663dfe03d326040518163ffffffff1660e01b815260040160206040518083038186803b15801561124657600080fd5b505afa15801561125a573d6000803e3d6000fd5b505050506040513d602081101561127057600080fd5b50516120ac565b91505b6000805460408051635fb31d7760e01b81526001600160a01b038a8116600483015289811660248301526044820187905291519190921691635fb31d77916064808301926020929190829003018186803b1580156112d757600080fd5b505afa1580156112eb573d6000803e3d6000fd5b505050506040513d602081101561130157600080fd5b50516001546040805163028c4f4160e41b81526001600160a01b038a81166004830152915193945060009391909216916328c4f410916024808301926020929190829003018186803b15801561135657600080fd5b505afa15801561136a573d6000803e3d6000fd5b505050506040513d602081101561138057600080fd5b505190506001600160a01b038116156113d3576113d082826001600160a01b0316639d5d4cd86040518163ffffffff1660e01b815260040160206040518083038186803b15801561124657600080fd5b91505b509695505050505050565b6000546001600160a01b031681565b6000858585858560405160200180866001600160a01b03166001600160a01b03168152602001858152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611470578181015183820152602001611458565b50505050905090810190601f16801561149d5780820380516001836020036101000a031916815260200191505b5096505050505050506040516020818303038152906040528051906020012090505b95945050505050565b600080546040805163359af54960e21b81526001600160a01b0388811660048301529151919092169163d66bd524916024808301926020929190829003018186803b15801561151657600080fd5b505afa15801561152a573d6000803e3d6000fd5b505050506040513d602081101561154057600080fd5b505190506001600160a01b038116611593576040805162461bcd60e51b81526020600482015260116024820152703ab739bab83837b93a32b2103a37b5b2b760791b604482015290519081900360640190fd5b6115ae6001600160a01b03821633308763ffffffff6120b816565b600080826001600160a01b0316639c8f9f23876040518263ffffffff1660e01b8152600401808281526020019150506040805180830381600087803b1580156115f657600080fd5b505af115801561160a573d6000803e3d6000fd5b505050506040513d604081101561162057600080fd5b5080516020918201516040805163c55dae6360e01b815290519295509093506116b492339286926001600160a01b0389169263c55dae6392600480840193829003018186803b15801561167257600080fd5b505afa158015611686573d6000803e3d6000fd5b505050506040513d602081101561169c57600080fd5b50516001600160a01b0316919063ffffffff61211816565b600160009054906101000a90046001600160a01b03166001600160a01b03166328c4f410846001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561171157600080fd5b505afa158015611725573d6000803e3d6000fd5b505050506040513d602081101561173b57600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b039092166004830152516024808301926020929190829003018186803b15801561178257600080fd5b505afa158015611796573d6000803e3d6000fd5b505050506040513d60208110156117ac57600080fd5b505160408051638723c37760e01b81526024810184905260048101918252604481018790526001600160a01b0390921691638723c377918891889186918190606401858580828437600081840152601f19601f820116905080830192505050945050505050602060405180830381600087803b15801561182b57600080fd5b505af115801561183f573d6000803e3d6000fd5b505050506040513d602081101561185557600080fd5b505050505050505050565b600086868686868660405160200180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b031681526020018581526020018060200184815260200180602001838103835286818151815260200191508051906020019080838360005b838110156118e85781810151838201526020016118d0565b50505050905090810190601f1680156119155780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b83811015611948578181015183820152602001611930565b50505050905090810190601f1680156119755780820380516001836020036101000a031916815260200191505b50985050505050505050506040516020818303038152906040528051906020012090509695505050505050565b6001546001600160a01b031681565b6001546040805163028c4f4160e41b81526001600160a01b0388811660048301529151600093849316916328c4f410916024808301926020929190829003018186803b158015611a0057600080fd5b505afa158015611a14573d6000803e3d6000fd5b505050506040513d6020811015611a2a57600080fd5b505190506001600160a01b03811615611b3257806001600160a01b031663bb4a1d8c858888876040518563ffffffff1660e01b81526004018085815260200184815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611aae578181015183820152602001611a96565b50505050905090810190601f168015611adb5780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015611afd57600080fd5b505af1158015611b11573d6000803e3d6000fd5b505050506040513d6020811015611b2757600080fd5b505191506114bf9050565b611b4d6001600160a01b03881633308963ffffffff6120b816565b859150506114bf565b6001546040805163028c4f4160e41b81526001600160a01b0387811660048301529151600093849384939116916328c4f41091602480820192602092909190829003018186803b158015611ba957600080fd5b505afa158015611bbd573d6000803e3d6000fd5b505050506040513d6020811015611bd357600080fd5b505190506001600160a01b03811615611bee57309150611bfa565b611bf78561216a565b91505b6000809054906101000a90046001600160a01b03166001600160a01b031663c55dae636040518163ffffffff1660e01b815260040160206040518083038186803b158015611c4757600080fd5b505afa158015611c5b573d6000803e3d6000fd5b505050506040513d6020811015611c7157600080fd5b50516001600160a01b0389811691161415611d86576000546040805163359af54960e21b81526001600160a01b038a811660048301529151828c169363095ea7b393169163d66bd524916024808301926020929190829003018186803b158015611cda57600080fd5b505afa158015611cee573d6000803e3d6000fd5b505050506040513d6020811015611d0457600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482018890525160448083019260209291908290030181600087803b158015611d5457600080fd5b505af1158015611d68573d6000803e3d6000fd5b505050506040513d6020811015611d7e57600080fd5b50611e829050565b6000546040805163359af54960e21b81526001600160a01b03808c16600483018190529251929363095ea7b39391169163d66bd524916024808301926020929190829003018186803b158015611ddb57600080fd5b505afa158015611def573d6000803e3d6000fd5b505050506040513d6020811015611e0557600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482018890525160448083019260209291908290030181600087803b158015611e5557600080fd5b505af1158015611e69573d6000803e3d6000fd5b505050506040513d6020811015611e7f57600080fd5b50505b6000805460408051636e53a8d360e11b81526001600160a01b0386811660048301528c811660248301528b81166044830152606482018990529151919092169263dca751a692608480820193602093909283900390910190829087803b158015611eeb57600080fd5b505af1158015611eff573d6000803e3d6000fd5b505050506040513d6020811015611f1557600080fd5b505192508215801590611f285750858310155b611f72576040805162461bcd60e51b81526020600482015260166024820152751a5b9d985b1a59081c9958d95a5d9948185b5bdd5b9d60521b604482015290519081900360640190fd5b6001600160a01b0381161561205e57806001600160a01b0316638723c37786856040518363ffffffff1660e01b81526004018080602001838152602001828103825284818151815260200191508051906020019080838360005b83811015611fe4578181015183820152602001611fcc565b50505050905090810190601f1680156120115780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b15801561203157600080fd5b505af1158015612045573d6000803e3d6000fd5b505050506040513d602081101561205b57600080fd5b50505b604080516001600160a01b03891681526020810185905281517f44e2ab5a6cfe856e15b49f53aec49ff1d9d164735554befaac76ac4dec58af93929181900390910190a15050505050505050565b61271090820204900390565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612112908590612171565b50505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610739908490612171565b6014015190565b612183826001600160a01b0316612329565b6121d4576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106122125780518252601f1990920191602091820191016121f3565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612274576040519150601f19603f3d011682016040523d82523d6000602084013e612279565b606091505b5091509150816122d0576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115612112578080602001905160208110156122ec57600080fd5b50516121125760405162461bcd60e51b815260040180806020018281038252602a815260200180612387602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470811580159061235d5750808214155b94935050505056fe696e73756666696369656e74206261736520746f6b656e20616c6c6f77616e63655361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a265627a7a723158203129de11953014b9d1ea7c745e60d4f6de0bc1558b484a846a8c938a5a7cddb564736f6c634300050c0032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f65d91333b1d4d3887016b17741ad602d77685940000000000000000000000005d9bf2bad3dd710e4d533681ed16ed1cfeac9e6f
-----Decoded View---------------
Arg [0] : _dex (address): 0xf65d91333B1d4d3887016b17741aD602d7768594
Arg [1] : _shifterRegistry (address): 0x5d9bF2Bad3dD710e4D533681ed16eD1cfeAc9e6F
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000f65d91333b1d4d3887016b17741ad602d7768594
Arg [1] : 0000000000000000000000005d9bf2bad3dd710e4d533681ed16ed1cfeac9e6f
Deployed Bytecode Sourcemap
74150:7094:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;74150:7094:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74679:270;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;74679:270:0;-1:-1:-1;;;;;74679:270:0;;:::i;:::-;;76744:1255;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;76744:1255:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;76744:1255:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;76744:1255:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;76744:1255:0;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;76744:1255:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;76744:1255:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;76744:1255:0;;-1:-1:-1;76744:1255:0;-1:-1:-1;76744:1255:0;:::i;:::-;;;;;;;;;;;;;;;;75030:1049;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;75030:1049:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;75030:1049:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;75030:1049:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;75030:1049:0;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;75030:1049:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;75030:1049:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;75030:1049:0;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;75030:1049:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;75030:1049:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;75030:1049:0;;-1:-1:-1;75030:1049:0;-1:-1:-1;75030:1049:0;:::i;80319:763::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;80319:763:0;;;;;;;;;;;;;;;;;:::i;74211:14::-;;;:::i;:::-;;;;-1:-1:-1;;;;;74211:14:0;;;;;;;;;;;;;;76418:318;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;76418:318:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;76418:318:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;76418:318:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;76418:318:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;76418:318:0;;-1:-1:-1;76418:318:0;;-1:-1:-1;;;;;76418:318:0:i;78007:592::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;78007:592:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;78007:592:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;78007:592:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;78007:592:0;;-1:-1:-1;78007:592:0;-1:-1:-1;78007:592:0;:::i;76087:323::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;76087:323:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;76087:323:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;76087:323:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;76087:323:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;76087:323:0;;;;;;;;;-1:-1:-1;76087:323:0;;;;-1:-1:-1;76087:323:0;;;;-1:-1:-1;;;;5:28;;2:2;;;46:1;43;36:12;2:2;76087:323:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;76087:323:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;76087:323:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;76087:323:0;;-1:-1:-1;76087:323:0;;-1:-1:-1;;;;;76087:323:0:i;74232:38::-;;;:::i;74679:270::-;-1:-1:-1;;;;;74742:22:0;;74738:204;;74781:42;;:10;;74809:4;74801:21;74781:42;;;;;;;;;74801:21;74781:10;:42;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;74781:42:0;74738:204;;;74891:38;;;-1:-1:-1;;;74891:38:0;;74923:4;74891:38;;;;;;-1:-1:-1;;;;;74856:22:0;;;;;74879:10;;74856:22;;74891:23;;:38;;;;;;;;;;;;;;;74856:22;74891:38;;;5:2:-1;;;;30:1;27;20:12;5:2;74891:38:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;74891:38:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;74891:38:0;74856:74;;;-1:-1:-1;;;;;;74856:74:0;;;;;;;-1:-1:-1;;;;;74856:74:0;;;;;;;;;;;;;;;;;;;;74891:38;;74856:74;;;;;;;-1:-1:-1;74856:74:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;74856:74:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;74856:74:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;74738:204:0;74679:270;:::o;76744:1255::-;76985:7;77030:3;;:20;;;-1:-1:-1;;;77030:20:0;;-1:-1:-1;;;;;77030:20:0;;;;;;;;;76985:7;;77030:3;;;;;:12;;:20;;;;;;;;;;;;;;;:3;:20;;;5:2:-1;;;;30:1;27;20:12;5:2;77030:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;77030:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;77030:20:0;;-1:-1:-1;;;;;;77073:26:0;;77065:56;;;;;-1:-1:-1;;;77065:56:0;;;;;;;;;;;;-1:-1:-1;;;77065:56:0;;;;;;;;;;;;;;;77136:14;77153:90;77174:18;77194:13;77209:6;77217:9;77228:14;;77153:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;77153:20:0;;-1:-1:-1;;;77153:90:0:i;:::-;77136:107;;77277:9;77262:12;:24;77258:296;;;77331:15;;:41;;;-1:-1:-1;;;77331:41:0;;-1:-1:-1;;;;;77331:41:0;;;;;;;;;77307:21;;77331:15;;;;;:33;;:41;;;;;;;;;;;;;;;:15;:41;;;5:2:-1;;;;30:1;27;20:12;5:2;77331:41:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;77331:41:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;77331:41:0;:80;;-1:-1:-1;;;77331:80:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;77331:49:0;;;;;;77381:6;;77389:7;;77398:6;;77406:4;;;;77331:80;;;;77406:4;;;;77331:80;1:33:-1;99:1;93:3;85:6;81:16;74:27;137:4;133:9;126:4;121:3;117:14;113:30;106:37;;169:3;161:6;157:16;147:26;;77331:80:0;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;77331:80:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;77331:80:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;77331:80:0;;;;;;;;;;;;;;;;77307:104;;77430:15;;;;;;;;;-1:-1:-1;;;;;77430:15:0;-1:-1:-1;;;;;77430:33:0;;77464:6;77430:41;;;;;;;;;;;;;-1:-1:-1;;;;;77430:41:0;-1:-1:-1;;;;;77430:41:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;77430:41:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;77430:41:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;77430:41:0;:81;;;-1:-1:-1;;;77430:81:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;77430:50:0;;;;;;77481:14;;;;77497:13;;77430:81;;;;77481:14;;;;77430:81;1:33:-1;99:1;93:3;85:6;81:16;74:27;137:4;133:9;126:4;121:3;117:14;113:30;106:37;;169:3;161:6;157:16;147:26;;77430:81:0;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;77430:81:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;77430:81:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;77537:1:0;;-1:-1:-1;77530:8:0;;-1:-1:-1;;;;77530:8:0;77258:296;77582:3;;:15;;;-1:-1:-1;;;77582:15:0;;;;77650:13;;-1:-1:-1;;;;;77582:3:0;;:13;;:15;;;;;;;;;;;;;;:3;:15;;;5:2:-1;;;;30:1;27;20:12;5:2;77582:15:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;77582:15:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;77582:15:0;;;;;;;;;;;;;;;;-1:-1:-1;;;;;77576:32:0;;77609:18;77637:7;77576:70;;;;;;;;;;;;;-1:-1:-1;;;;;77576:70:0;-1:-1:-1;;;;;77576:70:0;;;;;;-1:-1:-1;;;;;77576:70:0;-1:-1:-1;;;;;77576:70:0;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;77576:70:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;77576:70:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;77576:70:0;:87;;77568:150;;;;-1:-1:-1;;;77568:150:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;77733:25;77761:50;77773:6;77781:7;77790:6;77798;77806:4;;77761:50;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;77761:11:0;;-1:-1:-1;;;77761:50:0:i;:::-;77733:78;;77832:6;-1:-1:-1;;;;;77826:21:0;;77856:7;77866:17;77826:58;;;;;;;;;;;;;-1:-1:-1;;;;;77826:58:0;-1:-1:-1;;;;;77826:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;77826:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;77826:58:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;77826:58:0;;;;;;;;;;;;;;;;;77906:7;-1:-1:-1;;;;;77906:20:0;;77927:18;77947:13;77962:17;77981:9;77906:85;;;;;;;;;;;;;-1:-1:-1;;;;;77906:85:0;-1:-1:-1;;;;;77906:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;77906:85:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;77906:85:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;77906:85:0;;-1:-1:-1;;;;76744:1255:0;;;;;;;;;;;;;:::o;75030:1049::-;75362:13;75378:72;75395:4;75401;75407:10;75419:3;;75378:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;93:3;85:6;81:16;74:27;137:4;133:9;126:4;121:3;117:14;113:30;106:37;;169:3;161:6;157:16;147:26;;75378:72:0;;;;;;75424:9;75435:14;;75378:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;75378:16:0;;-1:-1:-1;;;75378:72:0:i;:::-;75362:88;;75546:9;75530:12;:25;75526:354;;75572:16;75591:15;;;;;;;;;-1:-1:-1;;;;;75591:15:0;-1:-1:-1;;;;;75591:33:0;;75633:4;75591:48;;;;;;;;;;;;;-1:-1:-1;;;;;75591:48:0;-1:-1:-1;;;;;75591:48:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;75591:48:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;75591:48:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;75591:48:0;;-1:-1:-1;;;;;;75658:24:0;;;75654:194;;75720:7;-1:-1:-1;;;;;75720:15:0;;75736:5;75743:7;75752:6;75760:4;;75720:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;93:3;85:6;81:16;74:27;137:4;133:9;126:4;121:3;117:14;113:30;106:37;;169:3;161:6;157:16;147:26;;75720:45:0;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;75720:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;75720:45:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;75720:45:0;75703:14;:62;;;75784:48;;;-1:-1:-1;;;75784:48:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;75784:16:0;;;;;75801:14;;;;75720:45;75784:48;;;;;75801:14;;;;75784:48;1:33:-1;99:1;93:3;85:6;81:16;74:27;137:4;133:9;126:4;121:3;117:14;113:30;106:37;;169:3;161:6;157:16;147:26;;75784:48:0;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;75784:48:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;75784:48:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;75654:194:0;75862:7;;;;75526:354;75909:47;75921:4;75927:7;75936:6;75944:5;75951:4;;75909:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;75909:11:0;;-1:-1:-1;;;75909:47:0:i;:::-;75892:14;:64;;;;75972:35;75986:4;75992:14;;75972:35;;;;-1:-1:-1;;;;;75972:35:0;-1:-1:-1;;;;;75972:35:0;;;;;;;;;;;;;;;;;;;;;76018:53;76027:4;76033;76039:10;76051:3;;76018:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;;76056:14:0;;;-1:-1:-1;76018:8:0;;-1:-1:-1;76018:53:0:i;:::-;75030:1049;;;;;;;;;;;;;;:::o;80319:763::-;80541:15;;:39;;;-1:-1:-1;;;80541:39:0;;-1:-1:-1;;;;;80541:39:0;;;;;;;;;80421:7;;80462:11;;80421:7;;80541:15;;;:33;;:39;;;;;;;;;;;;;;;:15;:39;;;5:2:-1;;;;30:1;27;20:12;5:2;80541:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;80541:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;80541:39:0;;-1:-1:-1;;;;;;80595:27:0;;;80591:120;;80652:47;80662:11;80675:10;-1:-1:-1;;;;;80675:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;80675:23:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;80675:23:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;80675:23:0;80652:9;:47::i;:::-;80639:60;;80591:120;80723:21;80747:3;;:50;;;-1:-1:-1;;;80747:50:0;;-1:-1:-1;;;;;80747:50:0;;;;;;;;;;;;;;;;;;;;;;:3;;;;;:26;;:50;;;;;;;;;;;;;;:3;:50;;;5:2:-1;;;;30:1;27;20:12;5:2;80747:50:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;80747:50:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;80747:50:0;80866:15;;:39;;;-1:-1:-1;;;80866:39:0;;-1:-1:-1;;;;;80866:39:0;;;;;;;;;80747:50;;-1:-1:-1;80844:19:0;;80866:15;;;;;:33;;:39;;;;;80747:50;;80866:39;;;;;;;:15;:39;;;5:2:-1;;;;30:1;27;20:12;5:2;80866:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;80866:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;80866:39:0;;-1:-1:-1;;;;;;80920:27:0;;;80916:126;;80980:50;80990:13;81005:10;-1:-1:-1;;;;;81005:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;80980:50:0;80964:66;;80916:126;-1:-1:-1;81061:13:0;80319:763;-1:-1:-1;;;;;;80319:763:0:o;74211:14::-;;;-1:-1:-1;;;;;74211:14:0;;:::o;76418:318::-;76610:7;76658:18;76678:13;76693:6;76701:9;76712:14;76647:80;;;;;;-1:-1:-1;;;;;76647:80:0;-1:-1:-1;;;;;76647:80:0;;;;;;;;;;;-1:-1:-1;;;;;76647:80:0;-1:-1:-1;;;;;76647:80:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;76647:80:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;76647:80:0;;;76637:91;;;;;;76630:98;;76418:318;;;;;;;;:::o;78007:592::-;78118:18;78139:3;;:20;;;-1:-1:-1;;;78139:20:0;;-1:-1:-1;;;;;78139:20:0;;;;;;;;;:3;;;;;:12;;:20;;;;;;;;;;;;;;:3;:20;;;5:2:-1;;;;30:1;27;20:12;5:2;78139:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;78139:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;78139:20:0;;-1:-1:-1;;;;;;78178:26:0;;78170:56;;;;;-1:-1:-1;;;78170:56:0;;;;;;;;;;;;-1:-1:-1;;;78170:56:0;;;;;;;;;;;;;;;78237:70;-1:-1:-1;;;;;78237:31:0;;78269:10;78289:4;78296:10;78237:70;:31;:70;:::i;:::-;78319:23;78344:24;78372:7;-1:-1:-1;;;;;78372:23:0;;78396:10;78372:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;78372:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;78372:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;78372:35:0;;;;;;;;78418:19;;-1:-1:-1;;;78418:19:0;;;;78372:35;;-1:-1:-1;78372:35:0;;-1:-1:-1;78418:61:0;;78451:10;;78372:35;;-1:-1:-1;;;;;78418:17:0;;;;;:19;;;;;;;;;;:17;:19;;;5:2:-1;;;;30:1;27;20:12;5:2;78418:19:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;78418:19:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;78418:19:0;-1:-1:-1;;;;;78418:32:0;;:61;;:32;:61;:::i;:::-;78490:15;;;;;;;;;-1:-1:-1;;;;;78490:15:0;-1:-1:-1;;;;;78490:33:0;;78532:7;-1:-1:-1;;;;;78532:13:0;;:15;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;78532:15:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;78532:15:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;78532:15:0;78490:59;;;-1:-1:-1;;;;;;78490:59:0;;;;;;;-1:-1:-1;;;;;78490:59:0;;;;;;;;;;;;;78532:15;;78490:59;;;;;;;;;;;5:2:-1;;;;30:1;27;20:12;5:2;78490:59:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;78490:59:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;78490:59:0;:101;;;-1:-1:-1;;;78490:101:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;78490:68:0;;;;;;78559:13;;;;78574:16;;78490:101;;;;78559:13;;;;78490:101;1:33:-1;99:1;93:3;85:6;81:16;74:27;137:4;133:9;126:4;121:3;117:14;113:30;106:37;;169:3;161:6;157:16;147:26;;78490:101:0;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;78490:101:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;78490:101:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;;;;78007:592:0:o;76087:323::-;76298:7;76346:4;76352;76358:10;76370:3;76375:9;76386:14;76335:66;;;;;;-1:-1:-1;;;;;76335:66:0;-1:-1:-1;;;;;76335:66:0;;;;;;-1:-1:-1;;;;;76335:66:0;-1:-1:-1;;;;;76335:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;76335:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;76335:66:0;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;76335:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;76335:66:0;;;76325:77;;;;;;76318:84;;76087:323;;;;;;;;:::o;74232:38::-;;;-1:-1:-1;;;;;74232:38:0;;:::o;79515:512::-;79725:15;;:48;;;-1:-1:-1;;;79725:48:0;;-1:-1:-1;;;;;79725:48:0;;;;;;;;;79686:7;;;;79725:15;;:33;;:48;;;;;;;;;;;;;;:15;:48;;;5:2:-1;;;;30:1;27;20:12;5:2;79725:48:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;79725:48:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;79725:48:0;;-1:-1:-1;;;;;;79788:24:0;;;79784:236;;79836:7;-1:-1:-1;;;;;79836:15:0;;79852:6;79860:7;79869:6;79877:4;79836:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;79836:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;79836:46:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;79836:46:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;79836:46:0;;-1:-1:-1;79829:53:0;;-1:-1:-1;79829:53:0;79784:236;79915:64;-1:-1:-1;;;;;79915:28:0;;79944:10;79964:4;79971:7;79915:64;:28;:64;:::i;:::-;80001:7;79994:14;;;;;78607:900;78810:15;;:48;;;-1:-1:-1;;;78810:48:0;;-1:-1:-1;;;;;78810:48:0;;;;;;;;;78744:15;;;;;;78810;;;:33;;:48;;;;;;;;;;;;;;;:15;:48;;;5:2:-1;;;;30:1;27;20:12;5:2;78810:48:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;78810:48:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;78810:48:0;;-1:-1:-1;;;;;;78875:24:0;;;78871:133;;78929:4;78916:18;;78871:133;;;78972:20;78988:3;78972:15;:20::i;:::-;78967:25;;78871:133;79028:3;;;;;;;;;-1:-1:-1;;;;;79028:3:0;-1:-1:-1;;;;;79028:13:0;;:15;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;79028:15:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;79028:15:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;79028:15:0;-1:-1:-1;;;;;79020:23:0;;;;;;79016:203;;;79088:3;;:18;;;-1:-1:-1;;;79088:18:0;;-1:-1:-1;;;;;79088:18:0;;;;;;;;;79060:19;;;;;;79088:3;;:12;;:18;;;;;;;;;;;;;;:3;:18;;;5:2:-1;;;;30:1;27;20:12;5:2;79088:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;79088:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;79088:18:0;79060:57;;;-1:-1:-1;;;;;;79060:57:0;;;;;;;-1:-1:-1;;;;;79060:57:0;;;;;;;;;;;;;;;;;;;79088:18;;79060:57;;;;;;;-1:-1:-1;79060:57:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;79060:57:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;79060:57:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;79016:203:0;;-1:-1:-1;79016:203:0;;79178:3;;:18;;;-1:-1:-1;;;79178:18:0;;-1:-1:-1;;;;;79150:19:0;;;79178:18;;;;;;;;79150:19;;;;79178:3;;;:12;;:18;;;;;;;;;;;;;;:3;:18;;;5:2:-1;;;;30:1;27;20:12;5:2;79178:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;79178:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;79178:18:0;79150:57;;;-1:-1:-1;;;;;;79150:57:0;;;;;;;-1:-1:-1;;;;;79150:57:0;;;;;;;;;;;;;;;;;;;79178:18;;79150:57;;;;;;;-1:-1:-1;79150:57:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;79150:57:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;79150:57:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;79016:203:0;79239:3;;;:34;;;-1:-1:-1;;;79239:34:0;;-1:-1:-1;;;;;79239:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:3;;;;;:9;;:34;;;;;;;;;;;;;;;;;;:3;:34;;;5:2:-1;;;;30:1;27;20:12;5:2;79239:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;79239:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;79239:34:0;;-1:-1:-1;79294:11:0;;;;;:36;;;79320:10;79309:7;:21;;79294:36;79286:71;;;;;-1:-1:-1;;;79286:71:0;;;;;;;;;;;;-1:-1:-1;;;79286:71:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;79372:24:0;;;79368:87;;79413:7;-1:-1:-1;;;;;79413:16:0;;79430:3;79435:7;79413:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;79413:30:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;79413:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;79413:30:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;79368:87:0;79470:29;;;-1:-1:-1;;;;;79470:29:0;;;;;;;;;;;;;;;;;;;;;;;78607:900;;;;;;;;:::o;81090:151::-;81228:5;81206:20;;;81205:28;81195:38;;;81090:151::o;45651:204::-;45778:68;;;-1:-1:-1;;;;;45778:68:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;45778:68:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;45752:95:0;;45771:5;;45752:18;:95::i;:::-;45651:204;;;;:::o;45467:176::-;45576:58;;;-1:-1:-1;;;;;45576:58:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;45576:58:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;45550:85:0;;45569:5;;45550:18;:85::i;80035:276::-;80267:2;80256:14;80250:21;;80035:276::o;47506:1114::-;48110:27;48118:5;-1:-1:-1;;;;;48110:25:0;;:27::i;:::-;48102:71;;;;;-1:-1:-1;;;48102:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;48247:12;48261:23;48296:5;-1:-1:-1;;;;;48288:19:0;48308:4;48288:25;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;48288:25:0;;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;48246:67:0;;;;48332:7;48324:52;;;;;-1:-1:-1;;;48324:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48393:17;;:21;48389:224;;48535:10;48524:30;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;48524:30:0;48516:85;;;;-1:-1:-1;;;48516:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;42400:810;42460:4;43119:20;;42962:66;43159:15;;;;;:42;;;43190:11;43178:8;:23;;43159:42;43151:51;42400:810;-1:-1:-1;;;;42400:810:0:o
Swarm Source
bzzr://3129de11953014b9d1ea7c745e60d4f6de0bc1558b484a846a8c938a5a7cddb5
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 25 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.