Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
DutchExchange
Compiler Version
v0.5.2+commit.1df8f40c
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2019-02-08 */ pragma solidity ^0.5.2; // File: @gnosis.pm/util-contracts/contracts/Proxy.sol /// @title Proxied - indicates that a contract will be proxied. Also defines storage requirements for Proxy. /// @author Alan Lu - <[email protected]> contract Proxied { address public masterCopy; } /// @title Proxy - Generic proxy contract allows to execute all transactions applying the code of a master contract. /// @author Stefan George - <[email protected]> contract Proxy is Proxied { /// @dev Constructor function sets address of master copy contract. /// @param _masterCopy Master copy address. constructor(address _masterCopy) public { require(_masterCopy != address(0), "The master copy is required"); masterCopy = _masterCopy; } /// @dev Fallback function forwards all transactions and returns all received return data. function() external payable { address _masterCopy = masterCopy; assembly { calldatacopy(0, 0, calldatasize) let success := delegatecall(not(0), _masterCopy, 0, calldatasize, 0, 0) returndatacopy(0, 0, returndatasize) switch success case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } } } // File: @gnosis.pm/util-contracts/contracts/Token.sol /// Implements ERC 20 Token standard: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md pragma solidity ^0.5.2; /// @title Abstract token contract - Functions to be implemented by token contracts contract Token { /* * Events */ event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); /* * Public functions */ function transfer(address to, uint value) public returns (bool); function transferFrom(address from, address to, uint value) public returns (bool); function approve(address spender, uint value) public returns (bool); function balanceOf(address owner) public view returns (uint); function allowance(address owner, address spender) public view returns (uint); function totalSupply() public view returns (uint); } // File: @gnosis.pm/util-contracts/contracts/Math.sol /// @title Math library - Allows calculation of logarithmic and exponential functions /// @author Alan Lu - <[email protected]> /// @author Stefan George - <[email protected]> library GnosisMath { /* * Constants */ // This is equal to 1 in our calculations uint public constant ONE = 0x10000000000000000; uint public constant LN2 = 0xb17217f7d1cf79ac; uint public constant LOG2_E = 0x171547652b82fe177; /* * Public functions */ /// @dev Returns natural exponential function value of given x /// @param x x /// @return e**x function exp(int x) public pure returns (uint) { // revert if x is > MAX_POWER, where // MAX_POWER = int(mp.floor(mp.log(mpf(2**256 - 1) / ONE) * ONE)) require(x <= 2454971259878909886679); // return 0 if exp(x) is tiny, using // MIN_POWER = int(mp.floor(mp.log(mpf(1) / ONE) * ONE)) if (x < -818323753292969962227) return 0; // Transform so that e^x -> 2^x x = x * int(ONE) / int(LN2); // 2^x = 2^whole(x) * 2^frac(x) // ^^^^^^^^^^ is a bit shift // so Taylor expand on z = frac(x) int shift; uint z; if (x >= 0) { shift = x / int(ONE); z = uint(x % int(ONE)); } else { shift = x / int(ONE) - 1; z = ONE - uint(-x % int(ONE)); } // 2^x = 1 + (ln 2) x + (ln 2)^2/2! x^2 + ... // // Can generate the z coefficients using mpmath and the following lines // >>> from mpmath import mp // >>> mp.dps = 100 // >>> ONE = 0x10000000000000000 // >>> print('\n'.join(hex(int(mp.log(2)**i / mp.factorial(i) * ONE)) for i in range(1, 7))) // 0xb17217f7d1cf79ab // 0x3d7f7bff058b1d50 // 0xe35846b82505fc5 // 0x276556df749cee5 // 0x5761ff9e299cc4 // 0xa184897c363c3 uint zpow = z; uint result = ONE; result += 0xb17217f7d1cf79ab * zpow / ONE; zpow = zpow * z / ONE; result += 0x3d7f7bff058b1d50 * zpow / ONE; zpow = zpow * z / ONE; result += 0xe35846b82505fc5 * zpow / ONE; zpow = zpow * z / ONE; result += 0x276556df749cee5 * zpow / ONE; zpow = zpow * z / ONE; result += 0x5761ff9e299cc4 * zpow / ONE; zpow = zpow * z / ONE; result += 0xa184897c363c3 * zpow / ONE; zpow = zpow * z / ONE; result += 0xffe5fe2c4586 * zpow / ONE; zpow = zpow * z / ONE; result += 0x162c0223a5c8 * zpow / ONE; zpow = zpow * z / ONE; result += 0x1b5253d395e * zpow / ONE; zpow = zpow * z / ONE; result += 0x1e4cf5158b * zpow / ONE; zpow = zpow * z / ONE; result += 0x1e8cac735 * zpow / ONE; zpow = zpow * z / ONE; result += 0x1c3bd650 * zpow / ONE; zpow = zpow * z / ONE; result += 0x1816193 * zpow / ONE; zpow = zpow * z / ONE; result += 0x131496 * zpow / ONE; zpow = zpow * z / ONE; result += 0xe1b7 * zpow / ONE; zpow = zpow * z / ONE; result += 0x9c7 * zpow / ONE; if (shift >= 0) { if (result >> (256 - shift) > 0) return (2 ** 256 - 1); return result << shift; } else return result >> (-shift); } /// @dev Returns natural logarithm value of given x /// @param x x /// @return ln(x) function ln(uint x) public pure returns (int) { require(x > 0); // binary search for floor(log2(x)) int ilog2 = floorLog2(x); int z; if (ilog2 < 0) z = int(x << uint(-ilog2)); else z = int(x >> uint(ilog2)); // z = x * 2^-⌊log₂x⌋ // so 1 <= z < 2 // and ln z = ln x - ⌊log₂x⌋/log₂e // so just compute ln z using artanh series // and calculate ln x from that int term = (z - int(ONE)) * int(ONE) / (z + int(ONE)); int halflnz = term; int termpow = term * term / int(ONE) * term / int(ONE); halflnz += termpow / 3; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 5; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 7; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 9; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 11; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 13; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 15; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 17; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 19; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 21; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 23; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 25; return (ilog2 * int(ONE)) * int(ONE) / int(LOG2_E) + 2 * halflnz; } /// @dev Returns base 2 logarithm value of given x /// @param x x /// @return logarithmic value function floorLog2(uint x) public pure returns (int lo) { lo = -64; int hi = 193; // I use a shift here instead of / 2 because it floors instead of rounding towards 0 int mid = (hi + lo) >> 1; while ((lo + 1) < hi) { if (mid < 0 && x << uint(-mid) < ONE || mid >= 0 && x >> uint(mid) < ONE) hi = mid; else lo = mid; mid = (hi + lo) >> 1; } } /// @dev Returns maximum of an array /// @param nums Numbers to look through /// @return Maximum number function max(int[] memory nums) public pure returns (int maxNum) { require(nums.length > 0); maxNum = -2 ** 255; for (uint i = 0; i < nums.length; i++) if (nums[i] > maxNum) maxNum = nums[i]; } /// @dev Returns whether an add operation causes an overflow /// @param a First addend /// @param b Second addend /// @return Did no overflow occur? function safeToAdd(uint a, uint b) internal pure returns (bool) { return a + b >= a; } /// @dev Returns whether a subtraction operation causes an underflow /// @param a Minuend /// @param b Subtrahend /// @return Did no underflow occur? function safeToSub(uint a, uint b) internal pure returns (bool) { return a >= b; } /// @dev Returns whether a multiply operation causes an overflow /// @param a First factor /// @param b Second factor /// @return Did no overflow occur? function safeToMul(uint a, uint b) internal pure returns (bool) { return b == 0 || a * b / b == a; } /// @dev Returns sum if no overflow occurred /// @param a First addend /// @param b Second addend /// @return Sum function add(uint a, uint b) internal pure returns (uint) { require(safeToAdd(a, b)); return a + b; } /// @dev Returns difference if no overflow occurred /// @param a Minuend /// @param b Subtrahend /// @return Difference function sub(uint a, uint b) internal pure returns (uint) { require(safeToSub(a, b)); return a - b; } /// @dev Returns product if no overflow occurred /// @param a First factor /// @param b Second factor /// @return Product function mul(uint a, uint b) internal pure returns (uint) { require(safeToMul(a, b)); return a * b; } /// @dev Returns whether an add operation causes an overflow /// @param a First addend /// @param b Second addend /// @return Did no overflow occur? function safeToAdd(int a, int b) internal pure returns (bool) { return (b >= 0 && a + b >= a) || (b < 0 && a + b < a); } /// @dev Returns whether a subtraction operation causes an underflow /// @param a Minuend /// @param b Subtrahend /// @return Did no underflow occur? function safeToSub(int a, int b) internal pure returns (bool) { return (b >= 0 && a - b <= a) || (b < 0 && a - b > a); } /// @dev Returns whether a multiply operation causes an overflow /// @param a First factor /// @param b Second factor /// @return Did no overflow occur? function safeToMul(int a, int b) internal pure returns (bool) { return (b == 0) || (a * b / b == a); } /// @dev Returns sum if no overflow occurred /// @param a First addend /// @param b Second addend /// @return Sum function add(int a, int b) internal pure returns (int) { require(safeToAdd(a, b)); return a + b; } /// @dev Returns difference if no overflow occurred /// @param a Minuend /// @param b Subtrahend /// @return Difference function sub(int a, int b) internal pure returns (int) { require(safeToSub(a, b)); return a - b; } /// @dev Returns product if no overflow occurred /// @param a First factor /// @param b Second factor /// @return Product function mul(int a, int b) internal pure returns (int) { require(safeToMul(a, b)); return a * b; } } // File: @gnosis.pm/util-contracts/contracts/GnosisStandardToken.sol /** * Deprecated: Use Open Zeppeling one instead */ contract StandardTokenData { /* * Storage */ mapping(address => uint) balances; mapping(address => mapping(address => uint)) allowances; uint totalTokens; } /** * Deprecated: Use Open Zeppeling one instead */ /// @title Standard token contract with overflow protection contract GnosisStandardToken is Token, StandardTokenData { using GnosisMath for *; /* * Public functions */ /// @dev Transfers sender's tokens to a given address. Returns success /// @param to Address of token receiver /// @param value Number of tokens to transfer /// @return Was transfer successful? function transfer(address to, uint value) public returns (bool) { if (!balances[msg.sender].safeToSub(value) || !balances[to].safeToAdd(value)) { return false; } balances[msg.sender] -= value; balances[to] += value; emit Transfer(msg.sender, to, value); return true; } /// @dev Allows allowed third party to transfer tokens from one address to another. Returns success /// @param from Address from where tokens are withdrawn /// @param to Address to where tokens are sent /// @param value Number of tokens to transfer /// @return Was transfer successful? function transferFrom(address from, address to, uint value) public returns (bool) { if (!balances[from].safeToSub(value) || !allowances[from][msg.sender].safeToSub( value ) || !balances[to].safeToAdd(value)) { return false; } balances[from] -= value; allowances[from][msg.sender] -= value; balances[to] += value; emit Transfer(from, to, value); return true; } /// @dev Sets approved amount of tokens for spender. Returns success /// @param spender Address of allowed account /// @param value Number of approved tokens /// @return Was approval successful? function approve(address spender, uint value) public returns (bool) { allowances[msg.sender][spender] = value; emit Approval(msg.sender, spender, value); return true; } /// @dev Returns number of allowed tokens for given address /// @param owner Address of token owner /// @param spender Address of token spender /// @return Remaining allowance for spender function allowance(address owner, address spender) public view returns (uint) { return allowances[owner][spender]; } /// @dev Returns number of tokens owned by given address /// @param owner Address of token owner /// @return Balance of owner function balanceOf(address owner) public view returns (uint) { return balances[owner]; } /// @dev Returns total supply of tokens /// @return Total supply function totalSupply() public view returns (uint) { return totalTokens; } } // File: contracts/TokenFRT.sol /// @title Standard token contract with overflow protection contract TokenFRT is Proxied, GnosisStandardToken { address public owner; string public constant symbol = "MGN"; string public constant name = "Magnolia Token"; uint8 public constant decimals = 18; struct UnlockedToken { uint amountUnlocked; uint withdrawalTime; } /* * Storage */ address public minter; // user => UnlockedToken mapping(address => UnlockedToken) public unlockedTokens; // user => amount mapping(address => uint) public lockedTokenBalances; /* * Public functions */ // @dev allows to set the minter of Magnolia tokens once. // @param _minter the minter of the Magnolia tokens, should be the DX-proxy function updateMinter(address _minter) public { require(msg.sender == owner, "Only the minter can set a new one"); require(_minter != address(0), "The new minter must be a valid address"); minter = _minter; } // @dev the intention is to set the owner as the DX-proxy, once it is deployed // Then only an update of the DX-proxy contract after a 30 days delay could change the minter again. function updateOwner(address _owner) public { require(msg.sender == owner, "Only the owner can update the owner"); require(_owner != address(0), "The new owner must be a valid address"); owner = _owner; } function mintTokens(address user, uint amount) public { require(msg.sender == minter, "Only the minter can mint tokens"); lockedTokenBalances[user] = add(lockedTokenBalances[user], amount); totalTokens = add(totalTokens, amount); } /// @dev Lock Token function lockTokens(uint amount) public returns (uint totalAmountLocked) { // Adjust amount by balance uint actualAmount = min(amount, balances[msg.sender]); // Update state variables balances[msg.sender] = sub(balances[msg.sender], actualAmount); lockedTokenBalances[msg.sender] = add(lockedTokenBalances[msg.sender], actualAmount); // Get return variable totalAmountLocked = lockedTokenBalances[msg.sender]; } function unlockTokens() public returns (uint totalAmountUnlocked, uint withdrawalTime) { // Adjust amount by locked balances uint amount = lockedTokenBalances[msg.sender]; if (amount > 0) { // Update state variables lockedTokenBalances[msg.sender] = sub(lockedTokenBalances[msg.sender], amount); unlockedTokens[msg.sender].amountUnlocked = add(unlockedTokens[msg.sender].amountUnlocked, amount); unlockedTokens[msg.sender].withdrawalTime = now + 24 hours; } // Get return variables totalAmountUnlocked = unlockedTokens[msg.sender].amountUnlocked; withdrawalTime = unlockedTokens[msg.sender].withdrawalTime; } function withdrawUnlockedTokens() public { require(unlockedTokens[msg.sender].withdrawalTime < now, "The tokens cannot be withdrawn yet"); balances[msg.sender] = add(balances[msg.sender], unlockedTokens[msg.sender].amountUnlocked); unlockedTokens[msg.sender].amountUnlocked = 0; } function min(uint a, uint b) public pure returns (uint) { if (a < b) { return a; } else { return b; } } /// @dev Returns whether an add operation causes an overflow /// @param a First addend /// @param b Second addend /// @return Did no overflow occur? function safeToAdd(uint a, uint b) public pure returns (bool) { return a + b >= a; } /// @dev Returns whether a subtraction operation causes an underflow /// @param a Minuend /// @param b Subtrahend /// @return Did no underflow occur? function safeToSub(uint a, uint b) public pure returns (bool) { return a >= b; } /// @dev Returns sum if no overflow occurred /// @param a First addend /// @param b Second addend /// @return Sum function add(uint a, uint b) public pure returns (uint) { require(safeToAdd(a, b), "It must be a safe adition"); return a + b; } /// @dev Returns difference if no overflow occurred /// @param a Minuend /// @param b Subtrahend /// @return Difference function sub(uint a, uint b) public pure returns (uint) { require(safeToSub(a, b), "It must be a safe substraction"); return a - b; } } // File: @gnosis.pm/owl-token/contracts/TokenOWL.sol contract TokenOWL is Proxied, GnosisStandardToken { using GnosisMath for *; string public constant name = "OWL Token"; string public constant symbol = "OWL"; uint8 public constant decimals = 18; struct masterCopyCountdownType { address masterCopy; uint timeWhenAvailable; } masterCopyCountdownType masterCopyCountdown; address public creator; address public minter; event Minted(address indexed to, uint256 amount); event Burnt(address indexed from, address indexed user, uint256 amount); modifier onlyCreator() { // R1 require(msg.sender == creator, "Only the creator can perform the transaction"); _; } /// @dev trickers the update process via the proxyMaster for a new address _masterCopy /// updating is only possible after 30 days function startMasterCopyCountdown(address _masterCopy) public onlyCreator { require(address(_masterCopy) != address(0), "The master copy must be a valid address"); // Update masterCopyCountdown masterCopyCountdown.masterCopy = _masterCopy; masterCopyCountdown.timeWhenAvailable = now + 30 days; } /// @dev executes the update process via the proxyMaster for a new address _masterCopy function updateMasterCopy() public onlyCreator { require(address(masterCopyCountdown.masterCopy) != address(0), "The master copy must be a valid address"); require( block.timestamp >= masterCopyCountdown.timeWhenAvailable, "It's not possible to update the master copy during the waiting period" ); // Update masterCopy masterCopy = masterCopyCountdown.masterCopy; } function getMasterCopy() public view returns (address) { return masterCopy; } /// @dev Set minter. Only the creator of this contract can call this. /// @param newMinter The new address authorized to mint this token function setMinter(address newMinter) public onlyCreator { minter = newMinter; } /// @dev change owner/creator of the contract. Only the creator/owner of this contract can call this. /// @param newOwner The new address, which should become the owner function setNewOwner(address newOwner) public onlyCreator { creator = newOwner; } /// @dev Mints OWL. /// @param to Address to which the minted token will be given /// @param amount Amount of OWL to be minted function mintOWL(address to, uint amount) public { require(minter != address(0), "The minter must be initialized"); require(msg.sender == minter, "Only the minter can mint OWL"); balances[to] = balances[to].add(amount); totalTokens = totalTokens.add(amount); emit Minted(to, amount); } /// @dev Burns OWL. /// @param user Address of OWL owner /// @param amount Amount of OWL to be burnt function burnOWL(address user, uint amount) public { allowances[user][msg.sender] = allowances[user][msg.sender].sub(amount); balances[user] = balances[user].sub(amount); totalTokens = totalTokens.sub(amount); emit Burnt(msg.sender, user, amount); } } // File: contracts/base/SafeTransfer.sol interface BadToken { function transfer(address to, uint value) external; function transferFrom(address from, address to, uint value) external; } contract SafeTransfer { function safeTransfer(address token, address to, uint value, bool from) internal returns (bool result) { if (from) { BadToken(token).transferFrom(msg.sender, address(this), value); } else { BadToken(token).transfer(to, value); } // solium-disable-next-line security/no-inline-assembly assembly { switch returndatasize case 0 { // This is our BadToken result := not(0) // result is true } case 32 { // This is our GoodToken returndatacopy(0, 0, 32) result := mload(0) // result == returndata of external call } default { // This is not an ERC20 token result := 0 } } return result; } } // File: contracts/base/AuctioneerManaged.sol contract AuctioneerManaged { // auctioneer has the power to manage some variables address public auctioneer; function updateAuctioneer(address _auctioneer) public onlyAuctioneer { require(_auctioneer != address(0), "The auctioneer must be a valid address"); auctioneer = _auctioneer; } // > Modifiers modifier onlyAuctioneer() { // Only allows auctioneer to proceed // R1 // require(msg.sender == auctioneer, "Only auctioneer can perform this operation"); require(msg.sender == auctioneer, "Only the auctioneer can nominate a new one"); _; } } // File: contracts/base/TokenWhitelist.sol contract TokenWhitelist is AuctioneerManaged { // Mapping that stores the tokens, which are approved // Only tokens approved by auctioneer generate frtToken tokens // addressToken => boolApproved mapping(address => bool) public approvedTokens; event Approval(address indexed token, bool approved); /// @dev for quick overview of approved Tokens /// @param addressesToCheck are the ERC-20 token addresses to be checked whether they are approved function getApprovedAddressesOfList(address[] calldata addressesToCheck) external view returns (bool[] memory) { uint length = addressesToCheck.length; bool[] memory isApproved = new bool[](length); for (uint i = 0; i < length; i++) { isApproved[i] = approvedTokens[addressesToCheck[i]]; } return isApproved; } function updateApprovalOfToken(address[] memory token, bool approved) public onlyAuctioneer { for (uint i = 0; i < token.length; i++) { approvedTokens[token[i]] = approved; emit Approval(token[i], approved); } } } // File: contracts/base/DxMath.sol contract DxMath { // > Math fns function min(uint a, uint b) public pure returns (uint) { if (a < b) { return a; } else { return b; } } function atleastZero(int a) public pure returns (uint) { if (a < 0) { return 0; } else { return uint(a); } } /// @dev Returns whether an add operation causes an overflow /// @param a First addend /// @param b Second addend /// @return Did no overflow occur? function safeToAdd(uint a, uint b) public pure returns (bool) { return a + b >= a; } /// @dev Returns whether a subtraction operation causes an underflow /// @param a Minuend /// @param b Subtrahend /// @return Did no underflow occur? function safeToSub(uint a, uint b) public pure returns (bool) { return a >= b; } /// @dev Returns whether a multiply operation causes an overflow /// @param a First factor /// @param b Second factor /// @return Did no overflow occur? function safeToMul(uint a, uint b) public pure returns (bool) { return b == 0 || a * b / b == a; } /// @dev Returns sum if no overflow occurred /// @param a First addend /// @param b Second addend /// @return Sum function add(uint a, uint b) public pure returns (uint) { require(safeToAdd(a, b)); return a + b; } /// @dev Returns difference if no overflow occurred /// @param a Minuend /// @param b Subtrahend /// @return Difference function sub(uint a, uint b) public pure returns (uint) { require(safeToSub(a, b)); return a - b; } /// @dev Returns product if no overflow occurred /// @param a First factor /// @param b Second factor /// @return Product function mul(uint a, uint b) public pure returns (uint) { require(safeToMul(a, b)); return a * b; } } // File: contracts/Oracle/DSMath.sol contract DSMath { /* standard uint256 functions */ function add(uint256 x, uint256 y) internal pure returns (uint256 z) { assert((z = x + y) >= x); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { assert((z = x - y) <= x); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { assert((z = x * y) >= x); } function div(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x / y; } function min(uint256 x, uint256 y) internal pure returns (uint256 z) { return x <= y ? x : y; } function max(uint256 x, uint256 y) internal pure returns (uint256 z) { return x >= y ? x : y; } /* uint128 functions (h is for half) */ function hadd(uint128 x, uint128 y) internal pure returns (uint128 z) { assert((z = x + y) >= x); } function hsub(uint128 x, uint128 y) internal pure returns (uint128 z) { assert((z = x - y) <= x); } function hmul(uint128 x, uint128 y) internal pure returns (uint128 z) { assert((z = x * y) >= x); } function hdiv(uint128 x, uint128 y) internal pure returns (uint128 z) { z = x / y; } function hmin(uint128 x, uint128 y) internal pure returns (uint128 z) { return x <= y ? x : y; } function hmax(uint128 x, uint128 y) internal pure returns (uint128 z) { return x >= y ? x : y; } /* int256 functions */ function imin(int256 x, int256 y) internal pure returns (int256 z) { return x <= y ? x : y; } function imax(int256 x, int256 y) internal pure returns (int256 z) { return x >= y ? x : y; } /* WAD math */ uint128 constant WAD = 10 ** 18; function wadd(uint128 x, uint128 y) internal pure returns (uint128) { return hadd(x, y); } function wsub(uint128 x, uint128 y) internal pure returns (uint128) { return hsub(x, y); } function wmul(uint128 x, uint128 y) internal pure returns (uint128 z) { z = cast((uint256(x) * y + WAD / 2) / WAD); } function wdiv(uint128 x, uint128 y) internal pure returns (uint128 z) { z = cast((uint256(x) * WAD + y / 2) / y); } function wmin(uint128 x, uint128 y) internal pure returns (uint128) { return hmin(x, y); } function wmax(uint128 x, uint128 y) internal pure returns (uint128) { return hmax(x, y); } /* RAY math */ uint128 constant RAY = 10 ** 27; function radd(uint128 x, uint128 y) internal pure returns (uint128) { return hadd(x, y); } function rsub(uint128 x, uint128 y) internal pure returns (uint128) { return hsub(x, y); } function rmul(uint128 x, uint128 y) internal pure returns (uint128 z) { z = cast((uint256(x) * y + RAY / 2) / RAY); } function rdiv(uint128 x, uint128 y) internal pure returns (uint128 z) { z = cast((uint256(x) * RAY + y / 2) / y); } function rpow(uint128 x, uint64 n) internal pure returns (uint128 z) { // This famous algorithm is called "exponentiation by squaring" // and calculates x^n with x as fixed-point and n as regular unsigned. // // It's O(log n), instead of O(n) for naive repeated multiplication. // // These facts are why it works: // // If n is even, then x^n = (x^2)^(n/2). // If n is odd, then x^n = x * x^(n-1), // and applying the equation for even x gives // x^n = x * (x^2)^((n-1) / 2). // // Also, EVM division is flooring and // floor[(n-1) / 2] = floor[n / 2]. z = n % 2 != 0 ? x : RAY; for (n /= 2; n != 0; n /= 2) { x = rmul(x, x); if (n % 2 != 0) { z = rmul(z, x); } } } function rmin(uint128 x, uint128 y) internal pure returns (uint128) { return hmin(x, y); } function rmax(uint128 x, uint128 y) internal pure returns (uint128) { return hmax(x, y); } function cast(uint256 x) internal pure returns (uint128 z) { assert((z = uint128(x)) == x); } } // File: contracts/Oracle/DSAuth.sol contract DSAuthority { function canCall(address src, address dst, bytes4 sig) public view returns (bool); } contract DSAuthEvents { event LogSetAuthority(address indexed authority); event LogSetOwner(address indexed owner); } contract DSAuth is DSAuthEvents { DSAuthority public authority; address public owner; constructor() public { owner = msg.sender; emit LogSetOwner(msg.sender); } function setOwner(address owner_) public auth { owner = owner_; emit LogSetOwner(owner); } function setAuthority(DSAuthority authority_) public auth { authority = authority_; emit LogSetAuthority(address(authority)); } modifier auth { require(isAuthorized(msg.sender, msg.sig), "It must be an authorized call"); _; } function isAuthorized(address src, bytes4 sig) internal view returns (bool) { if (src == address(this)) { return true; } else if (src == owner) { return true; } else if (authority == DSAuthority(0)) { return false; } else { return authority.canCall(src, address(this), sig); } } } // File: contracts/Oracle/DSNote.sol contract DSNote { event LogNote( bytes4 indexed sig, address indexed guy, bytes32 indexed foo, bytes32 bar, uint wad, bytes fax ); modifier note { bytes32 foo; bytes32 bar; // solium-disable-next-line security/no-inline-assembly assembly { foo := calldataload(4) bar := calldataload(36) } emit LogNote( msg.sig, msg.sender, foo, bar, msg.value, msg.data ); _; } } // File: contracts/Oracle/DSThing.sol contract DSThing is DSAuth, DSNote, DSMath {} // File: contracts/Oracle/PriceFeed.sol /// price-feed.sol // Copyright (C) 2017 DappHub, LLC // Licensed under the Apache License, Version 2.0 (the "License"). // You may not use this file except in compliance with the License. // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND (express or implied). contract PriceFeed is DSThing { uint128 val; uint32 public zzz; function peek() public view returns (bytes32, bool) { return (bytes32(uint256(val)), block.timestamp < zzz); } function read() public view returns (bytes32) { assert(block.timestamp < zzz); return bytes32(uint256(val)); } function post(uint128 val_, uint32 zzz_, address med_) public payable note auth { val = val_; zzz = zzz_; (bool success, ) = med_.call(abi.encodeWithSignature("poke()")); require(success, "The poke must succeed"); } function void() public payable note auth { zzz = 0; } } // File: contracts/Oracle/DSValue.sol contract DSValue is DSThing { bool has; bytes32 val; function peek() public view returns (bytes32, bool) { return (val, has); } function read() public view returns (bytes32) { (bytes32 wut, bool _has) = peek(); assert(_has); return wut; } function poke(bytes32 wut) public payable note auth { val = wut; has = true; } function void() public payable note auth { // unset the value has = false; } } // File: contracts/Oracle/Medianizer.sol contract Medianizer is DSValue { mapping(bytes12 => address) public values; mapping(address => bytes12) public indexes; bytes12 public next = bytes12(uint96(1)); uint96 public minimun = 0x1; function set(address wat) public auth { bytes12 nextId = bytes12(uint96(next) + 1); assert(nextId != 0x0); set(next, wat); next = nextId; } function set(bytes12 pos, address wat) public payable note auth { require(pos != 0x0, "pos cannot be 0x0"); require(wat == address(0) || indexes[wat] == 0, "wat is not defined or it has an index"); indexes[values[pos]] = bytes12(0); // Making sure to remove a possible existing address in that position if (wat != address(0)) { indexes[wat] = pos; } values[pos] = wat; } function setMin(uint96 min_) public payable note auth { require(min_ != 0x0, "min cannot be 0x0"); minimun = min_; } function setNext(bytes12 next_) public payable note auth { require(next_ != 0x0, "next cannot be 0x0"); next = next_; } function unset(bytes12 pos) public { set(pos, address(0)); } function unset(address wat) public { set(indexes[wat], address(0)); } function poke() public { poke(0); } function poke(bytes32) public payable note { (val, has) = compute(); } function compute() public view returns (bytes32, bool) { bytes32[] memory wuts = new bytes32[](uint96(next) - 1); uint96 ctr = 0; for (uint96 i = 1; i < uint96(next); i++) { if (values[bytes12(i)] != address(0)) { (bytes32 wut, bool wuz) = DSValue(values[bytes12(i)]).peek(); if (wuz) { if (ctr == 0 || wut >= wuts[ctr - 1]) { wuts[ctr] = wut; } else { uint96 j = 0; while (wut >= wuts[j]) { j++; } for (uint96 k = ctr; k > j; k--) { wuts[k] = wuts[k - 1]; } wuts[j] = wut; } ctr++; } } } if (ctr < minimun) return (val, false); bytes32 value; if (ctr % 2 == 0) { uint128 val1 = uint128(uint(wuts[(ctr / 2) - 1])); uint128 val2 = uint128(uint(wuts[ctr / 2])); value = bytes32(uint256(wdiv(hadd(val1, val2), 2 ether))); } else { value = wuts[(ctr - 1) / 2]; } return (value, true); } } // File: contracts/Oracle/PriceOracleInterface.sol /* This contract is the interface between the MakerDAO priceFeed and our DX platform. */ contract PriceOracleInterface { address public priceFeedSource; address public owner; bool public emergencyMode; // Modifiers modifier onlyOwner() { require(msg.sender == owner, "Only the owner can do the operation"); _; } /// @dev constructor of the contract /// @param _priceFeedSource address of price Feed Source -> should be maker feeds Medianizer contract constructor(address _owner, address _priceFeedSource) public { owner = _owner; priceFeedSource = _priceFeedSource; } /// @dev gives the owner the possibility to put the Interface into an emergencyMode, which will /// output always a price of 600 USD. This gives everyone time to set up a new pricefeed. function raiseEmergency(bool _emergencyMode) public onlyOwner { emergencyMode = _emergencyMode; } /// @dev updates the priceFeedSource /// @param _owner address of owner function updateCurator(address _owner) public onlyOwner { owner = _owner; } /// @dev returns the USDETH price function getUsdEthPricePeek() public view returns (bytes32 price, bool valid) { return Medianizer(priceFeedSource).peek(); } /// @dev returns the USDETH price, ie gets the USD price from Maker feed with 18 digits, but last 18 digits are cut off function getUSDETHPrice() public view returns (uint256) { // if the contract is in the emergencyMode, because there is an issue with the oracle, we will simply return a price of 600 USD if (emergencyMode) { return 600; } (bytes32 price, ) = Medianizer(priceFeedSource).peek(); // ensuring that there is no underflow or overflow possible, // even if the price is compromised uint priceUint = uint256(price)/(1 ether); if (priceUint == 0) { return 1; } if (priceUint > 1000000) { return 1000000; } return priceUint; } } // File: contracts/base/EthOracle.sol contract EthOracle is AuctioneerManaged, DxMath { uint constant WAITING_PERIOD_CHANGE_ORACLE = 30 days; // Price Oracle interface PriceOracleInterface public ethUSDOracle; // Price Oracle interface proposals during update process PriceOracleInterface public newProposalEthUSDOracle; uint public oracleInterfaceCountdown; event NewOracleProposal(PriceOracleInterface priceOracleInterface); function initiateEthUsdOracleUpdate(PriceOracleInterface _ethUSDOracle) public onlyAuctioneer { require(address(_ethUSDOracle) != address(0), "The oracle address must be valid"); newProposalEthUSDOracle = _ethUSDOracle; oracleInterfaceCountdown = add(block.timestamp, WAITING_PERIOD_CHANGE_ORACLE); emit NewOracleProposal(_ethUSDOracle); } function updateEthUSDOracle() public { require(address(newProposalEthUSDOracle) != address(0), "The new proposal must be a valid addres"); require( oracleInterfaceCountdown < block.timestamp, "It's not possible to update the oracle during the waiting period" ); ethUSDOracle = newProposalEthUSDOracle; newProposalEthUSDOracle = PriceOracleInterface(0); } } // File: contracts/base/DxUpgrade.sol contract DxUpgrade is Proxied, AuctioneerManaged, DxMath { uint constant WAITING_PERIOD_CHANGE_MASTERCOPY = 30 days; address public newMasterCopy; // Time when new masterCopy is updatabale uint public masterCopyCountdown; event NewMasterCopyProposal(address newMasterCopy); function startMasterCopyCountdown(address _masterCopy) public onlyAuctioneer { require(_masterCopy != address(0), "The new master copy must be a valid address"); // Update masterCopyCountdown newMasterCopy = _masterCopy; masterCopyCountdown = add(block.timestamp, WAITING_PERIOD_CHANGE_MASTERCOPY); emit NewMasterCopyProposal(_masterCopy); } function updateMasterCopy() public { require(newMasterCopy != address(0), "The new master copy must be a valid address"); require(block.timestamp >= masterCopyCountdown, "The master contract cannot be updated in a waiting period"); // Update masterCopy masterCopy = newMasterCopy; newMasterCopy = address(0); } } // File: contracts/DutchExchange.sol /// @title Dutch Exchange - exchange token pairs with the clever mechanism of the dutch auction /// @author Alex Herrmann - <[email protected]> /// @author Dominik Teiml - <[email protected]> contract DutchExchange is DxUpgrade, TokenWhitelist, EthOracle, SafeTransfer { // The price is a rational number, so we need a concept of a fraction struct Fraction { uint num; uint den; } uint constant WAITING_PERIOD_NEW_TOKEN_PAIR = 6 hours; uint constant WAITING_PERIOD_NEW_AUCTION = 10 minutes; uint constant AUCTION_START_WAITING_FOR_FUNDING = 1; // > Storage // Ether ERC-20 token address public ethToken; // Minimum required sell funding for adding a new token pair, in USD uint public thresholdNewTokenPair; // Minimum required sell funding for starting antoher auction, in USD uint public thresholdNewAuction; // Fee reduction token (magnolia, ERC-20 token) TokenFRT public frtToken; // Token for paying fees TokenOWL public owlToken; // For the following three mappings, there is one mapping for each token pair // The order which the tokens should be called is smaller, larger // These variables should never be called directly! They have getters below // Token => Token => index mapping(address => mapping(address => uint)) public latestAuctionIndices; // Token => Token => time mapping (address => mapping (address => uint)) public auctionStarts; // Token => Token => auctionIndex => time mapping (address => mapping (address => mapping (uint => uint))) public clearingTimes; // Token => Token => auctionIndex => price mapping(address => mapping(address => mapping(uint => Fraction))) public closingPrices; // Token => Token => amount mapping(address => mapping(address => uint)) public sellVolumesCurrent; // Token => Token => amount mapping(address => mapping(address => uint)) public sellVolumesNext; // Token => Token => amount mapping(address => mapping(address => uint)) public buyVolumes; // Token => user => amount // balances stores a user's balance in the DutchX mapping(address => mapping(address => uint)) public balances; // Token => Token => auctionIndex => amount mapping(address => mapping(address => mapping(uint => uint))) public extraTokens; // Token => Token => auctionIndex => user => amount mapping(address => mapping(address => mapping(uint => mapping(address => uint)))) public sellerBalances; mapping(address => mapping(address => mapping(uint => mapping(address => uint)))) public buyerBalances; mapping(address => mapping(address => mapping(uint => mapping(address => uint)))) public claimedAmounts; function depositAndSell(address sellToken, address buyToken, uint amount) external returns (uint newBal, uint auctionIndex, uint newSellerBal) { newBal = deposit(sellToken, amount); (auctionIndex, newSellerBal) = postSellOrder(sellToken, buyToken, 0, amount); } function claimAndWithdraw(address sellToken, address buyToken, address user, uint auctionIndex, uint amount) external returns (uint returned, uint frtsIssued, uint newBal) { (returned, frtsIssued) = claimSellerFunds(sellToken, buyToken, user, auctionIndex); newBal = withdraw(buyToken, amount); } /// @dev for multiple claims /// @param auctionSellTokens are the sellTokens defining an auctionPair /// @param auctionBuyTokens are the buyTokens defining an auctionPair /// @param auctionIndices are the auction indices on which an token should be claimedAmounts /// @param user is the user who wants to his tokens function claimTokensFromSeveralAuctionsAsSeller( address[] calldata auctionSellTokens, address[] calldata auctionBuyTokens, uint[] calldata auctionIndices, address user ) external returns (uint[] memory, uint[] memory) { uint length = checkLengthsForSeveralAuctionClaiming(auctionSellTokens, auctionBuyTokens, auctionIndices); uint[] memory claimAmounts = new uint[](length); uint[] memory frtsIssuedList = new uint[](length); for (uint i = 0; i < length; i++) { (claimAmounts[i], frtsIssuedList[i]) = claimSellerFunds( auctionSellTokens[i], auctionBuyTokens[i], user, auctionIndices[i] ); } return (claimAmounts, frtsIssuedList); } /// @dev for multiple claims /// @param auctionSellTokens are the sellTokens defining an auctionPair /// @param auctionBuyTokens are the buyTokens defining an auctionPair /// @param auctionIndices are the auction indices on which an token should be claimedAmounts /// @param user is the user who wants to his tokens function claimTokensFromSeveralAuctionsAsBuyer( address[] calldata auctionSellTokens, address[] calldata auctionBuyTokens, uint[] calldata auctionIndices, address user ) external returns (uint[] memory, uint[] memory) { uint length = checkLengthsForSeveralAuctionClaiming(auctionSellTokens, auctionBuyTokens, auctionIndices); uint[] memory claimAmounts = new uint[](length); uint[] memory frtsIssuedList = new uint[](length); for (uint i = 0; i < length; i++) { (claimAmounts[i], frtsIssuedList[i]) = claimBuyerFunds( auctionSellTokens[i], auctionBuyTokens[i], user, auctionIndices[i] ); } return (claimAmounts, frtsIssuedList); } /// @dev for multiple withdraws /// @param auctionSellTokens are the sellTokens defining an auctionPair /// @param auctionBuyTokens are the buyTokens defining an auctionPair /// @param auctionIndices are the auction indices on which an token should be claimedAmounts function claimAndWithdrawTokensFromSeveralAuctionsAsSeller( address[] calldata auctionSellTokens, address[] calldata auctionBuyTokens, uint[] calldata auctionIndices ) external returns (uint[] memory, uint frtsIssued) { uint length = checkLengthsForSeveralAuctionClaiming(auctionSellTokens, auctionBuyTokens, auctionIndices); uint[] memory claimAmounts = new uint[](length); uint claimFrts = 0; for (uint i = 0; i < length; i++) { (claimAmounts[i], claimFrts) = claimSellerFunds( auctionSellTokens[i], auctionBuyTokens[i], msg.sender, auctionIndices[i] ); frtsIssued += claimFrts; withdraw(auctionBuyTokens[i], claimAmounts[i]); } return (claimAmounts, frtsIssued); } /// @dev for multiple withdraws /// @param auctionSellTokens are the sellTokens defining an auctionPair /// @param auctionBuyTokens are the buyTokens defining an auctionPair /// @param auctionIndices are the auction indices on which an token should be claimedAmounts function claimAndWithdrawTokensFromSeveralAuctionsAsBuyer( address[] calldata auctionSellTokens, address[] calldata auctionBuyTokens, uint[] calldata auctionIndices ) external returns (uint[] memory, uint frtsIssued) { uint length = checkLengthsForSeveralAuctionClaiming(auctionSellTokens, auctionBuyTokens, auctionIndices); uint[] memory claimAmounts = new uint[](length); uint claimFrts = 0; for (uint i = 0; i < length; i++) { (claimAmounts[i], claimFrts) = claimBuyerFunds( auctionSellTokens[i], auctionBuyTokens[i], msg.sender, auctionIndices[i] ); frtsIssued += claimFrts; withdraw(auctionSellTokens[i], claimAmounts[i]); } return (claimAmounts, frtsIssued); } function getMasterCopy() external view returns (address) { return masterCopy; } /// @dev Constructor-Function creates exchange /// @param _frtToken - address of frtToken ERC-20 token /// @param _owlToken - address of owlToken ERC-20 token /// @param _auctioneer - auctioneer for managing interfaces /// @param _ethToken - address of ETH ERC-20 token /// @param _ethUSDOracle - address of the oracle contract for fetching feeds /// @param _thresholdNewTokenPair - Minimum required sell funding for adding a new token pair, in USD function setupDutchExchange( TokenFRT _frtToken, TokenOWL _owlToken, address _auctioneer, address _ethToken, PriceOracleInterface _ethUSDOracle, uint _thresholdNewTokenPair, uint _thresholdNewAuction ) public { // Make sure contract hasn't been initialised require(ethToken == address(0), "The contract must be uninitialized"); // Validates inputs require(address(_owlToken) != address(0), "The OWL address must be valid"); require(address(_frtToken) != address(0), "The FRT address must be valid"); require(_auctioneer != address(0), "The auctioneer address must be valid"); require(_ethToken != address(0), "The WETH address must be valid"); require(address(_ethUSDOracle) != address(0), "The oracle address must be valid"); frtToken = _frtToken; owlToken = _owlToken; auctioneer = _auctioneer; ethToken = _ethToken; ethUSDOracle = _ethUSDOracle; thresholdNewTokenPair = _thresholdNewTokenPair; thresholdNewAuction = _thresholdNewAuction; } function updateThresholdNewTokenPair(uint _thresholdNewTokenPair) public onlyAuctioneer { thresholdNewTokenPair = _thresholdNewTokenPair; } function updateThresholdNewAuction(uint _thresholdNewAuction) public onlyAuctioneer { thresholdNewAuction = _thresholdNewAuction; } /// @param initialClosingPriceNum initial price will be 2 * initialClosingPrice. This is its numerator /// @param initialClosingPriceDen initial price will be 2 * initialClosingPrice. This is its denominator function addTokenPair( address token1, address token2, uint token1Funding, uint token2Funding, uint initialClosingPriceNum, uint initialClosingPriceDen ) public { // R1 require(token1 != token2, "You cannot add a token pair using the same token"); // R2 require(initialClosingPriceNum != 0, "You must set the numerator for the initial price"); // R3 require(initialClosingPriceDen != 0, "You must set the denominator for the initial price"); // R4 require(getAuctionIndex(token1, token2) == 0, "The token pair was already added"); // R5: to prevent overflow require(initialClosingPriceNum < 10 ** 18, "You must set a smaller numerator for the initial price"); // R6 require(initialClosingPriceDen < 10 ** 18, "You must set a smaller denominator for the initial price"); setAuctionIndex(token1, token2); token1Funding = min(token1Funding, balances[token1][msg.sender]); token2Funding = min(token2Funding, balances[token2][msg.sender]); // R7 require(token1Funding < 10 ** 30, "You should use a smaller funding for token 1"); // R8 require(token2Funding < 10 ** 30, "You should use a smaller funding for token 2"); uint fundedValueUSD; uint ethUSDPrice = ethUSDOracle.getUSDETHPrice(); // Compute fundedValueUSD address ethTokenMem = ethToken; if (token1 == ethTokenMem) { // C1 // MUL: 10^30 * 10^6 = 10^36 fundedValueUSD = mul(token1Funding, ethUSDPrice); } else if (token2 == ethTokenMem) { // C2 // MUL: 10^30 * 10^6 = 10^36 fundedValueUSD = mul(token2Funding, ethUSDPrice); } else { // C3: Neither token is ethToken fundedValueUSD = calculateFundedValueTokenToken( token1, token2, token1Funding, token2Funding, ethTokenMem, ethUSDPrice ); } // R5 require(fundedValueUSD >= thresholdNewTokenPair, "You should surplus the threshold for adding token pairs"); // Save prices of opposite auctions closingPrices[token1][token2][0] = Fraction(initialClosingPriceNum, initialClosingPriceDen); closingPrices[token2][token1][0] = Fraction(initialClosingPriceDen, initialClosingPriceNum); // Split into two fns because of 16 local-var cap addTokenPairSecondPart(token1, token2, token1Funding, token2Funding); } function deposit(address tokenAddress, uint amount) public returns (uint) { // R1 require(safeTransfer(tokenAddress, msg.sender, amount, true), "The deposit transaction must succeed"); uint newBal = add(balances[tokenAddress][msg.sender], amount); balances[tokenAddress][msg.sender] = newBal; emit NewDeposit(tokenAddress, amount); return newBal; } function withdraw(address tokenAddress, uint amount) public returns (uint) { uint usersBalance = balances[tokenAddress][msg.sender]; amount = min(amount, usersBalance); // R1 require(amount > 0, "The amount must be greater than 0"); uint newBal = sub(usersBalance, amount); balances[tokenAddress][msg.sender] = newBal; // R2 require(safeTransfer(tokenAddress, msg.sender, amount, false), "The withdraw transfer must succeed"); emit NewWithdrawal(tokenAddress, amount); return newBal; } function postSellOrder(address sellToken, address buyToken, uint auctionIndex, uint amount) public returns (uint, uint) { // Note: if a user specifies auctionIndex of 0, it // means he is agnostic which auction his sell order goes into amount = min(amount, balances[sellToken][msg.sender]); // R1 // require(amount >= 0, "Sell amount should be greater than 0"); // R2 uint latestAuctionIndex = getAuctionIndex(sellToken, buyToken); require(latestAuctionIndex > 0); // R3 uint auctionStart = getAuctionStart(sellToken, buyToken); if (auctionStart == AUCTION_START_WAITING_FOR_FUNDING || auctionStart > now) { // C1: We are in the 10 minute buffer period // OR waiting for an auction to receive sufficient sellVolume // Auction has already cleared, and index has been incremented // sell order must use that auction index // R1.1 if (auctionIndex == 0) { auctionIndex = latestAuctionIndex; } else { require(auctionIndex == latestAuctionIndex, "Auction index should be equal to latest auction index"); } // R1.2 require(add(sellVolumesCurrent[sellToken][buyToken], amount) < 10 ** 30); } else { // C2 // R2.1: Sell orders must go to next auction if (auctionIndex == 0) { auctionIndex = latestAuctionIndex + 1; } else { require(auctionIndex == latestAuctionIndex + 1); } // R2.2 require(add(sellVolumesNext[sellToken][buyToken], amount) < 10 ** 30); } // Fee mechanism, fees are added to extraTokens uint amountAfterFee = settleFee(sellToken, buyToken, auctionIndex, amount); // Update variables balances[sellToken][msg.sender] = sub(balances[sellToken][msg.sender], amount); uint newSellerBal = add(sellerBalances[sellToken][buyToken][auctionIndex][msg.sender], amountAfterFee); sellerBalances[sellToken][buyToken][auctionIndex][msg.sender] = newSellerBal; if (auctionStart == AUCTION_START_WAITING_FOR_FUNDING || auctionStart > now) { // C1 uint sellVolumeCurrent = sellVolumesCurrent[sellToken][buyToken]; sellVolumesCurrent[sellToken][buyToken] = add(sellVolumeCurrent, amountAfterFee); } else { // C2 uint sellVolumeNext = sellVolumesNext[sellToken][buyToken]; sellVolumesNext[sellToken][buyToken] = add(sellVolumeNext, amountAfterFee); // close previous auction if theoretically closed closeTheoreticalClosedAuction(sellToken, buyToken, latestAuctionIndex); } if (auctionStart == AUCTION_START_WAITING_FOR_FUNDING) { scheduleNextAuction(sellToken, buyToken); } emit NewSellOrder(sellToken, buyToken, msg.sender, auctionIndex, amountAfterFee); return (auctionIndex, newSellerBal); } function postBuyOrder(address sellToken, address buyToken, uint auctionIndex, uint amount) public returns (uint newBuyerBal) { // R1: auction must not have cleared require(closingPrices[sellToken][buyToken][auctionIndex].den == 0); uint auctionStart = getAuctionStart(sellToken, buyToken); // R2 require(auctionStart <= now); // R4 require(auctionIndex == getAuctionIndex(sellToken, buyToken)); // R5: auction must not be in waiting period require(auctionStart > AUCTION_START_WAITING_FOR_FUNDING); // R6: auction must be funded require(sellVolumesCurrent[sellToken][buyToken] > 0); uint buyVolume = buyVolumes[sellToken][buyToken]; amount = min(amount, balances[buyToken][msg.sender]); // R7 require(add(buyVolume, amount) < 10 ** 30); // Overbuy is when a part of a buy order clears an auction // In that case we only process the part before the overbuy // To calculate overbuy, we first get current price uint sellVolume = sellVolumesCurrent[sellToken][buyToken]; uint num; uint den; (num, den) = getCurrentAuctionPrice(sellToken, buyToken, auctionIndex); // 10^30 * 10^37 = 10^67 uint outstandingVolume = atleastZero(int(mul(sellVolume, num) / den - buyVolume)); uint amountAfterFee; if (amount < outstandingVolume) { if (amount > 0) { amountAfterFee = settleFee(buyToken, sellToken, auctionIndex, amount); } } else { amount = outstandingVolume; amountAfterFee = outstandingVolume; } // Here we could also use outstandingVolume or amountAfterFee, it doesn't matter if (amount > 0) { // Update variables balances[buyToken][msg.sender] = sub(balances[buyToken][msg.sender], amount); newBuyerBal = add(buyerBalances[sellToken][buyToken][auctionIndex][msg.sender], amountAfterFee); buyerBalances[sellToken][buyToken][auctionIndex][msg.sender] = newBuyerBal; buyVolumes[sellToken][buyToken] = add(buyVolumes[sellToken][buyToken], amountAfterFee); emit NewBuyOrder(sellToken, buyToken, msg.sender, auctionIndex, amountAfterFee); } // Checking for equality would suffice here. nevertheless: if (amount >= outstandingVolume) { // Clear auction clearAuction(sellToken, buyToken, auctionIndex, sellVolume); } return (newBuyerBal); } function claimSellerFunds(address sellToken, address buyToken, address user, uint auctionIndex) public returns ( // < (10^60, 10^61) uint returned, uint frtsIssued ) { closeTheoreticalClosedAuction(sellToken, buyToken, auctionIndex); uint sellerBalance = sellerBalances[sellToken][buyToken][auctionIndex][user]; // R1 require(sellerBalance > 0); // Get closing price for said auction Fraction memory closingPrice = closingPrices[sellToken][buyToken][auctionIndex]; uint num = closingPrice.num; uint den = closingPrice.den; // R2: require auction to have cleared require(den > 0); // Calculate return // < 10^30 * 10^30 = 10^60 returned = mul(sellerBalance, num) / den; frtsIssued = issueFrts( sellToken, buyToken, returned, auctionIndex, sellerBalance, user ); // Claim tokens sellerBalances[sellToken][buyToken][auctionIndex][user] = 0; if (returned > 0) { balances[buyToken][user] = add(balances[buyToken][user], returned); } emit NewSellerFundsClaim( sellToken, buyToken, user, auctionIndex, returned, frtsIssued ); } function claimBuyerFunds(address sellToken, address buyToken, address user, uint auctionIndex) public returns (uint returned, uint frtsIssued) { closeTheoreticalClosedAuction(sellToken, buyToken, auctionIndex); uint num; uint den; (returned, num, den) = getUnclaimedBuyerFunds(sellToken, buyToken, user, auctionIndex); if (closingPrices[sellToken][buyToken][auctionIndex].den == 0) { // Auction is running claimedAmounts[sellToken][buyToken][auctionIndex][user] = add( claimedAmounts[sellToken][buyToken][auctionIndex][user], returned ); } else { // Auction has closed // We DON'T want to check for returned > 0, because that would fail if a user claims // intermediate funds & auction clears in same block (he/she would not be able to claim extraTokens) // Assign extra sell tokens (this is possible only after auction has cleared, // because buyVolume could still increase before that) uint extraTokensTotal = extraTokens[sellToken][buyToken][auctionIndex]; uint buyerBalance = buyerBalances[sellToken][buyToken][auctionIndex][user]; // closingPrices.num represents buyVolume // < 10^30 * 10^30 = 10^60 uint tokensExtra = mul( buyerBalance, extraTokensTotal ) / closingPrices[sellToken][buyToken][auctionIndex].num; returned = add(returned, tokensExtra); frtsIssued = issueFrts( buyToken, sellToken, mul(buyerBalance, den) / num, auctionIndex, buyerBalance, user ); // Auction has closed // Reset buyerBalances and claimedAmounts buyerBalances[sellToken][buyToken][auctionIndex][user] = 0; claimedAmounts[sellToken][buyToken][auctionIndex][user] = 0; } // Claim tokens if (returned > 0) { balances[sellToken][user] = add(balances[sellToken][user], returned); } emit NewBuyerFundsClaim( sellToken, buyToken, user, auctionIndex, returned, frtsIssued ); } /// @dev allows to close possible theoretical closed markets /// @param sellToken sellToken of an auction /// @param buyToken buyToken of an auction /// @param auctionIndex is the auctionIndex of the auction function closeTheoreticalClosedAuction(address sellToken, address buyToken, uint auctionIndex) public { if (auctionIndex == getAuctionIndex( buyToken, sellToken ) && closingPrices[sellToken][buyToken][auctionIndex].num == 0) { uint buyVolume = buyVolumes[sellToken][buyToken]; uint sellVolume = sellVolumesCurrent[sellToken][buyToken]; uint num; uint den; (num, den) = getCurrentAuctionPrice(sellToken, buyToken, auctionIndex); // 10^30 * 10^37 = 10^67 if (sellVolume > 0) { uint outstandingVolume = atleastZero(int(mul(sellVolume, num) / den - buyVolume)); if (outstandingVolume == 0) { postBuyOrder(sellToken, buyToken, auctionIndex, 0); } } } } /// @dev Claim buyer funds for one auction function getUnclaimedBuyerFunds(address sellToken, address buyToken, address user, uint auctionIndex) public view returns ( // < (10^67, 10^37) uint unclaimedBuyerFunds, uint num, uint den ) { // R1: checks if particular auction has ever run require(auctionIndex <= getAuctionIndex(sellToken, buyToken)); (num, den) = getCurrentAuctionPrice(sellToken, buyToken, auctionIndex); if (num == 0) { // This should rarely happen - as long as there is >= 1 buy order, // auction will clear before price = 0. So this is just fail-safe unclaimedBuyerFunds = 0; } else { uint buyerBalance = buyerBalances[sellToken][buyToken][auctionIndex][user]; // < 10^30 * 10^37 = 10^67 unclaimedBuyerFunds = atleastZero( int(mul(buyerBalance, den) / num - claimedAmounts[sellToken][buyToken][auctionIndex][user]) ); } } function getFeeRatio(address user) public view returns ( // feeRatio < 10^4 uint num, uint den ) { uint totalSupply = frtToken.totalSupply(); uint lockedFrt = frtToken.lockedTokenBalances(user); /* Fee Model: locked FRT range Fee ----------------- ------ [0, 0.01%) 0.5% [0.01%, 0.1%) 0.4% [0.1%, 1%) 0.3% [1%, 10%) 0.2% [10%, 100%) 0.1% */ if (lockedFrt * 10000 < totalSupply || totalSupply == 0) { // Maximum fee, if user has locked less than 0.01% of the total FRT // Fee: 0.5% num = 1; den = 200; } else if (lockedFrt * 1000 < totalSupply) { // If user has locked more than 0.01% and less than 0.1% of the total FRT // Fee: 0.4% num = 1; den = 250; } else if (lockedFrt * 100 < totalSupply) { // If user has locked more than 0.1% and less than 1% of the total FRT // Fee: 0.3% num = 3; den = 1000; } else if (lockedFrt * 10 < totalSupply) { // If user has locked more than 1% and less than 10% of the total FRT // Fee: 0.2% num = 1; den = 500; } else { // If user has locked more than 10% of the total FRT // Fee: 0.1% num = 1; den = 1000; } } //@ dev returns price in units [token2]/[token1] //@ param token1 first token for price calculation //@ param token2 second token for price calculation //@ param auctionIndex index for the auction to get the averaged price from function getPriceInPastAuction( address token1, address token2, uint auctionIndex ) public view // price < 10^31 returns (uint num, uint den) { if (token1 == token2) { // C1 num = 1; den = 1; } else { // C2 // R2.1 // require(auctionIndex >= 0); // C3 // R3.1 require(auctionIndex <= getAuctionIndex(token1, token2)); // auction still running uint i = 0; bool correctPair = false; Fraction memory closingPriceToken1; Fraction memory closingPriceToken2; while (!correctPair) { closingPriceToken2 = closingPrices[token2][token1][auctionIndex - i]; closingPriceToken1 = closingPrices[token1][token2][auctionIndex - i]; if (closingPriceToken1.num > 0 && closingPriceToken1.den > 0 || closingPriceToken2.num > 0 && closingPriceToken2.den > 0) { correctPair = true; } i++; } // At this point at least one closing price is strictly positive // If only one is positive, we want to output that if (closingPriceToken1.num == 0 || closingPriceToken1.den == 0) { num = closingPriceToken2.den; den = closingPriceToken2.num; } else if (closingPriceToken2.num == 0 || closingPriceToken2.den == 0) { num = closingPriceToken1.num; den = closingPriceToken1.den; } else { // If both prices are positive, output weighted average num = closingPriceToken2.den + closingPriceToken1.num; den = closingPriceToken2.num + closingPriceToken1.den; } } } function scheduleNextAuction( address sellToken, address buyToken ) internal { (uint sellVolume, uint sellVolumeOpp) = getSellVolumesInUSD(sellToken, buyToken); bool enoughSellVolume = sellVolume >= thresholdNewAuction; bool enoughSellVolumeOpp = sellVolumeOpp >= thresholdNewAuction; bool schedule; // Make sure both sides have liquidity in order to start the auction if (enoughSellVolume && enoughSellVolumeOpp) { schedule = true; } else if (enoughSellVolume || enoughSellVolumeOpp) { // But if the auction didn't start in 24h, then is enough to have // liquidity in one of the two sides uint latestAuctionIndex = getAuctionIndex(sellToken, buyToken); uint clearingTime = getClearingTime(sellToken, buyToken, latestAuctionIndex - 1); schedule = clearingTime <= now - 24 hours; } if (schedule) { // Schedule next auction setAuctionStart(sellToken, buyToken, WAITING_PERIOD_NEW_AUCTION); } else { resetAuctionStart(sellToken, buyToken); } } function getSellVolumesInUSD( address sellToken, address buyToken ) internal view returns (uint sellVolume, uint sellVolumeOpp) { // Check if auctions received enough sell orders uint ethUSDPrice = ethUSDOracle.getUSDETHPrice(); uint sellNum; uint sellDen; (sellNum, sellDen) = getPriceOfTokenInLastAuction(sellToken); uint buyNum; uint buyDen; (buyNum, buyDen) = getPriceOfTokenInLastAuction(buyToken); // We use current sell volume, because in clearAuction() we set // sellVolumesCurrent = sellVolumesNext before calling this function // (this is so that we don't need case work, // since it might also be called from postSellOrder()) // < 10^30 * 10^31 * 10^6 = 10^67 sellVolume = mul(mul(sellVolumesCurrent[sellToken][buyToken], sellNum), ethUSDPrice) / sellDen; sellVolumeOpp = mul(mul(sellVolumesCurrent[buyToken][sellToken], buyNum), ethUSDPrice) / buyDen; } /// @dev Gives best estimate for market price of a token in ETH of any price oracle on the Ethereum network /// @param token address of ERC-20 token /// @return Weighted average of closing prices of opposite Token-ethToken auctions, based on their sellVolume function getPriceOfTokenInLastAuction(address token) public view returns ( // price < 10^31 uint num, uint den ) { uint latestAuctionIndex = getAuctionIndex(token, ethToken); // getPriceInPastAuction < 10^30 (num, den) = getPriceInPastAuction(token, ethToken, latestAuctionIndex - 1); } function getCurrentAuctionPrice(address sellToken, address buyToken, uint auctionIndex) public view returns ( // price < 10^37 uint num, uint den ) { Fraction memory closingPrice = closingPrices[sellToken][buyToken][auctionIndex]; if (closingPrice.den != 0) { // Auction has closed (num, den) = (closingPrice.num, closingPrice.den); } else if (auctionIndex > getAuctionIndex(sellToken, buyToken)) { (num, den) = (0, 0); } else { // Auction is running uint pastNum; uint pastDen; (pastNum, pastDen) = getPriceInPastAuction(sellToken, buyToken, auctionIndex - 1); // If we're calling the function into an unstarted auction, // it will return the starting price of that auction uint timeElapsed = atleastZero(int(now - getAuctionStart(sellToken, buyToken))); // The numbers below are chosen such that // P(0 hrs) = 2 * lastClosingPrice, P(6 hrs) = lastClosingPrice, P(>=24 hrs) = 0 // 10^5 * 10^31 = 10^36 num = atleastZero(int((24 hours - timeElapsed) * pastNum)); // 10^6 * 10^31 = 10^37 den = mul((timeElapsed + 12 hours), pastDen); if (mul(num, sellVolumesCurrent[sellToken][buyToken]) <= mul(den, buyVolumes[sellToken][buyToken])) { num = buyVolumes[sellToken][buyToken]; den = sellVolumesCurrent[sellToken][buyToken]; } } } // > Helper fns function getTokenOrder(address token1, address token2) public pure returns (address, address) { if (token2 < token1) { (token1, token2) = (token2, token1); } return (token1, token2); } function getAuctionStart(address token1, address token2) public view returns (uint auctionStart) { (token1, token2) = getTokenOrder(token1, token2); auctionStart = auctionStarts[token1][token2]; } function getAuctionIndex(address token1, address token2) public view returns (uint auctionIndex) { (token1, token2) = getTokenOrder(token1, token2); auctionIndex = latestAuctionIndices[token1][token2]; } function calculateFundedValueTokenToken( address token1, address token2, uint token1Funding, uint token2Funding, address ethTokenMem, uint ethUSDPrice ) internal view returns (uint fundedValueUSD) { // We require there to exist ethToken-Token auctions // R3.1 require(getAuctionIndex(token1, ethTokenMem) > 0); // R3.2 require(getAuctionIndex(token2, ethTokenMem) > 0); // Price of Token 1 uint priceToken1Num; uint priceToken1Den; (priceToken1Num, priceToken1Den) = getPriceOfTokenInLastAuction(token1); // Price of Token 2 uint priceToken2Num; uint priceToken2Den; (priceToken2Num, priceToken2Den) = getPriceOfTokenInLastAuction(token2); // Compute funded value in ethToken and USD // 10^30 * 10^30 = 10^60 uint fundedValueETH = add( mul(token1Funding, priceToken1Num) / priceToken1Den, token2Funding * priceToken2Num / priceToken2Den ); fundedValueUSD = mul(fundedValueETH, ethUSDPrice); } function addTokenPairSecondPart( address token1, address token2, uint token1Funding, uint token2Funding ) internal { balances[token1][msg.sender] = sub(balances[token1][msg.sender], token1Funding); balances[token2][msg.sender] = sub(balances[token2][msg.sender], token2Funding); // Fee mechanism, fees are added to extraTokens uint token1FundingAfterFee = settleFee(token1, token2, 1, token1Funding); uint token2FundingAfterFee = settleFee(token2, token1, 1, token2Funding); // Update other variables sellVolumesCurrent[token1][token2] = token1FundingAfterFee; sellVolumesCurrent[token2][token1] = token2FundingAfterFee; sellerBalances[token1][token2][1][msg.sender] = token1FundingAfterFee; sellerBalances[token2][token1][1][msg.sender] = token2FundingAfterFee; // Save clearingTime as adding time (address tokenA, address tokenB) = getTokenOrder(token1, token2); clearingTimes[tokenA][tokenB][0] = now; setAuctionStart(token1, token2, WAITING_PERIOD_NEW_TOKEN_PAIR); emit NewTokenPair(token1, token2); } function setClearingTime( address token1, address token2, uint auctionIndex, uint auctionStart, uint sellVolume, uint buyVolume ) internal { (uint pastNum, uint pastDen) = getPriceInPastAuction(token1, token2, auctionIndex - 1); // timeElapsed = (12 hours)*(2 * pastNum * sellVolume - buyVolume * pastDen)/ // (sellVolume * pastNum + buyVolume * pastDen) uint numerator = sub(mul(mul(pastNum, sellVolume), 24 hours), mul(mul(buyVolume, pastDen), 12 hours)); uint timeElapsed = numerator / (add(mul(sellVolume, pastNum), mul(buyVolume, pastDen))); uint clearingTime = auctionStart + timeElapsed; (token1, token2) = getTokenOrder(token1, token2); clearingTimes[token1][token2][auctionIndex] = clearingTime; } function getClearingTime( address token1, address token2, uint auctionIndex ) public view returns (uint time) { (token1, token2) = getTokenOrder(token1, token2); time = clearingTimes[token1][token2][auctionIndex]; } function issueFrts( address primaryToken, address secondaryToken, uint x, uint auctionIndex, uint bal, address user ) internal returns (uint frtsIssued) { if (approvedTokens[primaryToken] && approvedTokens[secondaryToken]) { address ethTokenMem = ethToken; // Get frts issued based on ETH price of returned tokens if (primaryToken == ethTokenMem) { frtsIssued = bal; } else if (secondaryToken == ethTokenMem) { // 10^30 * 10^39 = 10^66 frtsIssued = x; } else { // Neither token is ethToken, so we use getHhistoricalPriceOracle() uint pastNum; uint pastDen; (pastNum, pastDen) = getPriceInPastAuction(primaryToken, ethTokenMem, auctionIndex - 1); // 10^30 * 10^35 = 10^65 frtsIssued = mul(bal, pastNum) / pastDen; } if (frtsIssued > 0) { // Issue frtToken frtToken.mintTokens(user, frtsIssued); } } } function settleFee(address primaryToken, address secondaryToken, uint auctionIndex, uint amount) internal returns ( // < 10^30 uint amountAfterFee ) { uint feeNum; uint feeDen; (feeNum, feeDen) = getFeeRatio(msg.sender); // 10^30 * 10^3 / 10^4 = 10^29 uint fee = mul(amount, feeNum) / feeDen; if (fee > 0) { fee = settleFeeSecondPart(primaryToken, fee); uint usersExtraTokens = extraTokens[primaryToken][secondaryToken][auctionIndex + 1]; extraTokens[primaryToken][secondaryToken][auctionIndex + 1] = add(usersExtraTokens, fee); emit Fee(primaryToken, secondaryToken, msg.sender, auctionIndex, fee); } amountAfterFee = sub(amount, fee); } function settleFeeSecondPart(address primaryToken, uint fee) internal returns (uint newFee) { // Allow user to reduce up to half of the fee with owlToken uint num; uint den; (num, den) = getPriceOfTokenInLastAuction(primaryToken); // Convert fee to ETH, then USD // 10^29 * 10^30 / 10^30 = 10^29 uint feeInETH = mul(fee, num) / den; uint ethUSDPrice = ethUSDOracle.getUSDETHPrice(); // 10^29 * 10^6 = 10^35 // Uses 18 decimal places <> exactly as owlToken tokens: 10**18 owlToken == 1 USD uint feeInUSD = mul(feeInETH, ethUSDPrice); uint amountOfowlTokenBurned = min(owlToken.allowance(msg.sender, address(this)), feeInUSD / 2); amountOfowlTokenBurned = min(owlToken.balanceOf(msg.sender), amountOfowlTokenBurned); if (amountOfowlTokenBurned > 0) { owlToken.burnOWL(msg.sender, amountOfowlTokenBurned); // Adjust fee // 10^35 * 10^29 = 10^64 uint adjustment = mul(amountOfowlTokenBurned, fee) / feeInUSD; newFee = sub(fee, adjustment); } else { newFee = fee; } } // addClearTimes /// @dev clears an Auction /// @param sellToken sellToken of the auction /// @param buyToken buyToken of the auction /// @param auctionIndex of the auction to be cleared. function clearAuction( address sellToken, address buyToken, uint auctionIndex, uint sellVolume ) internal { // Get variables uint buyVolume = buyVolumes[sellToken][buyToken]; uint sellVolumeOpp = sellVolumesCurrent[buyToken][sellToken]; uint closingPriceOppDen = closingPrices[buyToken][sellToken][auctionIndex].den; uint auctionStart = getAuctionStart(sellToken, buyToken); // Update closing price if (sellVolume > 0) { closingPrices[sellToken][buyToken][auctionIndex] = Fraction(buyVolume, sellVolume); } // if (opposite is 0 auction OR price = 0 OR opposite auction cleared) // price = 0 happens if auction pair has been running for >= 24 hrs if (sellVolumeOpp == 0 || now >= auctionStart + 24 hours || closingPriceOppDen > 0) { // Close auction pair uint buyVolumeOpp = buyVolumes[buyToken][sellToken]; if (closingPriceOppDen == 0 && sellVolumeOpp > 0) { // Save opposite price closingPrices[buyToken][sellToken][auctionIndex] = Fraction(buyVolumeOpp, sellVolumeOpp); } uint sellVolumeNext = sellVolumesNext[sellToken][buyToken]; uint sellVolumeNextOpp = sellVolumesNext[buyToken][sellToken]; // Update state variables for both auctions sellVolumesCurrent[sellToken][buyToken] = sellVolumeNext; if (sellVolumeNext > 0) { sellVolumesNext[sellToken][buyToken] = 0; } if (buyVolume > 0) { buyVolumes[sellToken][buyToken] = 0; } sellVolumesCurrent[buyToken][sellToken] = sellVolumeNextOpp; if (sellVolumeNextOpp > 0) { sellVolumesNext[buyToken][sellToken] = 0; } if (buyVolumeOpp > 0) { buyVolumes[buyToken][sellToken] = 0; } // Save clearing time setClearingTime(sellToken, buyToken, auctionIndex, auctionStart, sellVolume, buyVolume); // Increment auction index setAuctionIndex(sellToken, buyToken); // Check if next auction can be scheduled scheduleNextAuction(sellToken, buyToken); } emit AuctionCleared(sellToken, buyToken, sellVolume, buyVolume, auctionIndex); } function setAuctionStart(address token1, address token2, uint value) internal { (token1, token2) = getTokenOrder(token1, token2); uint auctionStart = now + value; uint auctionIndex = latestAuctionIndices[token1][token2]; auctionStarts[token1][token2] = auctionStart; emit AuctionStartScheduled(token1, token2, auctionIndex, auctionStart); } function resetAuctionStart(address token1, address token2) internal { (token1, token2) = getTokenOrder(token1, token2); if (auctionStarts[token1][token2] != AUCTION_START_WAITING_FOR_FUNDING) { auctionStarts[token1][token2] = AUCTION_START_WAITING_FOR_FUNDING; } } function setAuctionIndex(address token1, address token2) internal { (token1, token2) = getTokenOrder(token1, token2); latestAuctionIndices[token1][token2] += 1; } function checkLengthsForSeveralAuctionClaiming( address[] memory auctionSellTokens, address[] memory auctionBuyTokens, uint[] memory auctionIndices ) internal pure returns (uint length) { length = auctionSellTokens.length; uint length2 = auctionBuyTokens.length; require(length == length2); uint length3 = auctionIndices.length; require(length2 == length3); } // > Events event NewDeposit(address indexed token, uint amount); event NewWithdrawal(address indexed token, uint amount); event NewSellOrder( address indexed sellToken, address indexed buyToken, address indexed user, uint auctionIndex, uint amount ); event NewBuyOrder( address indexed sellToken, address indexed buyToken, address indexed user, uint auctionIndex, uint amount ); event NewSellerFundsClaim( address indexed sellToken, address indexed buyToken, address indexed user, uint auctionIndex, uint amount, uint frtsIssued ); event NewBuyerFundsClaim( address indexed sellToken, address indexed buyToken, address indexed user, uint auctionIndex, uint amount, uint frtsIssued ); event NewTokenPair(address indexed sellToken, address indexed buyToken); event AuctionCleared( address indexed sellToken, address indexed buyToken, uint sellVolume, uint buyVolume, uint indexed auctionIndex ); event AuctionStartScheduled( address indexed sellToken, address indexed buyToken, uint indexed auctionIndex, uint auctionStart ); event Fee( address indexed primaryToken, address indexed secondarToken, address indexed user, uint auctionIndex, uint fee ); }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":true,"inputs":[{"name":"token1","type":"address"},{"name":"token2","type":"address"}],"name":"getTokenOrder","outputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"addressesToCheck","type":"address[]"}],"name":"getApprovedAddressesOfList","outputs":[{"name":"","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getMasterCopy","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"sellToken","type":"address"},{"name":"buyToken","type":"address"},{"name":"user","type":"address"},{"name":"auctionIndex","type":"uint256"},{"name":"amount","type":"uint256"}],"name":"claimAndWithdraw","outputs":[{"name":"returned","type":"uint256"},{"name":"frtsIssued","type":"uint256"},{"name":"newBal","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"auctionSellTokens","type":"address[]"},{"name":"auctionBuyTokens","type":"address[]"},{"name":"auctionIndices","type":"uint256[]"}],"name":"claimAndWithdrawTokensFromSeveralAuctionsAsBuyer","outputs":[{"name":"","type":"uint256[]"},{"name":"frtsIssued","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"masterCopyCountdown","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"auctionStarts","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token1","type":"address"},{"name":"token2","type":"address"}],"name":"getAuctionIndex","outputs":[{"name":"auctionIndex","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"updateMasterCopy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"int256"}],"name":"atleastZero","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"uint256"},{"name":"","type":"address"}],"name":"buyerBalances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_ethUSDOracle","type":"address"}],"name":"initiateEthUsdOracleUpdate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tokenAddress","type":"address"},{"name":"amount","type":"uint256"}],"name":"deposit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token1","type":"address"},{"name":"token2","type":"address"},{"name":"auctionIndex","type":"uint256"}],"name":"getPriceInPastAuction","outputs":[{"name":"num","type":"uint256"},{"name":"den","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"safeToAdd","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"sellToken","type":"address"},{"name":"buyToken","type":"address"},{"name":"auctionIndex","type":"uint256"},{"name":"amount","type":"uint256"}],"name":"postSellOrder","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"sellToken","type":"address"},{"name":"buyToken","type":"address"},{"name":"auctionIndex","type":"uint256"},{"name":"amount","type":"uint256"}],"name":"postBuyOrder","outputs":[{"name":"newBuyerBal","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"auctioneer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"sellToken","type":"address"},{"name":"buyToken","type":"address"},{"name":"user","type":"address"},{"name":"auctionIndex","type":"uint256"}],"name":"claimSellerFunds","outputs":[{"name":"returned","type":"uint256"},{"name":"frtsIssued","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"sellToken","type":"address"},{"name":"buyToken","type":"address"},{"name":"amount","type":"uint256"}],"name":"depositAndSell","outputs":[{"name":"newBal","type":"uint256"},{"name":"auctionIndex","type":"uint256"},{"name":"newSellerBal","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address[]"},{"name":"approved","type":"bool"}],"name":"updateApprovalOfToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"approvedTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"thresholdNewTokenPair","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"newMasterCopy","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ethUSDOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token1","type":"address"},{"name":"token2","type":"address"},{"name":"auctionIndex","type":"uint256"}],"name":"getClearingTime","outputs":[{"name":"time","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"add","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"auctionSellTokens","type":"address[]"},{"name":"auctionBuyTokens","type":"address[]"},{"name":"auctionIndices","type":"uint256[]"},{"name":"user","type":"address"}],"name":"claimTokensFromSeveralAuctionsAsSeller","outputs":[{"name":"","type":"uint256[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_auctioneer","type":"address"}],"name":"updateAuctioneer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"min","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"ethToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"sellToken","type":"address"},{"name":"buyToken","type":"address"},{"name":"auctionIndex","type":"uint256"}],"name":"closeTheoreticalClosedAuction","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"frtToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"auctionSellTokens","type":"address[]"},{"name":"auctionBuyTokens","type":"address[]"},{"name":"auctionIndices","type":"uint256[]"}],"name":"claimAndWithdrawTokensFromSeveralAuctionsAsSeller","outputs":[{"name":"","type":"uint256[]"},{"name":"frtsIssued","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"uint256"},{"name":"","type":"address"}],"name":"claimedAmounts","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oracleInterfaceCountdown","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"masterCopy","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_frtToken","type":"address"},{"name":"_owlToken","type":"address"},{"name":"_auctioneer","type":"address"},{"name":"_ethToken","type":"address"},{"name":"_ethUSDOracle","type":"address"},{"name":"_thresholdNewTokenPair","type":"uint256"},{"name":"_thresholdNewAuction","type":"uint256"}],"name":"setupDutchExchange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"sellToken","type":"address"},{"name":"buyToken","type":"address"},{"name":"user","type":"address"},{"name":"auctionIndex","type":"uint256"}],"name":"claimBuyerFunds","outputs":[{"name":"returned","type":"uint256"},{"name":"frtsIssued","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"clearingTimes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"sellVolumesNext","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"sellVolumesCurrent","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"sub","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"buyVolumes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"uint256"},{"name":"","type":"address"}],"name":"sellerBalances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"balances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_thresholdNewAuction","type":"uint256"}],"name":"updateThresholdNewAuction","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"mul","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"safeToMul","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"newProposalEthUSDOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owlToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"auctionSellTokens","type":"address[]"},{"name":"auctionBuyTokens","type":"address[]"},{"name":"auctionIndices","type":"uint256[]"},{"name":"user","type":"address"}],"name":"claimTokensFromSeveralAuctionsAsBuyer","outputs":[{"name":"","type":"uint256[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token1","type":"address"},{"name":"token2","type":"address"}],"name":"getAuctionStart","outputs":[{"name":"auctionStart","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"sellToken","type":"address"},{"name":"buyToken","type":"address"},{"name":"user","type":"address"},{"name":"auctionIndex","type":"uint256"}],"name":"getUnclaimedBuyerFunds","outputs":[{"name":"unclaimedBuyerFunds","type":"uint256"},{"name":"num","type":"uint256"},{"name":"den","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_thresholdNewTokenPair","type":"uint256"}],"name":"updateThresholdNewTokenPair","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"safeToSub","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"token1","type":"address"},{"name":"token2","type":"address"},{"name":"token1Funding","type":"uint256"},{"name":"token2Funding","type":"uint256"},{"name":"initialClosingPriceNum","type":"uint256"},{"name":"initialClosingPriceDen","type":"uint256"}],"name":"addTokenPair","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"closingPrices","outputs":[{"name":"num","type":"uint256"},{"name":"den","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"user","type":"address"}],"name":"getFeeRatio","outputs":[{"name":"num","type":"uint256"},{"name":"den","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"thresholdNewAuction","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"tokenAddress","type":"address"},{"name":"amount","type":"uint256"}],"name":"withdraw","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"getPriceOfTokenInLastAuction","outputs":[{"name":"num","type":"uint256"},{"name":"den","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"updateEthUSDOracle","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_masterCopy","type":"address"}],"name":"startMasterCopyCountdown","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"extraTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"latestAuctionIndices","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"sellToken","type":"address"},{"name":"buyToken","type":"address"},{"name":"auctionIndex","type":"uint256"}],"name":"getCurrentAuctionPrice","outputs":[{"name":"num","type":"uint256"},{"name":"den","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"NewDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"NewWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sellToken","type":"address"},{"indexed":true,"name":"buyToken","type":"address"},{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"auctionIndex","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"NewSellOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sellToken","type":"address"},{"indexed":true,"name":"buyToken","type":"address"},{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"auctionIndex","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"NewBuyOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sellToken","type":"address"},{"indexed":true,"name":"buyToken","type":"address"},{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"auctionIndex","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"frtsIssued","type":"uint256"}],"name":"NewSellerFundsClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sellToken","type":"address"},{"indexed":true,"name":"buyToken","type":"address"},{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"auctionIndex","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"frtsIssued","type":"uint256"}],"name":"NewBuyerFundsClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sellToken","type":"address"},{"indexed":true,"name":"buyToken","type":"address"}],"name":"NewTokenPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sellToken","type":"address"},{"indexed":true,"name":"buyToken","type":"address"},{"indexed":false,"name":"sellVolume","type":"uint256"},{"indexed":false,"name":"buyVolume","type":"uint256"},{"indexed":true,"name":"auctionIndex","type":"uint256"}],"name":"AuctionCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sellToken","type":"address"},{"indexed":true,"name":"buyToken","type":"address"},{"indexed":true,"name":"auctionIndex","type":"uint256"},{"indexed":false,"name":"auctionStart","type":"uint256"}],"name":"AuctionStartScheduled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"primaryToken","type":"address"},{"indexed":true,"name":"secondarToken","type":"address"},{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"auctionIndex","type":"uint256"},{"indexed":false,"name":"fee","type":"uint256"}],"name":"Fee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"priceOracleInterface","type":"address"}],"name":"NewOracleProposal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"approved","type":"bool"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newMasterCopy","type":"address"}],"name":"NewMasterCopyProposal","type":"event"}]
Contract Creation Code
608060405234801561001057600080fd5b506156f6806100206000396000f3fe608060405234801561001057600080fd5b50600436106103f45760003560e060020a9004806382a57b4311610219578063cd94a2a411610129578063edd0b5cb116100bc578063f4279d1f1161008b578063f4279d1f14611397578063f625ee281461139f578063f79710fd146113c5578063fac7abe3146113fb578063fdab1b7b14611429576103f4565b8063edd0b5cb14611317578063ee93114c1461133d578063f3fef3a314611345578063f41d97fc14611371576103f4565b8063e1c95bb9116100f8578063e1c95bb914611259578063e31c71c414611276578063e9f8cd7014611299578063ebcc0de1146112e1576103f4565b8063cd94a2a4146110ca578063d3cc8d1c146110d2578063dae595e5146111ef578063df6af7d11461121d576103f4565b8063b64c4905116101ac578063c23f001f1161017b578063c23f001f14611031578063c6af43f91461105f578063c8a4ac9c1461107c578063cb10fa761461109f578063cd04ccfc146110c2576103f4565b8063b64c490514610f76578063b67d77c514610fa4578063b8beafd614610fc7578063c1a21bf314610ff5576103f4565b8063acb10351116101e8578063acb1035114610e84578063b029385014610ed6578063b04c023914610f12578063b3c2083f14610f48576103f4565b806382a57b4314610d245780639fec8e9614610e38578063a48cef4a14610e74578063a619486e14610e7c576103f4565b80635e7f22c211610314578063706eb3ab116102a7578063796a807611610276578063796a807614610c955780637ae2b5c714610cbb5780637bf1a62714610cde578063821b98f314610ce65780638261eb1b14610d1c576103f4565b8063706eb3ab14610a7e5780637420a32f14610a86578063771602f714610abc5780637895dd2114610adf576103f4565b806365b0d711116102e357806365b0d711146109a35780636d1ea3fa14610a485780636e6260fa14610a6e5780636ea6836014610a76576103f4565b80635e7f22c2146108ed5780635ec2c7bf1461092957806365054e5514610931578063657a37ad1461096d576103f4565b80632cef4dac1161038c57806347e7ef241161035b57806347e7ef24146107ff5780634bf8e7a21461082b5780634e30a66c1461087a57806359f96ae5146108b1576103f4565b80632cef4dac146107765780633069046814610780578063377758071461079d578063403fbf54146107d9576103f4565b80630c57cfba116103c85780630c57cfba146105915780630e7c0f80146107005780631006a41f1461071a57806314584a9d14610748576103f4565b8062599e65146103f957806302ffc0b01461044d57806304e80e901461050d57806306d58f2a14610531575b600080fd5b6104276004803603604081101561040f57600080fd5b50600160a060020a038135811691602001351661145f565b60408051600160a060020a03938416815291909216602082015281519081900390910190f35b6104bd6004803603602081101561046357600080fd5b81019060208101813564010000000081111561047e57600080fd5b82018360208201111561049057600080fd5b803590602001918460208302840111640100000000831117156104b257600080fd5b509092509050611488565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104f95781810151838201526020016104e1565b505050509050019250505060405180910390f35b610515611544565b60408051600160a060020a039092168252519081900360200190f35b610573600480360360a081101561054757600080fd5b50600160a060020a03813581169160208101358216916040820135169060608101359060800135611553565b60408051938452602084019290925282820152519081900360600190f35b6106a5600480360360608110156105a757600080fd5b8101906020810181356401000000008111156105c257600080fd5b8201836020820111156105d457600080fd5b803590602001918460208302840111640100000000831117156105f657600080fd5b91939092909160208101903564010000000081111561061457600080fd5b82018360208201111561062657600080fd5b8035906020019184602083028401116401000000008311171561064857600080fd5b91939092909160208101903564010000000081111561066657600080fd5b82018360208201111561067857600080fd5b8035906020019184602083028401116401000000008311171561069a57600080fd5b509092509050611580565b6040518080602001838152602001828103825284818151815260200191508051906020019060200280838360005b838110156106eb5781810151838201526020016106d3565b50505050905001935050505060405180910390f35b61070861172f565b60408051918252519081900360200190f35b6107086004803603604081101561073057600080fd5b50600160a060020a0381358116916020013516611735565b6107086004803603604081101561075e57600080fd5b50600160a060020a0381358116916020013516611752565b61077e61178d565b005b6107086004803603602081101561079657600080fd5b5035611851565b610708600480360360808110156107b357600080fd5b50600160a060020a0381358116916020810135821691604082013591606001351661186b565b61077e600480360360208110156107ef57600080fd5b5035600160a060020a0316611897565b6107086004803603604081101561081557600080fd5b50600160a060020a0381351690602001356119ba565b6108616004803603606081101561084157600080fd5b50600160a060020a03813581169160208101359091169060400135611a9c565b6040805192835260208301919091528051918290030190f35b61089d6004803603604081101561089057600080fd5b5080359060200135611c27565b604080519115158252519081900360200190f35b610861600480360360808110156108c757600080fd5b50600160a060020a03813581169160208101359091169060408101359060600135611c2e565b6107086004803603608081101561090357600080fd5b50600160a060020a03813581169160208101359091169060408101359060600135611fcb565b610515612413565b6108616004803603608081101561094757600080fd5b50600160a060020a03813581169160208101358216916040820135169060600135612422565b6105736004803603606081101561098357600080fd5b50600160a060020a038135811691602081013590911690604001356125f6565b61077e600480360360408110156109b957600080fd5b8101906020810181356401000000008111156109d457600080fd5b8201836020820111156109e657600080fd5b80359060200191846020830284011164010000000083111715610a0857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505050503515159050612623565b61089d60048036036020811015610a5e57600080fd5b5035600160a060020a0316612729565b61070861273e565b610515612744565b610515612753565b61070860048036036060811015610a9c57600080fd5b50600160a060020a03813581169160208101359091169060400135612762565b61070860048036036040811015610ad257600080fd5b50803590602001356127a7565b610bfc60048036036080811015610af557600080fd5b810190602081018135640100000000811115610b1057600080fd5b820183602082011115610b2257600080fd5b80359060200191846020830284011164010000000083111715610b4457600080fd5b919390929091602081019035640100000000811115610b6257600080fd5b820183602082011115610b7457600080fd5b80359060200191846020830284011164010000000083111715610b9657600080fd5b919390929091602081019035640100000000811115610bb457600080fd5b820183602082011115610bc657600080fd5b80359060200191846020830284011164010000000083111715610be857600080fd5b919350915035600160a060020a03166127c3565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015610c40578181015183820152602001610c28565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015610c7f578181015183820152602001610c67565b5050505090500194505050505060405180910390f35b61077e60048036036020811015610cab57600080fd5b5035600160a060020a0316612976565b61070860048036036040811015610cd157600080fd5b5080359060200135612a3b565b610515612a53565b61077e60048036036060811015610cfc57600080fd5b50600160a060020a03813581169160208101359091169060400135612a62565b610515612b37565b6106a560048036036060811015610d3a57600080fd5b810190602081018135640100000000811115610d5557600080fd5b820183602082011115610d6757600080fd5b80359060200191846020830284011164010000000083111715610d8957600080fd5b919390929091602081019035640100000000811115610da757600080fd5b820183602082011115610db957600080fd5b80359060200191846020830284011164010000000083111715610ddb57600080fd5b919390929091602081019035640100000000811115610df957600080fd5b820183602082011115610e0b57600080fd5b80359060200191846020830284011164010000000083111715610e2d57600080fd5b509092509050612b46565b61070860048036036080811015610e4e57600080fd5b50600160a060020a03813581169160208101358216916040820135916060013516612cab565b610708612cd7565b610515612cdd565b61077e600480360360e0811015610e9a57600080fd5b50600160a060020a0381358116916020810135821691604082013581169160608101358216916080820135169060a08101359060c00135612cec565b61086160048036036080811015610eec57600080fd5b50600160a060020a03813581169160208101358216916040820135169060600135612f78565b61070860048036036060811015610f2857600080fd5b50600160a060020a038135811691602081013590911690604001356132d2565b61070860048036036040811015610f5e57600080fd5b50600160a060020a03813581169160200135166132f5565b61070860048036036040811015610f8c57600080fd5b50600160a060020a0381358116916020013516613312565b61070860048036036040811015610fba57600080fd5b508035906020013561332f565b61070860048036036040811015610fdd57600080fd5b50600160a060020a038135811691602001351661334c565b6107086004803603608081101561100b57600080fd5b50600160a060020a03813581169160208101358216916040820135916060013516613369565b6107086004803603604081101561104757600080fd5b50600160a060020a0381358116916020013516613395565b61077e6004803603602081101561107557600080fd5b50356133b2565b6107086004803603604081101561109257600080fd5b5080359060200135613403565b61089d600480360360408110156110b557600080fd5b508035906020013561341f565b610515613441565b610515613450565b610bfc600480360360808110156110e857600080fd5b81019060208101813564010000000081111561110357600080fd5b82018360208201111561111557600080fd5b8035906020019184602083028401116401000000008311171561113757600080fd5b91939092909160208101903564010000000081111561115557600080fd5b82018360208201111561116757600080fd5b8035906020019184602083028401116401000000008311171561118957600080fd5b9193909290916020810190356401000000008111156111a757600080fd5b8201836020820111156111b957600080fd5b803590602001918460208302840111640100000000831117156111db57600080fd5b919350915035600160a060020a031661345f565b6107086004803603604081101561120557600080fd5b50600160a060020a03813581169160200135166135f4565b6105736004803603608081101561123357600080fd5b50600160a060020a0381358116916020810135821691604082013516906060013561362f565b61077e6004803603602081101561126f57600080fd5b50356136e9565b61089d6004803603604081101561128c57600080fd5b508035906020013561373a565b61077e600480360360c08110156112af57600080fd5b50600160a060020a03813581169160208101359091169060408101359060608101359060808101359060a0013561373f565b610861600480360360608110156112f757600080fd5b50600160a060020a03813581169160208101359091169060400135613c44565b6108616004803603602081101561132d57600080fd5b5035600160a060020a0316613c6e565b610708613e08565b6107086004803603604081101561135b57600080fd5b50600160a060020a038135169060200135613e0e565b6108616004803603602081101561138757600080fd5b5035600160a060020a0316613f49565b61077e613f91565b61077e600480360360208110156113b557600080fd5b5035600160a060020a0316614054565b610708600480360360608110156113db57600080fd5b50600160a060020a03813581169160208101359091169060400135614161565b6107086004803603604081101561141157600080fd5b50600160a060020a0381358116916020013516614184565b6108616004803603606081101561143f57600080fd5b50600160a060020a038135811691602081013590911690604001356141a1565b60008083600160a060020a031683600160a060020a03161015611480579192915b509192909150565b604080518281526020808402820101909152606090829082908280156114b8578160200160208202803883390190505b50905060005b8281101561153957600460008787848181106114d657fe5b90506020020135600160a060020a0316600160a060020a0316600160a060020a0316815260200190815260200160002060009054906101000a900460ff16828281518110151561152257fe5b9115156020928302909101909101526001016114be565b509150505b92915050565b600054600160a060020a031690565b600080600061156488888888612422565b90935091506115738785613e0e565b9050955095509592505050565b606060008061162389898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a91829185019084908082843760009201919091525061432e92505050565b9050606081604051908082528060200260200182016040528015611651578160200160208202803883390190505b5090506000805b8381101561171e576116b88c8c8381811061166f57fe5b90506020020135600160a060020a03168b8b84818110151561168d57fe5b90506020020135600160a060020a0316338b8b8681811015156116ac57fe5b90506020020135612f78565b84838151811015156116c657fe5b602090810290910101919091529485019491506117158c8c838181106116e857fe5b90506020020135600160a060020a0316848381518110151561170657fe5b90602001906020020151613e0e565b50600101611658565b509093505050965096945050505050565b60035481565b600e60209081526000928352604080842090915290825290205481565b600061175e838361145f565b600160a060020a039182166000908152600d602090815260408083209390941682529190915220549392505050565b600254600160a060020a031615156117d95760405160e560020a62461bcd02815260040180806020018281038252602b8152602001806154fd602b913960400191505060405180910390fd5b60035442101561181d5760405160e560020a62461bcd02815260040180806020018281038252603981526020018061546e6039913960400191505060405180910390fd5b600280546000805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a03841617909155169055565b60008082121561186357506000611866565b50805b919050565b601760209081526000948552604080862082529385528385208152918452828420909152825290205481565b600154600160a060020a031633146118e35760405160e560020a62461bcd02815260040180806020018281038252602a8152602001806154a7602a913960400191505060405180910390fd5b600160a060020a0381161515611943576040805160e560020a62461bcd02815260206004820181905260248201527f546865206f7261636c652061646472657373206d7573742062652076616c6964604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790556119784262278d006127a7565b60075560408051600160a060020a038316815290517f3f174cfd713408ca6e4620d1efcc241b23fc39aa7d4694bd98610d3384dc001c9181900360200190a150565b60006119c98333846001614355565b1515611a095760405160e560020a62461bcd0281526004018080602001828103825260248152602001806155986024913960400191505060405180910390fd5b600160a060020a0383166000908152601460209081526040808320338452909152812054611a3790846127a7565b600160a060020a03851660008181526014602090815260408083203384528252918290208490558151878152915193945091927f2cb77763bc1e8490c1a904905c4d74b4269919aca114464f4bb4d911e60de364929181900390910190a29392505050565b60008083600160a060020a031685600160a060020a03161415611ac457506001905080611c1f565b611ace8585611752565b831115611ada57600080fd5b600080611ae5615327565b611aed615327565b5b821515611bb3575050600160a060020a038087166000818152601060208181526040808420958d16808552958252808420888c038086529083528185208251808401845281548152600191820154818601529786529383528185209585529482528084209484529381528383208451808601909552805480865292015490840152919291118015611b83575060008260200151115b80611b9e575080516000108015611b9e575060008160200151115b15611ba857600192505b600190930192611aee565b81511580611bc357506020820151155b15611bd957602081015181519096509450611c1a565b80511580611be957506020810151155b15611bff57815160208301519096509450611c1a565b81600001518160200151019550816020015181600001510194505b505050505b935093915050565b8101101590565b600160a060020a03841660009081526014602090815260408083203384529091528120548190611c5f908490612a3b565b92506000611c6d8787611752565b905060008111611c7c57600080fd5b6000611c8888886135f4565b90506001811480611c9857504281115b15611d3b57851515611cac57819550611ced565b858214611ced5760405160e560020a62461bcd0281526004018080602001828103825260358152602001806155de6035913960400191505060405180910390fd5b600160a060020a038089166000908152601160209081526040808320938b16835292905220546c0c9f2c9cd04674edea4000000090611d2c90876127a7565b10611d3657600080fd5b611da5565b851515611d4d57816001019550611d5c565b600182018614611d5c57600080fd5b600160a060020a038089166000908152601260209081526040808320938b16835292905220546c0c9f2c9cd04674edea4000000090611d9b90876127a7565b10611da557600080fd5b6000611db38989898961449a565b600160a060020a038a166000908152601460209081526040808320338452909152902054909150611de4908761332f565b600160a060020a03808b166000818152601460209081526040808320338085529083528184209690965592825260168152828220938d1682529283528181208b8252835281812093815292909152812054611e3f90836127a7565b600160a060020a03808c166000908152601660209081526040808320938e1683529281528282208c8352815282822033835290522081905590506001831480611e8757504283115b15611ee857600160a060020a03808b166000908152601160209081526040808320938d1683529290522054611ebc81846127a7565b600160a060020a03808d166000908152601160209081526040808320938f168352929052205550611f4b565b600160a060020a03808b166000908152601260209081526040808320938d1683529290522054611f1881846127a7565b600160a060020a03808d166000908152601260209081526040808320938f1683529290522055611f498b8b87612a62565b505b6001831415611f5e57611f5e8a8a61459f565b33600160a060020a031689600160a060020a03168b600160a060020a03167f3681d6f6ad159bac260c32828859f6df545bbf841c6e70787bcf0acbc390512a8b86604051808381526020018281526020019250505060405180910390a49699969850959650505050505050565b600160a060020a03808516600090815260106020908152604080832093871683529281528282208583529052908120600101541561200857600080fd5b600061201486866135f4565b90504281111561202357600080fd5b61202d8686611752565b841461203857600080fd5b6001811161204557600080fd5b600160a060020a0380871660009081526011602090815260408083209389168352929052908120541161207757600080fd5b600160a060020a03808716600090815260136020908152604080832093891683529281528282205460148252838320338452909152919020546120bb908590612a3b565b93506c0c9f2c9cd04674edea400000006120d582866127a7565b106120df57600080fd5b600160a060020a038088166000908152601160209081526040808320938a1683529290529081205490806121148a8a8a6141a1565b9092509050600061213a858361212a8787613403565b81151561213357fe5b0403611851565b905060008189101561216357600089111561215e5761215b8b8d8c8c61449a565b90505b612169565b50965086805b60008911156123f157600160a060020a038b1660009081526014602090815260408083203384529091529020546121a0908a61332f565b601460008d600160a060020a0316600160a060020a03168152602001908152602001600020600033600160a060020a0316600160a060020a0316815260200190815260200160002081905550612272601760008e600160a060020a0316600160a060020a0316815260200190815260200160002060008d600160a060020a0316600160a060020a0316815260200190815260200160002060008c8152602001908152602001600020600033600160a060020a0316600160a060020a0316815260200190815260200160002054826127a7565b975087601760008e600160a060020a0316600160a060020a0316815260200190815260200160002060008d600160a060020a0316600160a060020a0316815260200190815260200160002060008c8152602001908152602001600020600033600160a060020a0316600160a060020a0316815260200190815260200160002081905550612347601360008e600160a060020a0316600160a060020a0316815260200190815260200160002060008d600160a060020a0316600160a060020a0316815260200190815260200160002054826127a7565b601360008e600160a060020a0316600160a060020a0316815260200190815260200160002060008d600160a060020a0316600160a060020a031681526020019081526020016000208190555033600160a060020a03168b600160a060020a03168d600160a060020a03167ff1751a362067564d5feb9ed26f1898bb14c17e1254e3724d454bc2ae80195c258d85604051808381526020018281526020019250505060405180910390a45b818910612404576124048c8c8c88614633565b50505050505050949350505050565b600154600160a060020a031681565b600080612430868685612a62565b600160a060020a03808716600090815260166020908152604080832089851684528252808320878452825280832093881683529290529081205490811161247657600080fd5b61247e615327565b50600160a060020a038088166000908152601060209081526040808320938a1683529281528282208783528152828220835180850190945280548085526001909101549184018290529181116124d357600080fd5b806124de8584613403565b8115156124e757fe5b0495506124f88a8a888a888d614958565b600160a060020a03808c1660009081526016602090815260408083208e8516845282528083208c84528252808320938d16835292905290812081905590955086111561259557600160a060020a03808a166000908152601460209081526040808320938c168352929052205461256e90876127a7565b600160a060020a03808b166000908152601460209081526040808320938d16835292905220555b60408051888152602081018890528082018790529051600160a060020a03808b16928c821692918e16917fa3ac9b53d029621ef95693b5f9b1d0b0da75029fe8530389271be02715e24c139181900360600190a45050505094509492505050565b600080600061260586856119ba565b92506126148686600087611c2e565b93979096509294509192505050565b600154600160a060020a0316331461266f5760405160e560020a62461bcd02815260040180806020018281038252602a8152602001806154a7602a913960400191505060405180910390fd5b60005b8251811015612724578160046000858481518110151561268e57fe5b602090810291909101810151600160a060020a03168252810191909152604001600020805460ff191691151591909117905582518390829081106126ce57fe5b90602001906020020151600160a060020a03167fc091bf3abd3a42f670f8ad1a6ad5b849311210403e1d85d6ac31f43114d5ca6e83604051808215151515815260200191505060405180910390a2600101612672565b505050565b60046020526000908152604090205460ff1681565b60095481565b600254600160a060020a031681565b600554600160a060020a031681565b600061276e848461145f565b600160a060020a039182166000908152600f60209081526040808320939094168252918252828120948152939052909120549392505050565b60006127b38383611c27565b15156127be57600080fd5b500190565b60608060006128668a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c91829185019084908082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525061432e92505050565b9050606081604051908082528060200260200182016040528015612894578160200160208202803883390190505b5090506060826040519080825280602002602001820160405280156128c3578160200160208202803883390190505b50905060005b83811015612964576129298d8d838181106128e057fe5b90506020020135600160a060020a03168c8c8481811015156128fe57fe5b90506020020135600160a060020a0316898c8c86818110151561291d57fe5b90506020020135612422565b848381518110151561293757fe5b906020019060200201848481518110151561294e57fe5b60209081029091010191909152526001016128c9565b50909b909a5098505050505050505050565b600154600160a060020a031633146129c25760405160e560020a62461bcd02815260040180806020018281038252602a8152602001806154a7602a913960400191505060405180910390fd5b600160a060020a0381161515612a0c5760405160e560020a62461bcd0281526004018080602001828103825260268152602001806154486026913960400191505060405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600081831015612a4c57508161153e565b508061153e565b600854600160a060020a031681565b612a6c8284611752565b81148015612aa55750600160a060020a038084166000908152601060209081526040808320938616835292815282822084835290522054155b1561272457600160a060020a038084166000818152601360209081526040808320948716808452948252808320549383526011825280832094835293905291822054909180612af58787876141a1565b90925090506000831115612b2e576000612b14858361212a8787613403565b9050801515612b2c57612b2a8888886000611fcb565b505b505b50505050505050565b600b54600160a060020a031681565b6060600080612be989898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a91829185019084908082843760009201919091525061432e92505050565b9050606081604051908082528060200260200182016040528015612c17578160200160208202803883390190505b5090506000805b8381101561171e57612c728c8c83818110612c3557fe5b90506020020135600160a060020a03168b8b848181101515612c5357fe5b90506020020135600160a060020a0316338b8b86818110151561291d57fe5b8483815181101515612c8057fe5b60209081029091010191909152948501949150612ca28a8a838181106116e857fe5b50600101612c1e565b601860209081526000948552604080862082529385528385208152918452828420909152825290205481565b60075481565b600054600160a060020a031681565b600854600160a060020a031615612d375760405160e560020a62461bcd0281526004018080602001828103825260228152602001806153c86022913960400191505060405180910390fd5b600160a060020a0386161515612d97576040805160e560020a62461bcd02815260206004820152601d60248201527f546865204f574c2061646472657373206d7573742062652076616c6964000000604482015290519081900360640190fd5b600160a060020a0387161515612df7576040805160e560020a62461bcd02815260206004820152601d60248201527f546865204652542061646472657373206d7573742062652076616c6964000000604482015290519081900360640190fd5b600160a060020a0385161515612e415760405160e560020a62461bcd0281526004018080602001828103825260248152602001806156136024913960400191505060405180910390fd5b600160a060020a0384161515612ea1576040805160e560020a62461bcd02815260206004820152601e60248201527f54686520574554482061646472657373206d7573742062652076616c69640000604482015290519081900360640190fd5b600160a060020a0383161515612f01576040805160e560020a62461bcd02815260206004820181905260248201527f546865206f7261636c652061646472657373206d7573742062652076616c6964604482015290519081900360640190fd5b600b805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a03998a1617909155600c8054821697891697909717909655600180548716958816959095179094556008805486169387169390931790925560058054909416941693909317909155600991909155600a55565b600080612f86868685612a62565b600080612f958888888861362f565b600160a060020a03808c166000908152601060209081526040808320938e1683529281528282208b8352905220600101549296509093509150151561305357600160a060020a0380891660009081526018602090815260408083208b8516845282528083208984528252808320938a168352929052205461301690856127a7565b600160a060020a03808a1660009081526018602090815260408083208c8516845282528083208a84528252808320938b1683529290522055613213565b600160a060020a0380891660008181526015602090815260408083208c86168085529083528184208b85528352818420548585526017845282852082865284528285208c86528452828520968d168552958352818420549484526010835281842090845282528083208a84529091528120546130cf8385613403565b8115156130d857fe5b0490506130e587826127a7565b96506131098a8c876130f78689613403565b81151561310057fe5b048b868e614958565b95506000601760008d600160a060020a0316600160a060020a0316815260200190815260200160002060008c600160a060020a0316600160a060020a0316815260200190815260200160002060008a815260200190815260200160002060008b600160a060020a0316600160a060020a03168152602001908152602001600020819055506000601860008d600160a060020a0316600160a060020a0316815260200190815260200160002060008c600160a060020a0316600160a060020a0316815260200190815260200160002060008a815260200190815260200160002060008b600160a060020a0316600160a060020a03168152602001908152602001600020819055505050505b600084111561327357600160a060020a038089166000908152601460209081526040808320938a168352929052205461324c90856127a7565b600160a060020a03808a166000908152601460209081526040808320938b16835292905220555b60408051868152602081018690528082018590529051600160a060020a03808916928a821692918c16917f4d1c39fd1a9c74f88b9f90c7b439b7e5dc6f26b6ff280fd497fdec5c538aaf529181900360600190a4505094509492505050565b600f60209081526000938452604080852082529284528284209052825290205481565b601260209081526000928352604080842090915290825290205481565b601160209081526000928352604080842090915290825290205481565b600061333b838361373a565b151561334657600080fd5b50900390565b601360209081526000928352604080842090915290825290205481565b601660209081526000948552604080862082529385528385208152918452828420909152825290205481565b601460209081526000928352604080842090915290825290205481565b600154600160a060020a031633146133fe5760405160e560020a62461bcd02815260040180806020018281038252602a8152602001806154a7602a913960400191505060405180910390fd5b600a55565b600061340f838361341f565b151561341a57600080fd5b500290565b600081158061343a5750828283850281151561343757fe5b04145b9392505050565b600654600160a060020a031681565b600c54600160a060020a031681565b60608060006135028a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c91829185019084908082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525061432e92505050565b9050606081604051908082528060200260200182016040528015613530578160200160208202803883390190505b50905060608260405190808252806020026020018201604052801561355f578160200160208202803883390190505b50905060005b83811015612964576135b98d8d8381811061357c57fe5b90506020020135600160a060020a03168c8c84818110151561359a57fe5b90506020020135600160a060020a0316898c8c8681811015156116ac57fe5b84838151811015156135c757fe5b90602001906020020184848151811015156135de57fe5b6020908102909101019190915252600101613565565b6000613600838361145f565b600160a060020a039182166000908152600e602090815260408083209390941682529190915220549392505050565b600080600061363e8787611752565b84111561364a57600080fd5b6136558787866141a1565b909250905081151561366a57600092506136df565b600160a060020a0380881660008181526017602090815260408083208b86168085529083528184208a85528352818420958b1680855295835281842054948452601883528184209084528252808320898452825280832094835293905291909120546136db908461212a8486613403565b9350505b9450945094915050565b600154600160a060020a031633146137355760405160e560020a62461bcd02815260040180806020018281038252602a8152602001806154a7602a913960400191505060405180910390fd5b600955565b111590565b600160a060020a03868116908616141561378d5760405160e560020a62461bcd0281526004018080602001828103825260308152602001806155286030913960400191505060405180910390fd5b8115156137ce5760405160e560020a62461bcd02815260040180806020018281038252603081526020018061566f6030913960400191505060405180910390fd5b80151561380f5760405160e560020a62461bcd0281526004018080602001828103825260328152602001806153756032913960400191505060405180910390fd5b6138198686611752565b1561386e576040805160e560020a62461bcd02815260206004820181905260248201527f54686520746f6b656e20706169722077617320616c7265616479206164646564604482015290519081900360640190fd5b670de0b6b3a764000082106138b75760405160e560020a62461bcd02815260040180806020018281038252603681526020018061533f6036913960400191505060405180910390fd5b670de0b6b3a764000081106139005760405160e560020a62461bcd0281526004018080602001828103825260388152602001806156376038913960400191505060405180910390fd5b61390a8686614aab565b600160a060020a0386166000908152601460209081526040808320338452909152902054613939908590612a3b565b600160a060020a038616600090815260146020908152604080832033845290915290205490945061396b908490612a3b565b92506c0c9f2c9cd04674edea4000000084106139bb5760405160e560020a62461bcd02815260040180806020018281038252602c81526020018061569f602c913960400191505060405180910390fd5b6c0c9f2c9cd04674edea400000008310613a095760405160e560020a62461bcd02815260040180806020018281038252602c8152602001806154d1602c913960400191505060405180910390fd5b600080600560009054906101000a9004600160a060020a0316600160a060020a031663a3ca17b26040518163ffffffff1660e060020a02815260040160206040518083038186803b158015613a5d57600080fd5b505afa158015613a71573d6000803e3d6000fd5b505050506040513d6020811015613a8757600080fd5b5051600854909150600160a060020a03908116908916811415613ab557613aae8783613403565b9250613aea565b80600160a060020a031688600160a060020a03161415613ad957613aae8683613403565b613ae7898989898587614ae7565b92505b600954831015613b2e5760405160e560020a62461bcd0281526004018080602001828103825260378152602001806153ea6037913960400191505060405180910390fd5b604080519081016040528086815260200185815250601060008b600160a060020a0316600160a060020a0316815260200190815260200160002060008a600160a060020a0316600160a060020a0316815260200190815260200160002060008081526020019081526020016000206000820151816000015560208201518160010155905050604080519081016040528085815260200186815250601060008a600160a060020a0316600160a060020a0316815260200190815260200160002060008b600160a060020a0316600160a060020a0316815260200190815260200160002060008081526020019081526020016000206000820151816000015560208201518160010155905050612b2a89898989614b7f565b60106020908152600093845260408085208252928452828420905282529020805460019091015482565b6000806000600b60009054906101000a9004600160a060020a0316600160a060020a03166318160ddd6040518163ffffffff1660e060020a02815260040160206040518083038186803b158015613cc457600080fd5b505afa158015613cd8573d6000803e3d6000fd5b505050506040513d6020811015613cee57600080fd5b5051600b54604080517f8b525d0c000000000000000000000000000000000000000000000000000000008152600160a060020a03888116600483015291519394506000939190921691638b525d0c916024808301926020929190829003018186803b158015613d5c57600080fd5b505afa158015613d70573d6000803e3d6000fd5b505050506040513d6020811015613d8657600080fd5b505190506127108102821180613d9a575081155b15613dac576001935060c89250613e01565b81816103e8021015613dc5576001935060fa9250613e01565b81816064021015613dde57600393506103e89250613e01565b8181600a021015613df757600193506101f49250613e01565b600193506103e892505b5050915091565b600a5481565b600160a060020a0382166000908152601460209081526040808320338452909152812054613e3c8382612a3b565b925060008311613e805760405160e560020a62461bcd0281526004018080602001828103825260218152602001806153a76021913960400191505060405180910390fd5b6000613e8c828561332f565b600160a060020a03861660009081526014602090815260408083203380855292528220839055919250613ec29187918790614355565b1515613f025760405160e560020a62461bcd0281526004018080602001828103825260228152602001806155bc6022913960400191505060405180910390fd5b604080518581529051600160a060020a038716917f6e2e05fb6a732995d6952d9158ca6b75f11cc6bf5a4af943aa1eb475a249440b919081900360200190a2949350505050565b60085460009081908190613f67908590600160a060020a0316611752565b600854909150613f86908590600160a060020a03166000198401611a9c565b909590945092505050565b600654600160a060020a03161515613fdd5760405160e560020a62461bcd0281526004018080602001828103825260278152602001806154216027913960400191505060405180910390fd5b60075442116140205760405160e560020a62461bcd0281526004018080602001828103825260408152602001806155586040913960400191505060405180910390fd5b600680546005805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a03841617909155169055565b600154600160a060020a031633146140a05760405160e560020a62461bcd02815260040180806020018281038252602a8152602001806154a7602a913960400191505060405180910390fd5b600160a060020a03811615156140ea5760405160e560020a62461bcd02815260040180806020018281038252602b8152602001806154fd602b913960400191505060405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03831617905561411f4262278d006127a7565b60035560408051600160a060020a038316815290517f36dceb79f427eda3edba9ac3c1d4db7a6e4d0b8637d97320847d93fa8e2f7a049181900360200190a150565b601560209081526000938452604080852082529284528284209052825290205481565b600d60209081526000928352604080842090915290825290205481565b6000806141ac615327565b50600160a060020a0380861660009081526010602090815260408083209388168352928152828220868352815290829020825180840190935280548352600101549082018190521561420957805160208201519093509150614325565b6142138686611752565b8411156142265760009250829150614325565b600080614237888860018903611a9c565b9092509050600061425261424b8a8a6135f4565b4203611851565b90506142648382620151800302611851565b95506142748161a8c00183613403565b600160a060020a03808b166000908152601360209081526040808320938d16835292905220549095506142a8908690613403565b600160a060020a03808b166000908152601160209081526040808320938d16835292905220546142d9908890613403565b11611c1a57600160a060020a03808a166000818152601360209081526040808320948d168084529482528083205493835260118252808320948352939052919091205490965094505050505b50935093915050565b8251825180821461433e57600080fd5b825181811461434c57600080fd5b50509392505050565b600081156143e757604080517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018590529051600160a060020a038716916323b872dd91606480830192600092919082900301818387803b1580156143ca57600080fd5b505af11580156143de573d6000803e3d6000fd5b50505050614463565b84600160a060020a031663a9059cbb85856040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050600060405180830381600087803b15801561444a57600080fd5b505af115801561445e573d6000803e3d6000fd5b505050505b3d801561447b57602081146144855760009150614491565b6000199150614491565b60206000803e60005191505b50949350505050565b60008060006144a833613c6e565b90925090506000816144ba8685613403565b8115156144c357fe5b0490506000811115614589576144d98882614d61565b600160a060020a03808a166000908152601560209081526040808320938c16835292815282822060018b0183529052205490915061451781836127a7565b600160a060020a03808b166000818152601560209081526040808320948e1680845294825280832060018e0184528252918290209490945580518b8152938401869052805133947f30c4d3fe752442ffa2415fd4e6398cb9e378bab963f042ce30ef4363b6ad93b692908290030190a4505b614593858261332f565b98975050505050505050565b6000806145ac8484615027565b600a5491935091508083108015918310159060009083906145ca5750815b156145d757506001614611565b82806145e05750815b156146115760006145f18888611752565b90506000614603898960018503612762565b6201517f1942011015925050505b8015614629576146248787610258615165565b612b2e565b612b2e87876151f9565b600160a060020a0380851660008181526013602090815260408083209488168084529482528083205460118352818420858552835281842054958452601083528184209484529382528083208784529091528120600101549192919061469988886135f4565b905060008511156146f0576040805180820182528581526020808201888152600160a060020a03808d16600090815260108452858120918d1681529083528481208b82529092529290209051815590516001909101555b82158061470257508062015180014210155b8061470d5750600082115b156148fa57600160a060020a038088166000908152601360209081526040808320938c1683529290522054821580156147465750600084115b15614797576040805180820182528281526020808201878152600160a060020a03808d16600090815260108452858120918f1681529083528481208c82529092529290209051815590516001909101555b600160a060020a03808a166000818152601260208181526040808420958e1680855295825280842054928252808420948452938152838320546011825284842095845294905291812082905590919082111561481657600160a060020a03808c166000908152601260209081526040808320938e168352929052908120555b600087111561484857600160a060020a03808c166000908152601360209081526040808320938e168352929052908120555b600160a060020a03808b166000908152601160209081526040808320938f1683529290529081208290558111156148a257600160a060020a03808b166000908152601260209081526040808320938f168352929052908120555b60008311156148d457600160a060020a03808b166000908152601360209081526040808320938f168352929052908120555b6148e28b8b8b878c8c615263565b6148ec8b8b614aab565b6148f68b8b61459f565b5050505b8587600160a060020a031689600160a060020a03167fb5806f8610464e96807c2b147620cc721c65309647f16cfccdf9fb7bd95152ac8888604051808381526020018281526020019250505060405180910390a45050505050505050565b600160a060020a03861660009081526004602052604081205460ff1680156149985750600160a060020a03861660009081526004602052604090205460ff165b15614aa157600854600160a060020a039081169088168114156149bd57839150614a0f565b80600160a060020a031687600160a060020a031614156149df57859150614a0f565b6000806149f08a8460018a03611a9c565b909250905080614a008784613403565b811515614a0957fe5b04935050505b6000821115614a9f57600b54604080517ff0dda65c000000000000000000000000000000000000000000000000000000008152600160a060020a038681166004830152602482018690529151919092169163f0dda65c91604480830192600092919082900301818387803b158015614a8657600080fd5b505af1158015614a9a573d6000803e3d6000fd5b505050505b505b9695505050505050565b614ab5828261145f565b600160a060020a039182166000908152600d602090815260408083209390941682529190915220805460010190555050565b600080614af48885611752565b11614afe57600080fd5b6000614b0a8785611752565b11614b1457600080fd5b600080614b2089613f49565b9092509050600080614b318a613f49565b90925090506000614b6384614b468c88613403565b811515614b4f57fe5b0483858c02811515614b5d57fe5b046127a7565b9050614b6f8188613403565b9c9b505050505050505050505050565b600160a060020a0384166000908152601460209081526040808320338452909152902054614bad908361332f565b600160a060020a0380861660009081526014602081815260408084203380865290835281852096909655938816835290815282822093825292909252902054614bf6908261332f565b600160a060020a0384166000908152601460209081526040808320338452909152812091909155614c2a858560018661449a565b90506000614c3b858760018661449a565b600160a060020a038088166000818152601160208181526040808420958c168085529582528084208990559181528183208484528152818320869055601680825282842086855282528284206001808652908352838520338087529084528486208b90559685529082528284209484529381528183209383529283528082209382529290915290812082905590915080614cd5888861145f565b600160a060020a038083166000908152600f6020908152604080832093851683529281528282208280529052204290559092509050614d178888615460615165565b86600160a060020a031688600160a060020a03167f6f4b2adffa0c3e90e47fdcd9d2c36f48b57eb3271dce519997271073dac17be960405160405180910390a35050505050505050565b6000806000614d6f85613f49565b9092509050600081614d818685613403565b811515614d8a57fe5b0490506000600560009054906101000a9004600160a060020a0316600160a060020a031663a3ca17b26040518163ffffffff1660e060020a02815260040160206040518083038186803b158015614de057600080fd5b505afa158015614df4573d6000803e3d6000fd5b505050506040513d6020811015614e0a57600080fd5b505190506000614e1a8383613403565b600c54604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523360048201523060248201529051929350600092614ec092600160a060020a03169163dd62ed3e916044808301926020929190829003018186803b158015614e8b57600080fd5b505afa158015614e9f573d6000803e3d6000fd5b505050506040513d6020811015614eb557600080fd5b505160028404612a3b565b600c54604080517f70a082310000000000000000000000000000000000000000000000000000000081523360048201529051929350614f5d92600160a060020a03909216916370a0823191602480820192602092909190829003018186803b158015614f2b57600080fd5b505afa158015614f3f573d6000803e3d6000fd5b505050506040513d6020811015614f5557600080fd5b505182612a3b565b9050600081111561501757600c54604080517f4417f4db000000000000000000000000000000000000000000000000000000008152336004820152602481018490529051600160a060020a0390921691634417f4db9160448082019260009290919082900301818387803b158015614fd457600080fd5b505af1158015614fe8573d6000803e3d6000fd5b50505050600082614ff9838b613403565b81151561500257fe5b04905061500f898261332f565b97505061501b565b8796505b50505050505092915050565b6000806000600560009054906101000a9004600160a060020a0316600160a060020a031663a3ca17b26040518163ffffffff1660e060020a02815260040160206040518083038186803b15801561507d57600080fd5b505afa158015615091573d6000803e3d6000fd5b505050506040513d60208110156150a757600080fd5b505190506000806150b787613f49565b90925090506000806150c888613f49565b600160a060020a03808c166000908152601160209081526040808320938e168352929052205491935091508390615109906151039087613403565b87613403565b81151561511257fe5b600160a060020a03808b166000908152601160209081526040808320938f16835292905220549190049750819061514d906151039085613403565b81151561515657fe5b04955050505050509250929050565b61516f838361145f565b600160a060020a038083166000818152600d6020908152604080832094861680845294825280832054848452600e83528184208685528352928190204289019081905581518181529151979a5095985094959194859493927f20017e7b1ef8e7882103f55ff346ca3135c4afe13dff1da2f01b482aece766a5929181900390910190a45050505050565b615203828261145f565b600160a060020a038083166000908152600e6020908152604080832093851683529290522054919350915060011461525f57600160a060020a038083166000908152600e60209081526040808320938516835292905220600190555b5050565b600080615274888860018903611a9c565b9150915060006152ad61529361528a8588613403565b62015180613403565b6152a86152a08786613403565b61a8c0613403565b61332f565b905060006152cd6152be8786613403565b6152c88786613403565b6127a7565b828115156152d757fe5b0490508681016152e78b8b61145f565b600160a060020a039182166000908152600f602090815260408083209390941682529182528281209b81529a905290982097909755505050505050505050565b60408051808201909152600080825260208201529056fe596f75206d75737420736574206120736d616c6c6572206e756d657261746f7220666f722074686520696e697469616c207072696365596f75206d75737420736574207468652064656e6f6d696e61746f7220666f722074686520696e697469616c20707269636554686520616d6f756e74206d7573742062652067726561746572207468616e203054686520636f6e7472616374206d75737420626520756e696e697469616c697a6564596f752073686f756c6420737572706c757320746865207468726573686f6c6420666f7220616464696e6720746f6b656e207061697273546865206e65772070726f706f73616c206d75737420626520612076616c6964206164647265735468652061756374696f6e656572206d75737420626520612076616c69642061646472657373546865206d617374657220636f6e74726163742063616e6e6f74206265207570646174656420696e20612077616974696e6720706572696f644f6e6c79207468652061756374696f6e6565722063616e206e6f6d696e6174652061206e6577206f6e65596f752073686f756c6420757365206120736d616c6c65722066756e64696e6720666f7220746f6b656e2032546865206e6577206d617374657220636f7079206d75737420626520612076616c69642061646472657373596f752063616e6e6f7420616464206120746f6b656e2070616972207573696e67207468652073616d6520746f6b656e49742773206e6f7420706f737369626c6520746f2075706461746520746865206f7261636c6520647572696e67207468652077616974696e6720706572696f64546865206465706f736974207472616e73616374696f6e206d7573742073756363656564546865207769746864726177207472616e73666572206d757374207375636365656441756374696f6e20696e6465782073686f756c6420626520657175616c20746f206c61746573742061756374696f6e20696e6465785468652061756374696f6e6565722061646472657373206d7573742062652076616c6964596f75206d75737420736574206120736d616c6c65722064656e6f6d696e61746f7220666f722074686520696e697469616c207072696365596f75206d7573742073657420746865206e756d657261746f7220666f722074686520696e697469616c207072696365596f752073686f756c6420757365206120736d616c6c65722066756e64696e6720666f7220746f6b656e2031a165627a7a723058207c2888b04e675c63e2fcd95ada8c4645e1b6e490b95f8c3ecdcf29cc9c08faca0029
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103f45760003560e060020a9004806382a57b4311610219578063cd94a2a411610129578063edd0b5cb116100bc578063f4279d1f1161008b578063f4279d1f14611397578063f625ee281461139f578063f79710fd146113c5578063fac7abe3146113fb578063fdab1b7b14611429576103f4565b8063edd0b5cb14611317578063ee93114c1461133d578063f3fef3a314611345578063f41d97fc14611371576103f4565b8063e1c95bb9116100f8578063e1c95bb914611259578063e31c71c414611276578063e9f8cd7014611299578063ebcc0de1146112e1576103f4565b8063cd94a2a4146110ca578063d3cc8d1c146110d2578063dae595e5146111ef578063df6af7d11461121d576103f4565b8063b64c4905116101ac578063c23f001f1161017b578063c23f001f14611031578063c6af43f91461105f578063c8a4ac9c1461107c578063cb10fa761461109f578063cd04ccfc146110c2576103f4565b8063b64c490514610f76578063b67d77c514610fa4578063b8beafd614610fc7578063c1a21bf314610ff5576103f4565b8063acb10351116101e8578063acb1035114610e84578063b029385014610ed6578063b04c023914610f12578063b3c2083f14610f48576103f4565b806382a57b4314610d245780639fec8e9614610e38578063a48cef4a14610e74578063a619486e14610e7c576103f4565b80635e7f22c211610314578063706eb3ab116102a7578063796a807611610276578063796a807614610c955780637ae2b5c714610cbb5780637bf1a62714610cde578063821b98f314610ce65780638261eb1b14610d1c576103f4565b8063706eb3ab14610a7e5780637420a32f14610a86578063771602f714610abc5780637895dd2114610adf576103f4565b806365b0d711116102e357806365b0d711146109a35780636d1ea3fa14610a485780636e6260fa14610a6e5780636ea6836014610a76576103f4565b80635e7f22c2146108ed5780635ec2c7bf1461092957806365054e5514610931578063657a37ad1461096d576103f4565b80632cef4dac1161038c57806347e7ef241161035b57806347e7ef24146107ff5780634bf8e7a21461082b5780634e30a66c1461087a57806359f96ae5146108b1576103f4565b80632cef4dac146107765780633069046814610780578063377758071461079d578063403fbf54146107d9576103f4565b80630c57cfba116103c85780630c57cfba146105915780630e7c0f80146107005780631006a41f1461071a57806314584a9d14610748576103f4565b8062599e65146103f957806302ffc0b01461044d57806304e80e901461050d57806306d58f2a14610531575b600080fd5b6104276004803603604081101561040f57600080fd5b50600160a060020a038135811691602001351661145f565b60408051600160a060020a03938416815291909216602082015281519081900390910190f35b6104bd6004803603602081101561046357600080fd5b81019060208101813564010000000081111561047e57600080fd5b82018360208201111561049057600080fd5b803590602001918460208302840111640100000000831117156104b257600080fd5b509092509050611488565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104f95781810151838201526020016104e1565b505050509050019250505060405180910390f35b610515611544565b60408051600160a060020a039092168252519081900360200190f35b610573600480360360a081101561054757600080fd5b50600160a060020a03813581169160208101358216916040820135169060608101359060800135611553565b60408051938452602084019290925282820152519081900360600190f35b6106a5600480360360608110156105a757600080fd5b8101906020810181356401000000008111156105c257600080fd5b8201836020820111156105d457600080fd5b803590602001918460208302840111640100000000831117156105f657600080fd5b91939092909160208101903564010000000081111561061457600080fd5b82018360208201111561062657600080fd5b8035906020019184602083028401116401000000008311171561064857600080fd5b91939092909160208101903564010000000081111561066657600080fd5b82018360208201111561067857600080fd5b8035906020019184602083028401116401000000008311171561069a57600080fd5b509092509050611580565b6040518080602001838152602001828103825284818151815260200191508051906020019060200280838360005b838110156106eb5781810151838201526020016106d3565b50505050905001935050505060405180910390f35b61070861172f565b60408051918252519081900360200190f35b6107086004803603604081101561073057600080fd5b50600160a060020a0381358116916020013516611735565b6107086004803603604081101561075e57600080fd5b50600160a060020a0381358116916020013516611752565b61077e61178d565b005b6107086004803603602081101561079657600080fd5b5035611851565b610708600480360360808110156107b357600080fd5b50600160a060020a0381358116916020810135821691604082013591606001351661186b565b61077e600480360360208110156107ef57600080fd5b5035600160a060020a0316611897565b6107086004803603604081101561081557600080fd5b50600160a060020a0381351690602001356119ba565b6108616004803603606081101561084157600080fd5b50600160a060020a03813581169160208101359091169060400135611a9c565b6040805192835260208301919091528051918290030190f35b61089d6004803603604081101561089057600080fd5b5080359060200135611c27565b604080519115158252519081900360200190f35b610861600480360360808110156108c757600080fd5b50600160a060020a03813581169160208101359091169060408101359060600135611c2e565b6107086004803603608081101561090357600080fd5b50600160a060020a03813581169160208101359091169060408101359060600135611fcb565b610515612413565b6108616004803603608081101561094757600080fd5b50600160a060020a03813581169160208101358216916040820135169060600135612422565b6105736004803603606081101561098357600080fd5b50600160a060020a038135811691602081013590911690604001356125f6565b61077e600480360360408110156109b957600080fd5b8101906020810181356401000000008111156109d457600080fd5b8201836020820111156109e657600080fd5b80359060200191846020830284011164010000000083111715610a0857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505050503515159050612623565b61089d60048036036020811015610a5e57600080fd5b5035600160a060020a0316612729565b61070861273e565b610515612744565b610515612753565b61070860048036036060811015610a9c57600080fd5b50600160a060020a03813581169160208101359091169060400135612762565b61070860048036036040811015610ad257600080fd5b50803590602001356127a7565b610bfc60048036036080811015610af557600080fd5b810190602081018135640100000000811115610b1057600080fd5b820183602082011115610b2257600080fd5b80359060200191846020830284011164010000000083111715610b4457600080fd5b919390929091602081019035640100000000811115610b6257600080fd5b820183602082011115610b7457600080fd5b80359060200191846020830284011164010000000083111715610b9657600080fd5b919390929091602081019035640100000000811115610bb457600080fd5b820183602082011115610bc657600080fd5b80359060200191846020830284011164010000000083111715610be857600080fd5b919350915035600160a060020a03166127c3565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015610c40578181015183820152602001610c28565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015610c7f578181015183820152602001610c67565b5050505090500194505050505060405180910390f35b61077e60048036036020811015610cab57600080fd5b5035600160a060020a0316612976565b61070860048036036040811015610cd157600080fd5b5080359060200135612a3b565b610515612a53565b61077e60048036036060811015610cfc57600080fd5b50600160a060020a03813581169160208101359091169060400135612a62565b610515612b37565b6106a560048036036060811015610d3a57600080fd5b810190602081018135640100000000811115610d5557600080fd5b820183602082011115610d6757600080fd5b80359060200191846020830284011164010000000083111715610d8957600080fd5b919390929091602081019035640100000000811115610da757600080fd5b820183602082011115610db957600080fd5b80359060200191846020830284011164010000000083111715610ddb57600080fd5b919390929091602081019035640100000000811115610df957600080fd5b820183602082011115610e0b57600080fd5b80359060200191846020830284011164010000000083111715610e2d57600080fd5b509092509050612b46565b61070860048036036080811015610e4e57600080fd5b50600160a060020a03813581169160208101358216916040820135916060013516612cab565b610708612cd7565b610515612cdd565b61077e600480360360e0811015610e9a57600080fd5b50600160a060020a0381358116916020810135821691604082013581169160608101358216916080820135169060a08101359060c00135612cec565b61086160048036036080811015610eec57600080fd5b50600160a060020a03813581169160208101358216916040820135169060600135612f78565b61070860048036036060811015610f2857600080fd5b50600160a060020a038135811691602081013590911690604001356132d2565b61070860048036036040811015610f5e57600080fd5b50600160a060020a03813581169160200135166132f5565b61070860048036036040811015610f8c57600080fd5b50600160a060020a0381358116916020013516613312565b61070860048036036040811015610fba57600080fd5b508035906020013561332f565b61070860048036036040811015610fdd57600080fd5b50600160a060020a038135811691602001351661334c565b6107086004803603608081101561100b57600080fd5b50600160a060020a03813581169160208101358216916040820135916060013516613369565b6107086004803603604081101561104757600080fd5b50600160a060020a0381358116916020013516613395565b61077e6004803603602081101561107557600080fd5b50356133b2565b6107086004803603604081101561109257600080fd5b5080359060200135613403565b61089d600480360360408110156110b557600080fd5b508035906020013561341f565b610515613441565b610515613450565b610bfc600480360360808110156110e857600080fd5b81019060208101813564010000000081111561110357600080fd5b82018360208201111561111557600080fd5b8035906020019184602083028401116401000000008311171561113757600080fd5b91939092909160208101903564010000000081111561115557600080fd5b82018360208201111561116757600080fd5b8035906020019184602083028401116401000000008311171561118957600080fd5b9193909290916020810190356401000000008111156111a757600080fd5b8201836020820111156111b957600080fd5b803590602001918460208302840111640100000000831117156111db57600080fd5b919350915035600160a060020a031661345f565b6107086004803603604081101561120557600080fd5b50600160a060020a03813581169160200135166135f4565b6105736004803603608081101561123357600080fd5b50600160a060020a0381358116916020810135821691604082013516906060013561362f565b61077e6004803603602081101561126f57600080fd5b50356136e9565b61089d6004803603604081101561128c57600080fd5b508035906020013561373a565b61077e600480360360c08110156112af57600080fd5b50600160a060020a03813581169160208101359091169060408101359060608101359060808101359060a0013561373f565b610861600480360360608110156112f757600080fd5b50600160a060020a03813581169160208101359091169060400135613c44565b6108616004803603602081101561132d57600080fd5b5035600160a060020a0316613c6e565b610708613e08565b6107086004803603604081101561135b57600080fd5b50600160a060020a038135169060200135613e0e565b6108616004803603602081101561138757600080fd5b5035600160a060020a0316613f49565b61077e613f91565b61077e600480360360208110156113b557600080fd5b5035600160a060020a0316614054565b610708600480360360608110156113db57600080fd5b50600160a060020a03813581169160208101359091169060400135614161565b6107086004803603604081101561141157600080fd5b50600160a060020a0381358116916020013516614184565b6108616004803603606081101561143f57600080fd5b50600160a060020a038135811691602081013590911690604001356141a1565b60008083600160a060020a031683600160a060020a03161015611480579192915b509192909150565b604080518281526020808402820101909152606090829082908280156114b8578160200160208202803883390190505b50905060005b8281101561153957600460008787848181106114d657fe5b90506020020135600160a060020a0316600160a060020a0316600160a060020a0316815260200190815260200160002060009054906101000a900460ff16828281518110151561152257fe5b9115156020928302909101909101526001016114be565b509150505b92915050565b600054600160a060020a031690565b600080600061156488888888612422565b90935091506115738785613e0e565b9050955095509592505050565b606060008061162389898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a91829185019084908082843760009201919091525061432e92505050565b9050606081604051908082528060200260200182016040528015611651578160200160208202803883390190505b5090506000805b8381101561171e576116b88c8c8381811061166f57fe5b90506020020135600160a060020a03168b8b84818110151561168d57fe5b90506020020135600160a060020a0316338b8b8681811015156116ac57fe5b90506020020135612f78565b84838151811015156116c657fe5b602090810290910101919091529485019491506117158c8c838181106116e857fe5b90506020020135600160a060020a0316848381518110151561170657fe5b90602001906020020151613e0e565b50600101611658565b509093505050965096945050505050565b60035481565b600e60209081526000928352604080842090915290825290205481565b600061175e838361145f565b600160a060020a039182166000908152600d602090815260408083209390941682529190915220549392505050565b600254600160a060020a031615156117d95760405160e560020a62461bcd02815260040180806020018281038252602b8152602001806154fd602b913960400191505060405180910390fd5b60035442101561181d5760405160e560020a62461bcd02815260040180806020018281038252603981526020018061546e6039913960400191505060405180910390fd5b600280546000805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a03841617909155169055565b60008082121561186357506000611866565b50805b919050565b601760209081526000948552604080862082529385528385208152918452828420909152825290205481565b600154600160a060020a031633146118e35760405160e560020a62461bcd02815260040180806020018281038252602a8152602001806154a7602a913960400191505060405180910390fd5b600160a060020a0381161515611943576040805160e560020a62461bcd02815260206004820181905260248201527f546865206f7261636c652061646472657373206d7573742062652076616c6964604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790556119784262278d006127a7565b60075560408051600160a060020a038316815290517f3f174cfd713408ca6e4620d1efcc241b23fc39aa7d4694bd98610d3384dc001c9181900360200190a150565b60006119c98333846001614355565b1515611a095760405160e560020a62461bcd0281526004018080602001828103825260248152602001806155986024913960400191505060405180910390fd5b600160a060020a0383166000908152601460209081526040808320338452909152812054611a3790846127a7565b600160a060020a03851660008181526014602090815260408083203384528252918290208490558151878152915193945091927f2cb77763bc1e8490c1a904905c4d74b4269919aca114464f4bb4d911e60de364929181900390910190a29392505050565b60008083600160a060020a031685600160a060020a03161415611ac457506001905080611c1f565b611ace8585611752565b831115611ada57600080fd5b600080611ae5615327565b611aed615327565b5b821515611bb3575050600160a060020a038087166000818152601060208181526040808420958d16808552958252808420888c038086529083528185208251808401845281548152600191820154818601529786529383528185209585529482528084209484529381528383208451808601909552805480865292015490840152919291118015611b83575060008260200151115b80611b9e575080516000108015611b9e575060008160200151115b15611ba857600192505b600190930192611aee565b81511580611bc357506020820151155b15611bd957602081015181519096509450611c1a565b80511580611be957506020810151155b15611bff57815160208301519096509450611c1a565b81600001518160200151019550816020015181600001510194505b505050505b935093915050565b8101101590565b600160a060020a03841660009081526014602090815260408083203384529091528120548190611c5f908490612a3b565b92506000611c6d8787611752565b905060008111611c7c57600080fd5b6000611c8888886135f4565b90506001811480611c9857504281115b15611d3b57851515611cac57819550611ced565b858214611ced5760405160e560020a62461bcd0281526004018080602001828103825260358152602001806155de6035913960400191505060405180910390fd5b600160a060020a038089166000908152601160209081526040808320938b16835292905220546c0c9f2c9cd04674edea4000000090611d2c90876127a7565b10611d3657600080fd5b611da5565b851515611d4d57816001019550611d5c565b600182018614611d5c57600080fd5b600160a060020a038089166000908152601260209081526040808320938b16835292905220546c0c9f2c9cd04674edea4000000090611d9b90876127a7565b10611da557600080fd5b6000611db38989898961449a565b600160a060020a038a166000908152601460209081526040808320338452909152902054909150611de4908761332f565b600160a060020a03808b166000818152601460209081526040808320338085529083528184209690965592825260168152828220938d1682529283528181208b8252835281812093815292909152812054611e3f90836127a7565b600160a060020a03808c166000908152601660209081526040808320938e1683529281528282208c8352815282822033835290522081905590506001831480611e8757504283115b15611ee857600160a060020a03808b166000908152601160209081526040808320938d1683529290522054611ebc81846127a7565b600160a060020a03808d166000908152601160209081526040808320938f168352929052205550611f4b565b600160a060020a03808b166000908152601260209081526040808320938d1683529290522054611f1881846127a7565b600160a060020a03808d166000908152601260209081526040808320938f1683529290522055611f498b8b87612a62565b505b6001831415611f5e57611f5e8a8a61459f565b33600160a060020a031689600160a060020a03168b600160a060020a03167f3681d6f6ad159bac260c32828859f6df545bbf841c6e70787bcf0acbc390512a8b86604051808381526020018281526020019250505060405180910390a49699969850959650505050505050565b600160a060020a03808516600090815260106020908152604080832093871683529281528282208583529052908120600101541561200857600080fd5b600061201486866135f4565b90504281111561202357600080fd5b61202d8686611752565b841461203857600080fd5b6001811161204557600080fd5b600160a060020a0380871660009081526011602090815260408083209389168352929052908120541161207757600080fd5b600160a060020a03808716600090815260136020908152604080832093891683529281528282205460148252838320338452909152919020546120bb908590612a3b565b93506c0c9f2c9cd04674edea400000006120d582866127a7565b106120df57600080fd5b600160a060020a038088166000908152601160209081526040808320938a1683529290529081205490806121148a8a8a6141a1565b9092509050600061213a858361212a8787613403565b81151561213357fe5b0403611851565b905060008189101561216357600089111561215e5761215b8b8d8c8c61449a565b90505b612169565b50965086805b60008911156123f157600160a060020a038b1660009081526014602090815260408083203384529091529020546121a0908a61332f565b601460008d600160a060020a0316600160a060020a03168152602001908152602001600020600033600160a060020a0316600160a060020a0316815260200190815260200160002081905550612272601760008e600160a060020a0316600160a060020a0316815260200190815260200160002060008d600160a060020a0316600160a060020a0316815260200190815260200160002060008c8152602001908152602001600020600033600160a060020a0316600160a060020a0316815260200190815260200160002054826127a7565b975087601760008e600160a060020a0316600160a060020a0316815260200190815260200160002060008d600160a060020a0316600160a060020a0316815260200190815260200160002060008c8152602001908152602001600020600033600160a060020a0316600160a060020a0316815260200190815260200160002081905550612347601360008e600160a060020a0316600160a060020a0316815260200190815260200160002060008d600160a060020a0316600160a060020a0316815260200190815260200160002054826127a7565b601360008e600160a060020a0316600160a060020a0316815260200190815260200160002060008d600160a060020a0316600160a060020a031681526020019081526020016000208190555033600160a060020a03168b600160a060020a03168d600160a060020a03167ff1751a362067564d5feb9ed26f1898bb14c17e1254e3724d454bc2ae80195c258d85604051808381526020018281526020019250505060405180910390a45b818910612404576124048c8c8c88614633565b50505050505050949350505050565b600154600160a060020a031681565b600080612430868685612a62565b600160a060020a03808716600090815260166020908152604080832089851684528252808320878452825280832093881683529290529081205490811161247657600080fd5b61247e615327565b50600160a060020a038088166000908152601060209081526040808320938a1683529281528282208783528152828220835180850190945280548085526001909101549184018290529181116124d357600080fd5b806124de8584613403565b8115156124e757fe5b0495506124f88a8a888a888d614958565b600160a060020a03808c1660009081526016602090815260408083208e8516845282528083208c84528252808320938d16835292905290812081905590955086111561259557600160a060020a03808a166000908152601460209081526040808320938c168352929052205461256e90876127a7565b600160a060020a03808b166000908152601460209081526040808320938d16835292905220555b60408051888152602081018890528082018790529051600160a060020a03808b16928c821692918e16917fa3ac9b53d029621ef95693b5f9b1d0b0da75029fe8530389271be02715e24c139181900360600190a45050505094509492505050565b600080600061260586856119ba565b92506126148686600087611c2e565b93979096509294509192505050565b600154600160a060020a0316331461266f5760405160e560020a62461bcd02815260040180806020018281038252602a8152602001806154a7602a913960400191505060405180910390fd5b60005b8251811015612724578160046000858481518110151561268e57fe5b602090810291909101810151600160a060020a03168252810191909152604001600020805460ff191691151591909117905582518390829081106126ce57fe5b90602001906020020151600160a060020a03167fc091bf3abd3a42f670f8ad1a6ad5b849311210403e1d85d6ac31f43114d5ca6e83604051808215151515815260200191505060405180910390a2600101612672565b505050565b60046020526000908152604090205460ff1681565b60095481565b600254600160a060020a031681565b600554600160a060020a031681565b600061276e848461145f565b600160a060020a039182166000908152600f60209081526040808320939094168252918252828120948152939052909120549392505050565b60006127b38383611c27565b15156127be57600080fd5b500190565b60608060006128668a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c91829185019084908082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525061432e92505050565b9050606081604051908082528060200260200182016040528015612894578160200160208202803883390190505b5090506060826040519080825280602002602001820160405280156128c3578160200160208202803883390190505b50905060005b83811015612964576129298d8d838181106128e057fe5b90506020020135600160a060020a03168c8c8481811015156128fe57fe5b90506020020135600160a060020a0316898c8c86818110151561291d57fe5b90506020020135612422565b848381518110151561293757fe5b906020019060200201848481518110151561294e57fe5b60209081029091010191909152526001016128c9565b50909b909a5098505050505050505050565b600154600160a060020a031633146129c25760405160e560020a62461bcd02815260040180806020018281038252602a8152602001806154a7602a913960400191505060405180910390fd5b600160a060020a0381161515612a0c5760405160e560020a62461bcd0281526004018080602001828103825260268152602001806154486026913960400191505060405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600081831015612a4c57508161153e565b508061153e565b600854600160a060020a031681565b612a6c8284611752565b81148015612aa55750600160a060020a038084166000908152601060209081526040808320938616835292815282822084835290522054155b1561272457600160a060020a038084166000818152601360209081526040808320948716808452948252808320549383526011825280832094835293905291822054909180612af58787876141a1565b90925090506000831115612b2e576000612b14858361212a8787613403565b9050801515612b2c57612b2a8888886000611fcb565b505b505b50505050505050565b600b54600160a060020a031681565b6060600080612be989898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a91829185019084908082843760009201919091525061432e92505050565b9050606081604051908082528060200260200182016040528015612c17578160200160208202803883390190505b5090506000805b8381101561171e57612c728c8c83818110612c3557fe5b90506020020135600160a060020a03168b8b848181101515612c5357fe5b90506020020135600160a060020a0316338b8b86818110151561291d57fe5b8483815181101515612c8057fe5b60209081029091010191909152948501949150612ca28a8a838181106116e857fe5b50600101612c1e565b601860209081526000948552604080862082529385528385208152918452828420909152825290205481565b60075481565b600054600160a060020a031681565b600854600160a060020a031615612d375760405160e560020a62461bcd0281526004018080602001828103825260228152602001806153c86022913960400191505060405180910390fd5b600160a060020a0386161515612d97576040805160e560020a62461bcd02815260206004820152601d60248201527f546865204f574c2061646472657373206d7573742062652076616c6964000000604482015290519081900360640190fd5b600160a060020a0387161515612df7576040805160e560020a62461bcd02815260206004820152601d60248201527f546865204652542061646472657373206d7573742062652076616c6964000000604482015290519081900360640190fd5b600160a060020a0385161515612e415760405160e560020a62461bcd0281526004018080602001828103825260248152602001806156136024913960400191505060405180910390fd5b600160a060020a0384161515612ea1576040805160e560020a62461bcd02815260206004820152601e60248201527f54686520574554482061646472657373206d7573742062652076616c69640000604482015290519081900360640190fd5b600160a060020a0383161515612f01576040805160e560020a62461bcd02815260206004820181905260248201527f546865206f7261636c652061646472657373206d7573742062652076616c6964604482015290519081900360640190fd5b600b805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a03998a1617909155600c8054821697891697909717909655600180548716958816959095179094556008805486169387169390931790925560058054909416941693909317909155600991909155600a55565b600080612f86868685612a62565b600080612f958888888861362f565b600160a060020a03808c166000908152601060209081526040808320938e1683529281528282208b8352905220600101549296509093509150151561305357600160a060020a0380891660009081526018602090815260408083208b8516845282528083208984528252808320938a168352929052205461301690856127a7565b600160a060020a03808a1660009081526018602090815260408083208c8516845282528083208a84528252808320938b1683529290522055613213565b600160a060020a0380891660008181526015602090815260408083208c86168085529083528184208b85528352818420548585526017845282852082865284528285208c86528452828520968d168552958352818420549484526010835281842090845282528083208a84529091528120546130cf8385613403565b8115156130d857fe5b0490506130e587826127a7565b96506131098a8c876130f78689613403565b81151561310057fe5b048b868e614958565b95506000601760008d600160a060020a0316600160a060020a0316815260200190815260200160002060008c600160a060020a0316600160a060020a0316815260200190815260200160002060008a815260200190815260200160002060008b600160a060020a0316600160a060020a03168152602001908152602001600020819055506000601860008d600160a060020a0316600160a060020a0316815260200190815260200160002060008c600160a060020a0316600160a060020a0316815260200190815260200160002060008a815260200190815260200160002060008b600160a060020a0316600160a060020a03168152602001908152602001600020819055505050505b600084111561327357600160a060020a038089166000908152601460209081526040808320938a168352929052205461324c90856127a7565b600160a060020a03808a166000908152601460209081526040808320938b16835292905220555b60408051868152602081018690528082018590529051600160a060020a03808916928a821692918c16917f4d1c39fd1a9c74f88b9f90c7b439b7e5dc6f26b6ff280fd497fdec5c538aaf529181900360600190a4505094509492505050565b600f60209081526000938452604080852082529284528284209052825290205481565b601260209081526000928352604080842090915290825290205481565b601160209081526000928352604080842090915290825290205481565b600061333b838361373a565b151561334657600080fd5b50900390565b601360209081526000928352604080842090915290825290205481565b601660209081526000948552604080862082529385528385208152918452828420909152825290205481565b601460209081526000928352604080842090915290825290205481565b600154600160a060020a031633146133fe5760405160e560020a62461bcd02815260040180806020018281038252602a8152602001806154a7602a913960400191505060405180910390fd5b600a55565b600061340f838361341f565b151561341a57600080fd5b500290565b600081158061343a5750828283850281151561343757fe5b04145b9392505050565b600654600160a060020a031681565b600c54600160a060020a031681565b60608060006135028a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c91829185019084908082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525061432e92505050565b9050606081604051908082528060200260200182016040528015613530578160200160208202803883390190505b50905060608260405190808252806020026020018201604052801561355f578160200160208202803883390190505b50905060005b83811015612964576135b98d8d8381811061357c57fe5b90506020020135600160a060020a03168c8c84818110151561359a57fe5b90506020020135600160a060020a0316898c8c8681811015156116ac57fe5b84838151811015156135c757fe5b90602001906020020184848151811015156135de57fe5b6020908102909101019190915252600101613565565b6000613600838361145f565b600160a060020a039182166000908152600e602090815260408083209390941682529190915220549392505050565b600080600061363e8787611752565b84111561364a57600080fd5b6136558787866141a1565b909250905081151561366a57600092506136df565b600160a060020a0380881660008181526017602090815260408083208b86168085529083528184208a85528352818420958b1680855295835281842054948452601883528184209084528252808320898452825280832094835293905291909120546136db908461212a8486613403565b9350505b9450945094915050565b600154600160a060020a031633146137355760405160e560020a62461bcd02815260040180806020018281038252602a8152602001806154a7602a913960400191505060405180910390fd5b600955565b111590565b600160a060020a03868116908616141561378d5760405160e560020a62461bcd0281526004018080602001828103825260308152602001806155286030913960400191505060405180910390fd5b8115156137ce5760405160e560020a62461bcd02815260040180806020018281038252603081526020018061566f6030913960400191505060405180910390fd5b80151561380f5760405160e560020a62461bcd0281526004018080602001828103825260328152602001806153756032913960400191505060405180910390fd5b6138198686611752565b1561386e576040805160e560020a62461bcd02815260206004820181905260248201527f54686520746f6b656e20706169722077617320616c7265616479206164646564604482015290519081900360640190fd5b670de0b6b3a764000082106138b75760405160e560020a62461bcd02815260040180806020018281038252603681526020018061533f6036913960400191505060405180910390fd5b670de0b6b3a764000081106139005760405160e560020a62461bcd0281526004018080602001828103825260388152602001806156376038913960400191505060405180910390fd5b61390a8686614aab565b600160a060020a0386166000908152601460209081526040808320338452909152902054613939908590612a3b565b600160a060020a038616600090815260146020908152604080832033845290915290205490945061396b908490612a3b565b92506c0c9f2c9cd04674edea4000000084106139bb5760405160e560020a62461bcd02815260040180806020018281038252602c81526020018061569f602c913960400191505060405180910390fd5b6c0c9f2c9cd04674edea400000008310613a095760405160e560020a62461bcd02815260040180806020018281038252602c8152602001806154d1602c913960400191505060405180910390fd5b600080600560009054906101000a9004600160a060020a0316600160a060020a031663a3ca17b26040518163ffffffff1660e060020a02815260040160206040518083038186803b158015613a5d57600080fd5b505afa158015613a71573d6000803e3d6000fd5b505050506040513d6020811015613a8757600080fd5b5051600854909150600160a060020a03908116908916811415613ab557613aae8783613403565b9250613aea565b80600160a060020a031688600160a060020a03161415613ad957613aae8683613403565b613ae7898989898587614ae7565b92505b600954831015613b2e5760405160e560020a62461bcd0281526004018080602001828103825260378152602001806153ea6037913960400191505060405180910390fd5b604080519081016040528086815260200185815250601060008b600160a060020a0316600160a060020a0316815260200190815260200160002060008a600160a060020a0316600160a060020a0316815260200190815260200160002060008081526020019081526020016000206000820151816000015560208201518160010155905050604080519081016040528085815260200186815250601060008a600160a060020a0316600160a060020a0316815260200190815260200160002060008b600160a060020a0316600160a060020a0316815260200190815260200160002060008081526020019081526020016000206000820151816000015560208201518160010155905050612b2a89898989614b7f565b60106020908152600093845260408085208252928452828420905282529020805460019091015482565b6000806000600b60009054906101000a9004600160a060020a0316600160a060020a03166318160ddd6040518163ffffffff1660e060020a02815260040160206040518083038186803b158015613cc457600080fd5b505afa158015613cd8573d6000803e3d6000fd5b505050506040513d6020811015613cee57600080fd5b5051600b54604080517f8b525d0c000000000000000000000000000000000000000000000000000000008152600160a060020a03888116600483015291519394506000939190921691638b525d0c916024808301926020929190829003018186803b158015613d5c57600080fd5b505afa158015613d70573d6000803e3d6000fd5b505050506040513d6020811015613d8657600080fd5b505190506127108102821180613d9a575081155b15613dac576001935060c89250613e01565b81816103e8021015613dc5576001935060fa9250613e01565b81816064021015613dde57600393506103e89250613e01565b8181600a021015613df757600193506101f49250613e01565b600193506103e892505b5050915091565b600a5481565b600160a060020a0382166000908152601460209081526040808320338452909152812054613e3c8382612a3b565b925060008311613e805760405160e560020a62461bcd0281526004018080602001828103825260218152602001806153a76021913960400191505060405180910390fd5b6000613e8c828561332f565b600160a060020a03861660009081526014602090815260408083203380855292528220839055919250613ec29187918790614355565b1515613f025760405160e560020a62461bcd0281526004018080602001828103825260228152602001806155bc6022913960400191505060405180910390fd5b604080518581529051600160a060020a038716917f6e2e05fb6a732995d6952d9158ca6b75f11cc6bf5a4af943aa1eb475a249440b919081900360200190a2949350505050565b60085460009081908190613f67908590600160a060020a0316611752565b600854909150613f86908590600160a060020a03166000198401611a9c565b909590945092505050565b600654600160a060020a03161515613fdd5760405160e560020a62461bcd0281526004018080602001828103825260278152602001806154216027913960400191505060405180910390fd5b60075442116140205760405160e560020a62461bcd0281526004018080602001828103825260408152602001806155586040913960400191505060405180910390fd5b600680546005805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a03841617909155169055565b600154600160a060020a031633146140a05760405160e560020a62461bcd02815260040180806020018281038252602a8152602001806154a7602a913960400191505060405180910390fd5b600160a060020a03811615156140ea5760405160e560020a62461bcd02815260040180806020018281038252602b8152602001806154fd602b913960400191505060405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03831617905561411f4262278d006127a7565b60035560408051600160a060020a038316815290517f36dceb79f427eda3edba9ac3c1d4db7a6e4d0b8637d97320847d93fa8e2f7a049181900360200190a150565b601560209081526000938452604080852082529284528284209052825290205481565b600d60209081526000928352604080842090915290825290205481565b6000806141ac615327565b50600160a060020a0380861660009081526010602090815260408083209388168352928152828220868352815290829020825180840190935280548352600101549082018190521561420957805160208201519093509150614325565b6142138686611752565b8411156142265760009250829150614325565b600080614237888860018903611a9c565b9092509050600061425261424b8a8a6135f4565b4203611851565b90506142648382620151800302611851565b95506142748161a8c00183613403565b600160a060020a03808b166000908152601360209081526040808320938d16835292905220549095506142a8908690613403565b600160a060020a03808b166000908152601160209081526040808320938d16835292905220546142d9908890613403565b11611c1a57600160a060020a03808a166000818152601360209081526040808320948d168084529482528083205493835260118252808320948352939052919091205490965094505050505b50935093915050565b8251825180821461433e57600080fd5b825181811461434c57600080fd5b50509392505050565b600081156143e757604080517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018590529051600160a060020a038716916323b872dd91606480830192600092919082900301818387803b1580156143ca57600080fd5b505af11580156143de573d6000803e3d6000fd5b50505050614463565b84600160a060020a031663a9059cbb85856040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050600060405180830381600087803b15801561444a57600080fd5b505af115801561445e573d6000803e3d6000fd5b505050505b3d801561447b57602081146144855760009150614491565b6000199150614491565b60206000803e60005191505b50949350505050565b60008060006144a833613c6e565b90925090506000816144ba8685613403565b8115156144c357fe5b0490506000811115614589576144d98882614d61565b600160a060020a03808a166000908152601560209081526040808320938c16835292815282822060018b0183529052205490915061451781836127a7565b600160a060020a03808b166000818152601560209081526040808320948e1680845294825280832060018e0184528252918290209490945580518b8152938401869052805133947f30c4d3fe752442ffa2415fd4e6398cb9e378bab963f042ce30ef4363b6ad93b692908290030190a4505b614593858261332f565b98975050505050505050565b6000806145ac8484615027565b600a5491935091508083108015918310159060009083906145ca5750815b156145d757506001614611565b82806145e05750815b156146115760006145f18888611752565b90506000614603898960018503612762565b6201517f1942011015925050505b8015614629576146248787610258615165565b612b2e565b612b2e87876151f9565b600160a060020a0380851660008181526013602090815260408083209488168084529482528083205460118352818420858552835281842054958452601083528184209484529382528083208784529091528120600101549192919061469988886135f4565b905060008511156146f0576040805180820182528581526020808201888152600160a060020a03808d16600090815260108452858120918d1681529083528481208b82529092529290209051815590516001909101555b82158061470257508062015180014210155b8061470d5750600082115b156148fa57600160a060020a038088166000908152601360209081526040808320938c1683529290522054821580156147465750600084115b15614797576040805180820182528281526020808201878152600160a060020a03808d16600090815260108452858120918f1681529083528481208c82529092529290209051815590516001909101555b600160a060020a03808a166000818152601260208181526040808420958e1680855295825280842054928252808420948452938152838320546011825284842095845294905291812082905590919082111561481657600160a060020a03808c166000908152601260209081526040808320938e168352929052908120555b600087111561484857600160a060020a03808c166000908152601360209081526040808320938e168352929052908120555b600160a060020a03808b166000908152601160209081526040808320938f1683529290529081208290558111156148a257600160a060020a03808b166000908152601260209081526040808320938f168352929052908120555b60008311156148d457600160a060020a03808b166000908152601360209081526040808320938f168352929052908120555b6148e28b8b8b878c8c615263565b6148ec8b8b614aab565b6148f68b8b61459f565b5050505b8587600160a060020a031689600160a060020a03167fb5806f8610464e96807c2b147620cc721c65309647f16cfccdf9fb7bd95152ac8888604051808381526020018281526020019250505060405180910390a45050505050505050565b600160a060020a03861660009081526004602052604081205460ff1680156149985750600160a060020a03861660009081526004602052604090205460ff165b15614aa157600854600160a060020a039081169088168114156149bd57839150614a0f565b80600160a060020a031687600160a060020a031614156149df57859150614a0f565b6000806149f08a8460018a03611a9c565b909250905080614a008784613403565b811515614a0957fe5b04935050505b6000821115614a9f57600b54604080517ff0dda65c000000000000000000000000000000000000000000000000000000008152600160a060020a038681166004830152602482018690529151919092169163f0dda65c91604480830192600092919082900301818387803b158015614a8657600080fd5b505af1158015614a9a573d6000803e3d6000fd5b505050505b505b9695505050505050565b614ab5828261145f565b600160a060020a039182166000908152600d602090815260408083209390941682529190915220805460010190555050565b600080614af48885611752565b11614afe57600080fd5b6000614b0a8785611752565b11614b1457600080fd5b600080614b2089613f49565b9092509050600080614b318a613f49565b90925090506000614b6384614b468c88613403565b811515614b4f57fe5b0483858c02811515614b5d57fe5b046127a7565b9050614b6f8188613403565b9c9b505050505050505050505050565b600160a060020a0384166000908152601460209081526040808320338452909152902054614bad908361332f565b600160a060020a0380861660009081526014602081815260408084203380865290835281852096909655938816835290815282822093825292909252902054614bf6908261332f565b600160a060020a0384166000908152601460209081526040808320338452909152812091909155614c2a858560018661449a565b90506000614c3b858760018661449a565b600160a060020a038088166000818152601160208181526040808420958c168085529582528084208990559181528183208484528152818320869055601680825282842086855282528284206001808652908352838520338087529084528486208b90559685529082528284209484529381528183209383529283528082209382529290915290812082905590915080614cd5888861145f565b600160a060020a038083166000908152600f6020908152604080832093851683529281528282208280529052204290559092509050614d178888615460615165565b86600160a060020a031688600160a060020a03167f6f4b2adffa0c3e90e47fdcd9d2c36f48b57eb3271dce519997271073dac17be960405160405180910390a35050505050505050565b6000806000614d6f85613f49565b9092509050600081614d818685613403565b811515614d8a57fe5b0490506000600560009054906101000a9004600160a060020a0316600160a060020a031663a3ca17b26040518163ffffffff1660e060020a02815260040160206040518083038186803b158015614de057600080fd5b505afa158015614df4573d6000803e3d6000fd5b505050506040513d6020811015614e0a57600080fd5b505190506000614e1a8383613403565b600c54604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523360048201523060248201529051929350600092614ec092600160a060020a03169163dd62ed3e916044808301926020929190829003018186803b158015614e8b57600080fd5b505afa158015614e9f573d6000803e3d6000fd5b505050506040513d6020811015614eb557600080fd5b505160028404612a3b565b600c54604080517f70a082310000000000000000000000000000000000000000000000000000000081523360048201529051929350614f5d92600160a060020a03909216916370a0823191602480820192602092909190829003018186803b158015614f2b57600080fd5b505afa158015614f3f573d6000803e3d6000fd5b505050506040513d6020811015614f5557600080fd5b505182612a3b565b9050600081111561501757600c54604080517f4417f4db000000000000000000000000000000000000000000000000000000008152336004820152602481018490529051600160a060020a0390921691634417f4db9160448082019260009290919082900301818387803b158015614fd457600080fd5b505af1158015614fe8573d6000803e3d6000fd5b50505050600082614ff9838b613403565b81151561500257fe5b04905061500f898261332f565b97505061501b565b8796505b50505050505092915050565b6000806000600560009054906101000a9004600160a060020a0316600160a060020a031663a3ca17b26040518163ffffffff1660e060020a02815260040160206040518083038186803b15801561507d57600080fd5b505afa158015615091573d6000803e3d6000fd5b505050506040513d60208110156150a757600080fd5b505190506000806150b787613f49565b90925090506000806150c888613f49565b600160a060020a03808c166000908152601160209081526040808320938e168352929052205491935091508390615109906151039087613403565b87613403565b81151561511257fe5b600160a060020a03808b166000908152601160209081526040808320938f16835292905220549190049750819061514d906151039085613403565b81151561515657fe5b04955050505050509250929050565b61516f838361145f565b600160a060020a038083166000818152600d6020908152604080832094861680845294825280832054848452600e83528184208685528352928190204289019081905581518181529151979a5095985094959194859493927f20017e7b1ef8e7882103f55ff346ca3135c4afe13dff1da2f01b482aece766a5929181900390910190a45050505050565b615203828261145f565b600160a060020a038083166000908152600e6020908152604080832093851683529290522054919350915060011461525f57600160a060020a038083166000908152600e60209081526040808320938516835292905220600190555b5050565b600080615274888860018903611a9c565b9150915060006152ad61529361528a8588613403565b62015180613403565b6152a86152a08786613403565b61a8c0613403565b61332f565b905060006152cd6152be8786613403565b6152c88786613403565b6127a7565b828115156152d757fe5b0490508681016152e78b8b61145f565b600160a060020a039182166000908152600f602090815260408083209390941682529182528281209b81529a905290982097909755505050505050505050565b60408051808201909152600080825260208201529056fe596f75206d75737420736574206120736d616c6c6572206e756d657261746f7220666f722074686520696e697469616c207072696365596f75206d75737420736574207468652064656e6f6d696e61746f7220666f722074686520696e697469616c20707269636554686520616d6f756e74206d7573742062652067726561746572207468616e203054686520636f6e7472616374206d75737420626520756e696e697469616c697a6564596f752073686f756c6420737572706c757320746865207468726573686f6c6420666f7220616464696e6720746f6b656e207061697273546865206e65772070726f706f73616c206d75737420626520612076616c6964206164647265735468652061756374696f6e656572206d75737420626520612076616c69642061646472657373546865206d617374657220636f6e74726163742063616e6e6f74206265207570646174656420696e20612077616974696e6720706572696f644f6e6c79207468652061756374696f6e6565722063616e206e6f6d696e6174652061206e6577206f6e65596f752073686f756c6420757365206120736d616c6c65722066756e64696e6720666f7220746f6b656e2032546865206e6577206d617374657220636f7079206d75737420626520612076616c69642061646472657373596f752063616e6e6f7420616464206120746f6b656e2070616972207573696e67207468652073616d6520746f6b656e49742773206e6f7420706f737369626c6520746f2075706461746520746865206f7261636c6520647572696e67207468652077616974696e6720706572696f64546865206465706f736974207472616e73616374696f6e206d7573742073756363656564546865207769746864726177207472616e73666572206d757374207375636365656441756374696f6e20696e6465782073686f756c6420626520657175616c20746f206c61746573742061756374696f6e20696e6465785468652061756374696f6e6565722061646472657373206d7573742062652076616c6964596f75206d75737420736574206120736d616c6c65722064656e6f6d696e61746f7220666f722074686520696e697469616c207072696365596f75206d7573742073657420746865206e756d657261746f7220666f722074686520696e697469616c207072696365596f752073686f756c6420757365206120736d616c6c65722066756e64696e6720666f7220746f6b656e2031a165627a7a723058207c2888b04e675c63e2fcd95ada8c4645e1b6e490b95f8c3ecdcf29cc9c08faca0029
Swarm Source
bzzr://7c2888b04e675c63e2fcd95ada8c4645e1b6e490b95f8c3ecdcf29cc9c08faca
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 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.