Address Details
contract
0xFB23032c212cE655bD158297277b02cD7c144701
- Contract Name
- Lifeboat
- Creator
- 0x436bc8–71b5aa at 0x82bb71–30afd6
- Balance
- 0 CELO ( )
- Locked CELO Balance
- 0.00 CELO
- Voting CELO Balance
- 0.00 CELO
- Pending Unlocked Gold
- 0.00 CELO
- Tokens
-
Fetching tokens...
- Transactions
- Fetching transactions...
- Transfers
- Fetching transfers...
- Gas Used
- Fetching gas used...
- Last Balance Update
- 13262094
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- Lifeboat
- Optimization enabled
- true
- Compiler version
- v0.8.11+commit.d7f03943
- Optimization runs
- 2000
- EVM Version
- london
- Verified at
- 2022-05-30T05:42:54.656738Z
project:/contracts/Lifeboat.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; import "./IStdReference.sol"; import "./ISwappaRouterV1.sol"; import "./IERC20.sol"; import "./SafeDecimalMath.sol"; import "./SafeMath.sol"; contract Lifeboat { using SafeMath for uint256; using SafeDecimalMath for uint256; // Swappa router to use for completing the swap ISwappaRouterV1 public immutable swappa; // Oracle for reference price IStdReference public immutable oracle; // Limit for max swap amount per user uint256 public immutable limit; // Source token for the swap IERC20 public immutable source; // Destination token for the swap IERC20 public immutable destination; // Gas depot to pay for rescue transactions address payable public immutable gasDepot; // Oracle base token string public oracleBase; // Oracle quote token string public oracleQuote; // Swapped balance for each user mapping(address => State) public states; struct State { // Amount of remaining tokens to swap uint256 remaining; // Depeg threshold to trigger the swap as a decimal // e.g. 0.95 CUSD/USD uint256 depegThreshold; // Minimum price to accept for the swap as a decimal // e.g. 0.90 USDC/CUSD (source / destination) uint256 minimumPrice; } struct SwapArgs { address[] path; address[] pairs; bytes[] extras; uint256 deadline; } event StateChanged(address indexed user, State state); constructor( ISwappaRouterV1 _swappa, IStdReference _oracle, uint256 _limit, IERC20 _source, IERC20 _destination, address payable _gasDepot, string memory _oracleBase, string memory _oracleQuote ) { swappa = _swappa; oracle = _oracle; limit = _limit; source = _source; destination = _destination; gasDepot = _gasDepot; oracleBase = _oracleBase; oracleQuote = _oracleQuote; // sanity check that the oracle reference data is correct require(getCurrentPeg() > 0, "invalid oracle reference data"); // sanity check the source and destination tokens require(source.totalSupply() > 0, "invalid source token"); require(destination.totalSupply() > 0, "invalid destination token"); // sanity check the limit require(limit > 0, "invalid limit"); } function getCurrentPeg() public view returns (uint256) { return oracle.getReferenceData(oracleBase, oracleQuote).rate; } function unenroll() public { delete states[msg.sender]; emit StateChanged(msg.sender, states[msg.sender]); } function enroll( uint256 amount, uint256 depegThreshold, uint256 minimumPrice ) public payable returns (State memory state) { if (amount == 0) { // enrolling with amount 0 is the same as unenrolling unenroll(); return state; } // do not allow enrollment greater than contract limit state.remaining = amount > limit ? limit : amount; state.depegThreshold = depegThreshold; state.minimumPrice = minimumPrice; require(msg.value > 0, "missing gas depot donation"); require( 0 < depegThreshold && depegThreshold < SafeDecimalMath.UNIT, "invalid depeg threshold" ); require( 0 < minimumPrice && minimumPrice < depegThreshold, "invalid minimum price" ); gasDepot.transfer(address(this).balance); states[msg.sender] = state; emit StateChanged(msg.sender, state); return state; } function effectiveRemaining(address user) public view returns (uint256) { uint256 remaining = states[user].remaining; uint256 allowance = source.allowance(user, address(this)); if (allowance < remaining) { // allowance is not enough remaining = allowance; } uint256 balance = source.balanceOf(user); if (balance < remaining) { // balance is not enough remaining = balance; } return remaining; } function swap(address user, SwapArgs calldata args) public returns (uint256 outputAmount) { State memory state = states[user]; require(getCurrentPeg() < state.depegThreshold, "current peg safe"); require( args.path[0] == address(source) && args.path[args.path.length - 1] == address(destination), "invalid swap path" ); uint256 inputAmount = effectiveRemaining(user); require(inputAmount > 0, "invalid input amount"); // use the minimal price to rescale to the destination token uint256 minOutputAmount = inputAmount .multiplyDecimal(state.minimumPrice) .mul(destination.decimals()) .div(source.decimals()); // pull the necessary input amount from the user require( source.transferFrom(user, address(this), inputAmount), "failed to transfer input" ); require( source.approve(address(swappa), inputAmount), "failed to approve swappa" ); outputAmount = swappa.swapExactInputForOutputWithPrecheck( args.path, args.pairs, args.extras, inputAmount, minOutputAmount, user, args.deadline ); // decrement the remaining and emit uint256 remaining = state.remaining.sub(inputAmount); if (remaining == 0) { delete states[user]; } else { states[user].remaining = remaining; } emit StateChanged(user, states[user]); return outputAmount; } function rescueERC20(IERC20 token) external returns (bool) { return token.transfer(gasDepot, token.balanceOf(address(this))); } }
/project_/contracts/IERC20.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval( address indexed owner, address indexed spender, uint256 value ); }
/project_/contracts/IStdReference.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; pragma experimental ABIEncoderV2; interface IStdReference { /// A structure returned whenever someone requests for standard reference data. struct ReferenceData { uint256 rate; // base/quote exchange rate, multiplied by 1e18. uint256 lastUpdatedBase; // UNIX epoch of the last time when base price gets updated. uint256 lastUpdatedQuote; // UNIX epoch of the last time when quote price gets updated. } /// Returns the price data for the given base/quote pair. Revert if not available. function getReferenceData(string memory _base, string memory _quote) external view returns (ReferenceData memory); /// Similar to getReferenceData, but with multiple base/quote pairs at once. function getReferenceDataBulk( string[] memory _bases, string[] memory _quotes ) external view returns (ReferenceData[] memory); }
/project_/contracts/ISwappaRouterV1.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; pragma experimental ABIEncoderV2; interface ISwappaRouterV1 { function getOutputAmount( address[] calldata path, address[] calldata pairs, bytes[] calldata extras, uint256 inputAmount ) external view returns (uint256 outputAmount); function swapExactInputForOutput( address[] calldata path, address[] calldata pairs, bytes[] calldata extras, uint256 inputAmount, uint256 minOutputAmount, address to, uint256 deadline ) external returns (uint256 outputAmount); function swapExactInputForOutputWithPrecheck( address[] calldata path, address[] calldata pairs, bytes[] calldata extras, uint256 inputAmount, uint256 minOutputAmount, address to, uint256 deadline ) external returns (uint256 outputAmount); }
/project_/contracts/SafeDecimalMath.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; // Libraries import "./SafeMath.sol"; // https://docs.synthetix.io/contracts/source/libraries/safedecimalmath library SafeDecimalMath { using SafeMath for uint256; /* Number of decimal places in the representations. */ uint8 public constant decimals = 18; uint8 public constant highPrecisionDecimals = 27; /* The number representing 1.0. */ uint256 public constant UNIT = 10**uint256(decimals); /* The number representing 1.0 for higher fidelity numbers. */ uint256 public constant PRECISE_UNIT = 10**uint256(highPrecisionDecimals); uint256 private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint256(highPrecisionDecimals - decimals); /** * @return Provides an interface to UNIT. */ function unit() external pure returns (uint256) { return UNIT; } /** * @return Provides an interface to PRECISE_UNIT. */ function preciseUnit() external pure returns (uint256) { return PRECISE_UNIT; } /** * @return The result of multiplying x and y, interpreting the operands as fixed-point * decimals. * * @dev A unit factor is divided out after the product of x and y is evaluated, * so that product must be less than 2**256. As this is an integer division, * the internal division always rounds down. This helps save on gas. Rounding * is more expensive on gas. */ function multiplyDecimal(uint256 x, uint256 y) internal pure returns (uint256) { /* Divide by UNIT to remove the extra factor introduced by the product. */ return x.mul(y) / UNIT; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of the specified precision unit. * * @dev The operands should be in the form of a the specified unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function _multiplyDecimalRound( uint256 x, uint256 y, uint256 precisionUnit ) private pure returns (uint256) { /* Divide by UNIT to remove the extra factor introduced by the product. */ uint256 quotientTimesTen = x.mul(y) / (precisionUnit / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a precise unit. * * @dev The operands should be in the precise unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRoundPrecise(uint256 x, uint256 y) internal pure returns (uint256) { return _multiplyDecimalRound(x, y, PRECISE_UNIT); } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a standard unit. * * @dev The operands should be in the standard unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRound(uint256 x, uint256 y) internal pure returns (uint256) { return _multiplyDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is a high * precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and UNIT must be less than 2**256. As * this is an integer division, the result is always rounded down. * This helps save on gas. Rounding is more expensive on gas. */ function divideDecimal(uint256 x, uint256 y) internal pure returns (uint256) { /* Reintroduce the UNIT factor that will be divided out by y. */ return x.mul(UNIT).div(y); } /** * @return The result of safely dividing x and y. The return value is as a rounded * decimal in the precision unit specified in the parameter. * * @dev y is divided after the product of x and the specified precision unit * is evaluated, so the product of x and the specified precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function _divideDecimalRound( uint256 x, uint256 y, uint256 precisionUnit ) private pure returns (uint256) { uint256 resultTimesTen = x.mul(precisionUnit * 10).div(y); if (resultTimesTen % 10 >= 5) { resultTimesTen += 10; } return resultTimesTen / 10; } /** * @return The result of safely dividing x and y. The return value is as a rounded * standard precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and the standard precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRound(uint256 x, uint256 y) internal pure returns (uint256) { return _divideDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is as a rounded * high precision decimal. * * @dev y is divided after the product of x and the high precision unit * is evaluated, so the product of x and the high precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRoundPrecise(uint256 x, uint256 y) internal pure returns (uint256) { return _divideDecimalRound(x, y, PRECISE_UNIT); } /** * @dev Convert a standard decimal representation to a high precision one. */ function decimalToPreciseDecimal(uint256 i) internal pure returns (uint256) { return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR); } /** * @dev Convert a high precision decimal to a standard decimal representation. */ function preciseDecimalToDecimal(uint256 i) internal pure returns (uint256) { uint256 quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } // Computes `a - b`, setting the value to 0 if b > a. function floorsub(uint256 a, uint256 b) internal pure returns (uint256) { return b >= a ? 0 : a - b; } /* ---------- Utilities ---------- */ /* * Absolute value of the input, returned as a signed number. */ function signedAbs(int256 x) internal pure returns (int256) { return x < 0 ? -x : x; } /* * Absolute value of the input, returned as an unsigned number. */ function abs(int256 x) internal pure returns (uint256) { return uint256(signedAbs(x)); } }
/project_/contracts/SafeMath.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_swappa","internalType":"contract ISwappaRouterV1"},{"type":"address","name":"_oracle","internalType":"contract IStdReference"},{"type":"uint256","name":"_limit","internalType":"uint256"},{"type":"address","name":"_source","internalType":"contract IERC20"},{"type":"address","name":"_destination","internalType":"contract IERC20"},{"type":"address","name":"_gasDepot","internalType":"address payable"},{"type":"string","name":"_oracleBase","internalType":"string"},{"type":"string","name":"_oracleQuote","internalType":"string"}]},{"type":"event","name":"StateChanged","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"tuple","name":"state","internalType":"struct Lifeboat.State","indexed":false,"components":[{"type":"uint256","name":"remaining","internalType":"uint256"},{"type":"uint256","name":"depegThreshold","internalType":"uint256"},{"type":"uint256","name":"minimumPrice","internalType":"uint256"}]}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"destination","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"effectiveRemaining","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"tuple","name":"state","internalType":"struct Lifeboat.State","components":[{"type":"uint256","name":"remaining","internalType":"uint256"},{"type":"uint256","name":"depegThreshold","internalType":"uint256"},{"type":"uint256","name":"minimumPrice","internalType":"uint256"}]}],"name":"enroll","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"depegThreshold","internalType":"uint256"},{"type":"uint256","name":"minimumPrice","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address payable"}],"name":"gasDepot","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCurrentPeg","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"limit","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IStdReference"}],"name":"oracle","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"oracleBase","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"oracleQuote","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"rescueERC20","inputs":[{"type":"address","name":"token","internalType":"contract IERC20"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"source","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"remaining","internalType":"uint256"},{"type":"uint256","name":"depegThreshold","internalType":"uint256"},{"type":"uint256","name":"minimumPrice","internalType":"uint256"}],"name":"states","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"outputAmount","internalType":"uint256"}],"name":"swap","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"tuple","name":"args","internalType":"struct Lifeboat.SwapArgs","components":[{"type":"address[]","name":"path","internalType":"address[]"},{"type":"address[]","name":"pairs","internalType":"address[]"},{"type":"bytes[]","name":"extras","internalType":"bytes[]"},{"type":"uint256","name":"deadline","internalType":"uint256"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ISwappaRouterV1"}],"name":"swappa","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unenroll","inputs":[]}]
Contract Creation Code
0x6101406040523480156200001257600080fd5b5060405162002198380380620021988339810160408190526200003591620004cc565b6001600160a01b0380891660805287811660a05260c087905285811660e052848116610100528316610120528151620000769060009060208501906200032f565b5080516200008c9060019060208401906200032f565b50600062000099620002af565b11620000ec5760405162461bcd60e51b815260206004820152601d60248201527f696e76616c6964206f7261636c65207265666572656e6365206461746100000060448201526064015b60405180910390fd5b600060e0516001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200012f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001559190620005ac565b11620001a45760405162461bcd60e51b815260206004820152601460248201527f696e76616c696420736f7572636520746f6b656e0000000000000000000000006044820152606401620000e3565b6000610100516001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001e8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200020e9190620005ac565b116200025d5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642064657374696e6174696f6e20746f6b656e000000000000006044820152606401620000e3565b600060c05111620002a15760405162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081b1a5b5a5d609a1b6044820152606401620000e3565b50505050505050506200073c565b60a05160405163195556f360e21b81526000916001600160a01b0316906365555bcc90620002e5908490600190600401620006ab565b606060405180830381865afa15801562000303573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003299190620006dd565b51919050565b8280546200033d90620005c6565b90600052602060002090601f016020900481019282620003615760008555620003ac565b82601f106200037c57805160ff1916838001178555620003ac565b82800160010185558215620003ac579182015b82811115620003ac5782518255916020019190600101906200038f565b50620003ba929150620003be565b5090565b5b80821115620003ba5760008155600101620003bf565b6001600160a01b0381168114620003eb57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156200042f576200042f620003ee565b604052919050565b600082601f8301126200044957600080fd5b81516001600160401b03811115620004655762000465620003ee565b60206200047b601f8301601f1916820162000404565b82815285828487010111156200049057600080fd5b60005b83811015620004b057858101830151828201840152820162000493565b83811115620004c25760008385840101525b5095945050505050565b600080600080600080600080610100898b031215620004ea57600080fd5b8851620004f781620003d5565b60208a01519098506200050a81620003d5565b60408a015160608b015191985096506200052481620003d5565b60808a01519095506200053781620003d5565b60a08a01519094506200054a81620003d5565b60c08a01519093506001600160401b03808211156200056857600080fd5b620005768c838d0162000437565b935060e08b01519150808211156200058d57600080fd5b506200059c8b828c0162000437565b9150509295985092959890939650565b600060208284031215620005bf57600080fd5b5051919050565b600181811c90821680620005db57607f821691505b60208210811415620005fd57634e487b7160e01b600052602260045260246000fd5b50919050565b8054600090600181811c90808316806200061e57607f831692505b60208084108214156200064157634e487b7160e01b600052602260045260246000fd5b838852602088018280156200065f576001811462000671576200069e565b60ff198716825282820197506200069e565b60008981526020902060005b8781101562000698578154848201529086019084016200067d565b83019850505b5050505050505092915050565b604081526000620006c0604083018562000603565b8281036020840152620006d4818562000603565b95945050505050565b600060608284031215620006f057600080fd5b604051606081016001600160401b0381118282101715620007155762000715620003ee565b80604052508251815260208301516020820152604083015160408201528091505092915050565b60805160a05160c05160e05161010051610120516119a3620007f5600039600081816102f40152818161056301526110ae01526000818161035c01528181610a6c0152610c1401526000818161026c015281816107960152818161084a01528181610a0101528181610b8c01528181610d020152610e1c015260008181610328015281816103e601526104130152600081816102c0015261066001526000818161015a01528181610ded0152610edf01526119a36000f3fe6080604052600436106100e85760003560e01c80635bcba7d31161008a57806389d4b3e91161005957806389d4b3e9146102e2578063a4d66daf14610316578063b269681d1461034a578063ccec37161461037e57600080fd5b80635bcba7d31461024557806367e828bf1461025a5780637a05b7f31461028e5780637dc0d1d0146102ae57600080fd5b806316bea400116100c657806316bea400146101c957806320f3b418146101ec5780632bd27b40146102035780634562aee31461022357600080fd5b806302a22337146100ed578063056bc3b41461014857806307a415f014610194575b600080fd5b3480156100f957600080fd5b50610128610108366004611362565b600260208190526000918252604090912080546001820154919092015483565b604080519384526020840192909252908201526060015b60405180910390f35b34801561015457600080fd5b5061017c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161013f565b6101a76101a236600461137f565b6103ae565b604080518251815260208084015190820152918101519082015260600161013f565b3480156101d557600080fd5b506101de61062d565b60405190815260200161013f565b3480156101f857600080fd5b506102016106df565b005b34801561020f57600080fd5b506101de61021e366004611362565b610740565b34801561022f57600080fd5b506102386108ce565b60405161013f91906113ab565b34801561025157600080fd5b5061023861095c565b34801561026657600080fd5b5061017c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029a57600080fd5b506101de6102a9366004611400565b610969565b3480156102ba57600080fd5b5061017c7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102ee57600080fd5b5061017c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561032257600080fd5b506101de7f000000000000000000000000000000000000000000000000000000000000000081565b34801561035657600080fd5b5061017c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561038a57600080fd5b5061039e610399366004611362565b61106c565b604051901515815260200161013f565b6103d260405180606001604052806000815260200160008152602001600081525090565b836103e4576103df6106df565b610626565b7f000000000000000000000000000000000000000000000000000000000000000084116104115783610433565b7f00000000000000000000000000000000000000000000000000000000000000005b81526020810183905260408101829052346104955760405162461bcd60e51b815260206004820152601a60248201527f6d697373696e6720676173206465706f7420646f6e6174696f6e00000000000060448201526064015b60405180910390fd5b8260001080156104af57506104ac6012600a611551565b83105b6104fb5760405162461bcd60e51b815260206004820152601760248201527f696e76616c6964206465706567207468726573686f6c64000000000000000000604482015260640161048c565b81600010801561050a57508282105b6105565760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d2070726963650000000000000000000000604482015260640161048c565b6040516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016904780156108fc02916000818181858888f193505050501580156105ab573d6000803e3d6000fd5b50336000818152600260208181526040928390208551815590850151600182015582850151910155517fc8a7ba43356f20e6e5c92337e803c1859364d33a59c781540205bbec291315ce9061061d90849081518152602080830151908201526040918201519181019190915260600190565b60405180910390a25b9392505050565b6040517f65555bcc0000000000000000000000000000000000000000000000000000000081526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906365555bcc90610698908490600190600401611656565b606060405180830381865afa1580156106b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d9919061167b565b51919050565b33600081815260026020818152604080842084815560018101859055909201839055815183815290810183905280820192909252517fc8a7ba43356f20e6e5c92337e803c1859364d33a59c781540205bbec291315ce9181900360600190a2565b6001600160a01b038181166000818152600260205260408082205490517fdd62ed3e00000000000000000000000000000000000000000000000000000000815260048101939093523060248401529092909183917f0000000000000000000000000000000000000000000000000000000000000000169063dd62ed3e90604401602060405180830381865afa1580156107dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080191906116e5565b90508181101561080f578091505b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa158015610893573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b791906116e5565b9050828110156108c5578092505b50909392505050565b600080546108db9061155d565b80601f01602080910402602001604051908101604052809291908181526020018280546109079061155d565b80156109545780601f1061092957610100808354040283529160200191610954565b820191906000526020600020905b81548152906001019060200180831161093757829003601f168201915b505050505081565b600180546108db9061155d565b6001600160a01b03821660009081526002602081815260408084208151606081018352815481526001820154938101849052930154908301526109aa61062d565b106109f75760405162461bcd60e51b815260206004820152601060248201527f63757272656e7420706567207361666500000000000000000000000000000000604482015260640161048c565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016610a2b84806116fe565b6000818110610a3c57610a3c61174f565b9050602002016020810190610a519190611362565b6001600160a01b0316148015610adc57506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016610a9684806116fe565b6001610aa287806116fe565b610aad929150611765565b818110610abc57610abc61174f565b9050602002016020810190610ad19190611362565b6001600160a01b0316145b610b285760405162461bcd60e51b815260206004820152601160248201527f696e76616c696420737761702070617468000000000000000000000000000000604482015260640161048c565b6000610b3385610740565b905060008111610b855760405162461bcd60e51b815260206004820152601460248201527f696e76616c696420696e70757420616d6f756e74000000000000000000000000604482015260640161048c565b6000610cba7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0c919061177c565b60ff16610cb47f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c94919061177c565b60ff16610cae8760400151876111a190919063ffffffff16565b906111c3565b9061125e565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152306024830152604482018590529192507f0000000000000000000000000000000000000000000000000000000000000000909116906323b872dd906064016020604051808303816000875af1158015610d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d71919061179f565b610dbd5760405162461bcd60e51b815260206004820152601860248201527f6661696c656420746f207472616e7366657220696e7075740000000000000000604482015260640161048c565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b3906044016020604051808303816000875af1158015610e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e89919061179f565b610ed55760405162461bcd60e51b815260206004820152601860248201527f6661696c656420746f20617070726f7665207377617070610000000000000000604482015260640161048c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663adf6fa02610f0e87806116fe565b610f1b60208a018a6116fe565b610f2860408c018c6116fe565b89898f8f606001356040518b63ffffffff1660e01b8152600401610f559a99989796959493929190611835565b6020604051808303816000875af1158015610f74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9891906116e5565b8351909450600090610faa90846112a0565b905080610fdc576001600160a01b03871660009081526002602081905260408220828155600181018390550155610ff8565b6001600160a01b03871660009081526002602052604090208190555b6001600160a01b0387166000818152600260205260409081902090517fc8a7ba43356f20e6e5c92337e803c1859364d33a59c781540205bbec291315ce91611059918154815260018201546020820152600290910154604082015260600190565b60405180910390a2505050505b92915050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b0383169063a9059cbb907f00000000000000000000000000000000000000000000000000000000000000009083906370a0823190602401602060405180830381865afa1580156110f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111a91906116e5565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801561117d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611066919061179f565b60006111af6012600a611551565b6111b984846111c3565b610626919061192c565b6000826111d257506000611066565b60006111de838561194e565b9050826111eb858361192c565b146106265760405162461bcd60e51b815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60448201527f7700000000000000000000000000000000000000000000000000000000000000606482015260840161048c565b600061062683836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506112e2565b600061062683836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611319565b600081836113035760405162461bcd60e51b815260040161048c91906113ab565b506000611310848661192c565b95945050505050565b6000818484111561133d5760405162461bcd60e51b815260040161048c91906113ab565b5060006113108486611765565b6001600160a01b038116811461135f57600080fd5b50565b60006020828403121561137457600080fd5b81356106268161134a565b60008060006060848603121561139457600080fd5b505081359360208301359350604090920135919050565b600060208083528351808285015260005b818110156113d8578581018301518582016040015282016113bc565b818111156113ea576000604083870101525b50601f01601f1916929092016040019392505050565b6000806040838503121561141357600080fd5b823561141e8161134a565b9150602083013567ffffffffffffffff81111561143a57600080fd5b83016080818603121561144c57600080fd5b809150509250929050565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156114a857816000190482111561148e5761148e611457565b8085161561149b57918102915b93841c9390800290611472565b509250929050565b6000826114bf57506001611066565b816114cc57506000611066565b81600181146114e257600281146114ec57611508565b6001915050611066565b60ff8411156114fd576114fd611457565b50506001821b611066565b5060208310610133831016604e8410600b841016171561152b575081810a611066565b611535838361146d565b806000190482111561154957611549611457565b029392505050565b600061062683836114b0565b600181811c9082168061157157607f821691505b6020821081141561159257634e487b7160e01b600052602260045260246000fd5b50919050565b8054600090600181811c90808316806115b257607f831692505b60208084108214156115d457634e487b7160e01b600052602260045260246000fd5b838852602088018280156115ef576001811461161e57611649565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00871682528282019750611649565b60008981526020902060005b878110156116435781548482015290860190840161162a565b83019850505b5050505050505092915050565b6040815260006116696040830185611598565b82810360208401526113108185611598565b60006060828403121561168d57600080fd5b6040516060810181811067ffffffffffffffff821117156116be57634e487b7160e01b600052604160045260246000fd5b80604052508251815260208301516020820152604083015160408201528091505092915050565b6000602082840312156116f757600080fd5b5051919050565b6000808335601e1984360301811261171557600080fd5b83018035915067ffffffffffffffff82111561173057600080fd5b6020019150600581901b360382131561174857600080fd5b9250929050565b634e487b7160e01b600052603260045260246000fd5b60008282101561177757611777611457565b500390565b60006020828403121561178e57600080fd5b815160ff8116811461062657600080fd5b6000602082840312156117b157600080fd5b8151801515811461062657600080fd5b8183526000602080850194508260005b858110156117ff5781356117e48161134a565b6001600160a01b0316875295820195908201906001016117d1565b509495945050505050565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b60e08152600061184960e083018c8e6117c1565b828103602084015261185c818b8d6117c1565b8381036040850152888152905060208082019060058a901b8301018a60005b8b8110156118ee57601f198584030184528135601e198e36030181126118a057600080fd5b8d01803567ffffffffffffffff8111156118b957600080fd5b8036038f13156118c857600080fd5b6118d685826020850161180a565b6020968701969095509390930192505060010161187b565b505080935050505085606083015284608083015261191760a08301856001600160a01b03169052565b8260c08301529b9a5050505050505050505050565b60008261194957634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161561196857611968611457565b50029056fea26469706673582212207190da2f8c0495bb9f7c50b6fb2fb476f5675accef657aca01793a931b35eb2964736f6c634300080b0033000000000000000000000000f35ed7156babf2541e032b3bb8625210316e2832000000000000000000000000da7a001b254cd22e46d3eab04d937489c93174c300000000000000000000000000000000000000000000003635c9adc5dea00000000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a000000000000000000000000ef4229c8c3250c675f21bcefa42f58efbff6002a000000000000000000000000436bc8c741b55864b40a0d3b6f2b6ecb5771b5aa000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000004435553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035553440000000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x6080604052600436106100e85760003560e01c80635bcba7d31161008a57806389d4b3e91161005957806389d4b3e9146102e2578063a4d66daf14610316578063b269681d1461034a578063ccec37161461037e57600080fd5b80635bcba7d31461024557806367e828bf1461025a5780637a05b7f31461028e5780637dc0d1d0146102ae57600080fd5b806316bea400116100c657806316bea400146101c957806320f3b418146101ec5780632bd27b40146102035780634562aee31461022357600080fd5b806302a22337146100ed578063056bc3b41461014857806307a415f014610194575b600080fd5b3480156100f957600080fd5b50610128610108366004611362565b600260208190526000918252604090912080546001820154919092015483565b604080519384526020840192909252908201526060015b60405180910390f35b34801561015457600080fd5b5061017c7f000000000000000000000000f35ed7156babf2541e032b3bb8625210316e283281565b6040516001600160a01b03909116815260200161013f565b6101a76101a236600461137f565b6103ae565b604080518251815260208084015190820152918101519082015260600161013f565b3480156101d557600080fd5b506101de61062d565b60405190815260200161013f565b3480156101f857600080fd5b506102016106df565b005b34801561020f57600080fd5b506101de61021e366004611362565b610740565b34801561022f57600080fd5b506102386108ce565b60405161013f91906113ab565b34801561025157600080fd5b5061023861095c565b34801561026657600080fd5b5061017c7f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a81565b34801561029a57600080fd5b506101de6102a9366004611400565b610969565b3480156102ba57600080fd5b5061017c7f000000000000000000000000da7a001b254cd22e46d3eab04d937489c93174c381565b3480156102ee57600080fd5b5061017c7f000000000000000000000000436bc8c741b55864b40a0d3b6f2b6ecb5771b5aa81565b34801561032257600080fd5b506101de7f00000000000000000000000000000000000000000000003635c9adc5dea0000081565b34801561035657600080fd5b5061017c7f000000000000000000000000ef4229c8c3250c675f21bcefa42f58efbff6002a81565b34801561038a57600080fd5b5061039e610399366004611362565b61106c565b604051901515815260200161013f565b6103d260405180606001604052806000815260200160008152602001600081525090565b836103e4576103df6106df565b610626565b7f00000000000000000000000000000000000000000000003635c9adc5dea0000084116104115783610433565b7f00000000000000000000000000000000000000000000003635c9adc5dea000005b81526020810183905260408101829052346104955760405162461bcd60e51b815260206004820152601a60248201527f6d697373696e6720676173206465706f7420646f6e6174696f6e00000000000060448201526064015b60405180910390fd5b8260001080156104af57506104ac6012600a611551565b83105b6104fb5760405162461bcd60e51b815260206004820152601760248201527f696e76616c6964206465706567207468726573686f6c64000000000000000000604482015260640161048c565b81600010801561050a57508282105b6105565760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d2070726963650000000000000000000000604482015260640161048c565b6040516001600160a01b037f000000000000000000000000436bc8c741b55864b40a0d3b6f2b6ecb5771b5aa16904780156108fc02916000818181858888f193505050501580156105ab573d6000803e3d6000fd5b50336000818152600260208181526040928390208551815590850151600182015582850151910155517fc8a7ba43356f20e6e5c92337e803c1859364d33a59c781540205bbec291315ce9061061d90849081518152602080830151908201526040918201519181019190915260600190565b60405180910390a25b9392505050565b6040517f65555bcc0000000000000000000000000000000000000000000000000000000081526000906001600160a01b037f000000000000000000000000da7a001b254cd22e46d3eab04d937489c93174c316906365555bcc90610698908490600190600401611656565b606060405180830381865afa1580156106b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d9919061167b565b51919050565b33600081815260026020818152604080842084815560018101859055909201839055815183815290810183905280820192909252517fc8a7ba43356f20e6e5c92337e803c1859364d33a59c781540205bbec291315ce9181900360600190a2565b6001600160a01b038181166000818152600260205260408082205490517fdd62ed3e00000000000000000000000000000000000000000000000000000000815260048101939093523060248401529092909183917f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a169063dd62ed3e90604401602060405180830381865afa1580156107dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080191906116e5565b90508181101561080f578091505b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301526000917f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a909116906370a0823190602401602060405180830381865afa158015610893573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b791906116e5565b9050828110156108c5578092505b50909392505050565b600080546108db9061155d565b80601f01602080910402602001604051908101604052809291908181526020018280546109079061155d565b80156109545780601f1061092957610100808354040283529160200191610954565b820191906000526020600020905b81548152906001019060200180831161093757829003601f168201915b505050505081565b600180546108db9061155d565b6001600160a01b03821660009081526002602081815260408084208151606081018352815481526001820154938101849052930154908301526109aa61062d565b106109f75760405162461bcd60e51b815260206004820152601060248201527f63757272656e7420706567207361666500000000000000000000000000000000604482015260640161048c565b6001600160a01b037f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a16610a2b84806116fe565b6000818110610a3c57610a3c61174f565b9050602002016020810190610a519190611362565b6001600160a01b0316148015610adc57506001600160a01b037f000000000000000000000000ef4229c8c3250c675f21bcefa42f58efbff6002a16610a9684806116fe565b6001610aa287806116fe565b610aad929150611765565b818110610abc57610abc61174f565b9050602002016020810190610ad19190611362565b6001600160a01b0316145b610b285760405162461bcd60e51b815260206004820152601160248201527f696e76616c696420737761702070617468000000000000000000000000000000604482015260640161048c565b6000610b3385610740565b905060008111610b855760405162461bcd60e51b815260206004820152601460248201527f696e76616c696420696e70757420616d6f756e74000000000000000000000000604482015260640161048c565b6000610cba7f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0c919061177c565b60ff16610cb47f000000000000000000000000ef4229c8c3250c675f21bcefa42f58efbff6002a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c94919061177c565b60ff16610cae8760400151876111a190919063ffffffff16565b906111c3565b9061125e565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152306024830152604482018590529192507f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a909116906323b872dd906064016020604051808303816000875af1158015610d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d71919061179f565b610dbd5760405162461bcd60e51b815260206004820152601860248201527f6661696c656420746f207472616e7366657220696e7075740000000000000000604482015260640161048c565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000f35ed7156babf2541e032b3bb8625210316e283281166004830152602482018490527f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a169063095ea7b3906044016020604051808303816000875af1158015610e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e89919061179f565b610ed55760405162461bcd60e51b815260206004820152601860248201527f6661696c656420746f20617070726f7665207377617070610000000000000000604482015260640161048c565b6001600160a01b037f000000000000000000000000f35ed7156babf2541e032b3bb8625210316e28321663adf6fa02610f0e87806116fe565b610f1b60208a018a6116fe565b610f2860408c018c6116fe565b89898f8f606001356040518b63ffffffff1660e01b8152600401610f559a99989796959493929190611835565b6020604051808303816000875af1158015610f74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9891906116e5565b8351909450600090610faa90846112a0565b905080610fdc576001600160a01b03871660009081526002602081905260408220828155600181018390550155610ff8565b6001600160a01b03871660009081526002602052604090208190555b6001600160a01b0387166000818152600260205260409081902090517fc8a7ba43356f20e6e5c92337e803c1859364d33a59c781540205bbec291315ce91611059918154815260018201546020820152600290910154604082015260600190565b60405180910390a2505050505b92915050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b0383169063a9059cbb907f000000000000000000000000436bc8c741b55864b40a0d3b6f2b6ecb5771b5aa9083906370a0823190602401602060405180830381865afa1580156110f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111a91906116e5565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801561117d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611066919061179f565b60006111af6012600a611551565b6111b984846111c3565b610626919061192c565b6000826111d257506000611066565b60006111de838561194e565b9050826111eb858361192c565b146106265760405162461bcd60e51b815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60448201527f7700000000000000000000000000000000000000000000000000000000000000606482015260840161048c565b600061062683836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506112e2565b600061062683836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611319565b600081836113035760405162461bcd60e51b815260040161048c91906113ab565b506000611310848661192c565b95945050505050565b6000818484111561133d5760405162461bcd60e51b815260040161048c91906113ab565b5060006113108486611765565b6001600160a01b038116811461135f57600080fd5b50565b60006020828403121561137457600080fd5b81356106268161134a565b60008060006060848603121561139457600080fd5b505081359360208301359350604090920135919050565b600060208083528351808285015260005b818110156113d8578581018301518582016040015282016113bc565b818111156113ea576000604083870101525b50601f01601f1916929092016040019392505050565b6000806040838503121561141357600080fd5b823561141e8161134a565b9150602083013567ffffffffffffffff81111561143a57600080fd5b83016080818603121561144c57600080fd5b809150509250929050565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156114a857816000190482111561148e5761148e611457565b8085161561149b57918102915b93841c9390800290611472565b509250929050565b6000826114bf57506001611066565b816114cc57506000611066565b81600181146114e257600281146114ec57611508565b6001915050611066565b60ff8411156114fd576114fd611457565b50506001821b611066565b5060208310610133831016604e8410600b841016171561152b575081810a611066565b611535838361146d565b806000190482111561154957611549611457565b029392505050565b600061062683836114b0565b600181811c9082168061157157607f821691505b6020821081141561159257634e487b7160e01b600052602260045260246000fd5b50919050565b8054600090600181811c90808316806115b257607f831692505b60208084108214156115d457634e487b7160e01b600052602260045260246000fd5b838852602088018280156115ef576001811461161e57611649565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00871682528282019750611649565b60008981526020902060005b878110156116435781548482015290860190840161162a565b83019850505b5050505050505092915050565b6040815260006116696040830185611598565b82810360208401526113108185611598565b60006060828403121561168d57600080fd5b6040516060810181811067ffffffffffffffff821117156116be57634e487b7160e01b600052604160045260246000fd5b80604052508251815260208301516020820152604083015160408201528091505092915050565b6000602082840312156116f757600080fd5b5051919050565b6000808335601e1984360301811261171557600080fd5b83018035915067ffffffffffffffff82111561173057600080fd5b6020019150600581901b360382131561174857600080fd5b9250929050565b634e487b7160e01b600052603260045260246000fd5b60008282101561177757611777611457565b500390565b60006020828403121561178e57600080fd5b815160ff8116811461062657600080fd5b6000602082840312156117b157600080fd5b8151801515811461062657600080fd5b8183526000602080850194508260005b858110156117ff5781356117e48161134a565b6001600160a01b0316875295820195908201906001016117d1565b509495945050505050565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b60e08152600061184960e083018c8e6117c1565b828103602084015261185c818b8d6117c1565b8381036040850152888152905060208082019060058a901b8301018a60005b8b8110156118ee57601f198584030184528135601e198e36030181126118a057600080fd5b8d01803567ffffffffffffffff8111156118b957600080fd5b8036038f13156118c857600080fd5b6118d685826020850161180a565b6020968701969095509390930192505060010161187b565b505080935050505085606083015284608083015261191760a08301856001600160a01b03169052565b8260c08301529b9a5050505050505050505050565b60008261194957634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161561196857611968611457565b50029056fea26469706673582212207190da2f8c0495bb9f7c50b6fb2fb476f5675accef657aca01793a931b35eb2964736f6c634300080b0033