- Contract name:
- ProxyAdminMultisig
- Optimization enabled
- true
- Compiler version
- v0.8.10+commit.fc410830
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2022-11-03T14:17:25.023343Z
Constructor Arguments
000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000561293bc75993bbd53f63fdfdb43847f91cfd079000000000000000000000000742408a71603159b3074fa83e52e9c37ca1a6810000000000000000000000000f8f67ba5b24ceb288b48a8cfbd878f7b2c057d7a
Arg [0] (address[]) : [0x561293bc75993bbd53f63fdfdb43847f91cfd079, 0x742408a71603159b3074fa83e52e9c37ca1a6810, 0xf8f67ba5b24ceb288b48a8cfbd878f7b2c057d7a]
Arg [1] (uint256) : 2
Contract source code
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol) /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`. // This gives `2**k < a <= 2**(k+1)` ā `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`. // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a // good first aproximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1; uint256 x = a; if (x >> 128 > 0) { x >>= 128; result <<= 64; } if (x >> 64 > 0) { x >>= 64; result <<= 32; } if (x >> 32 > 0) { x >>= 32; result <<= 16; } if (x >> 16 > 0) { x >>= 16; result <<= 8; } if (x >> 8 > 0) { x >>= 8; result <<= 4; } if (x >> 4 > 0) { x >>= 4; result <<= 2; } if (x >> 2 > 0) { result <<= 1; } // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { uint256 result = sqrt(a); if (rounding == Rounding.Up && result * result < a) { result += 1; } return result; } } library Constants { string internal constant PROPOSAL_STATUS_PENDING = "Pending"; string internal constant PROPOSAL_STATUS_DELETED = "Deleted"; string internal constant PROPOSAL_STATUS_EXECUTED = "Executed"; address internal constant SENTINEL_OWNER = address(0x1); string internal constant PROPOSAL_TYPE_UPGRADE = "Upgrade"; string internal constant PROPOSAL_TYPE_CHANGE_ADMIN = "ChangeAdmin"; } interface ITransparentUpgradeableProxy { function changeAdmin(address newAdmin) external; function upgradeTo(address newImplementation) external; } error NotOwner(); error ThresholdIsZero(); error ThresholdExceedsOwnersCount(uint256 threshold, uint256 ownersCount); error InvalidOwner(); error OwnerExists(); error UnexpectedProposalType(); error NotPendingProposal(); error AlreadyApproved(); error NotEnoughApproval(); contract ProxyAdminMultisig { // events event Setup( address indexed initiator, address[] owners, uint256 indexed ownerCount, uint256 indexed threshold ); event Propose( uint256 indexed proposalId, address target, string proposalType, // "ChangeAdmin" or "Upgrade" address data ); event Approval(address indexed owner, uint256 indexed proposalId); event Delete(address indexed owner, uint256 indexed proposalId); event Execution( uint256 indexed proposalId, address target, string proposalType, // "ChangeAdmin" or "Upgrade" address data ); event Upgrade(address target, address implementation); event ChangeAdmin(address target, address newAdmin); modifier onlyMember() { if (owners[msg.sender] == address(0)) { revert NotOwner(); } _; } mapping(address => address) internal owners; uint256 internal ownersCount; uint256 internal threshold; struct Proposal { uint256 proposalId; address target; string proposalType; // "ChangeAdmin" or "Upgrade" address data; uint256 approvalCount; address[] approvals; string status; } uint256 internal proposalCount; mapping(uint256 => Proposal) internal proposals; uint256[] internal pendingProposalIds; constructor(address[] memory _owners, uint256 _threshold) { if (_threshold == 0) { revert ThresholdIsZero(); } if (_threshold > _owners.length) { revert ThresholdExceedsOwnersCount(_threshold, _owners.length); } // initialize owners address currentOwner = Constants.SENTINEL_OWNER; for (uint256 i = 0; i < _owners.length; i++) { address owner = _owners[i]; if (owner == address(0) || owner == Constants.SENTINEL_OWNER || currentOwner == owner) { revert InvalidOwner(); } if (owners[owner] != address(0)) { revert OwnerExists(); } owners[currentOwner] = owner; currentOwner = owner; } owners[currentOwner] = Constants.SENTINEL_OWNER; ownersCount = _owners.length; threshold = _threshold; emit Setup(msg.sender, _owners, ownersCount, threshold); } function propose( address target, string calldata proposalType, address data ) external onlyMember { if ( keccak256(bytes(proposalType)) != keccak256(bytes(Constants.PROPOSAL_TYPE_CHANGE_ADMIN)) && keccak256(bytes(proposalType)) != keccak256(bytes(Constants.PROPOSAL_TYPE_UPGRADE)) ) { revert UnexpectedProposalType(); } proposalCount++; uint256 proposalId = proposalCount; // create proposal proposals[proposalId].proposalId = proposalId; proposals[proposalId].target = target; proposals[proposalId].proposalType = proposalType; proposals[proposalId].data = data; proposals[proposalId].approvalCount = 0; proposals[proposalId].status = Constants.PROPOSAL_STATUS_PENDING; pendingProposalIds.push(proposalId); emit Propose(proposalId, target, proposalType, data); } function approveProposal(uint256 proposalId) external onlyMember { if (!_isPendingProposal(proposalId)) { revert NotPendingProposal(); } if (_hasApproved(msg.sender, proposalId)) { revert AlreadyApproved(); } // approve proposal proposals[proposalId].approvalCount++; proposals[proposalId].approvals.push(msg.sender); emit Approval(msg.sender, proposalId); if (proposals[proposalId].approvalCount >= threshold) { _executeProposal(proposalId); } } // reject and delete a pending proposal function deleteProposal(uint256 proposalId) external onlyMember { if (!_isPendingProposal(proposalId)) { revert NotPendingProposal(); } _deletePendingProposalId(proposalId); proposals[proposalId].status = Constants.PROPOSAL_STATUS_DELETED; emit Delete(msg.sender, proposalId); } function getPendingProposals() external view returns (Proposal[] memory results) { uint256 len = pendingProposalIds.length; results = new Proposal[](len); for (uint256 i = 0; i < len; i++) { uint256 pid = pendingProposalIds[i]; results[i] = proposals[pid]; } } function getAllProposals(uint256 offset, uint256 limit) external view returns (Proposal[] memory results) { if (offset >= proposalCount) return results; uint256 len = Math.min(limit, proposalCount - offset); results = new Proposal[](len); for (uint256 i = offset; i < offset + len; i++) { // plus 1 because proposalId starts from 1 results[i - offset] = proposals[i + 1]; } } function getWalletDetail() external view returns ( uint256 _threshold, uint256 _ownersCount, address[] memory _owners ) { _threshold = threshold; _ownersCount = ownersCount; _owners = _getOwners(); } function getProposalCount() external view returns (uint256) { return proposalCount; } function isOwner(address owner) external view returns (bool) { return owner != Constants.SENTINEL_OWNER && owners[owner] != address(0); } function _getOwners() internal view returns (address[] memory) { address[] memory array = new address[](ownersCount); uint256 index = 0; address currentOwner = owners[Constants.SENTINEL_OWNER]; while (currentOwner != Constants.SENTINEL_OWNER) { array[index] = currentOwner; currentOwner = owners[currentOwner]; index++; } return array; } function _executeProposal(uint256 proposalId) internal { Proposal storage proposal = proposals[proposalId]; if (proposal.approvalCount < threshold) { revert NotEnoughApproval(); } if ( keccak256(bytes(proposal.proposalType)) == keccak256(bytes(Constants.PROPOSAL_TYPE_CHANGE_ADMIN)) ) { ITransparentUpgradeableProxy(proposal.target).changeAdmin(proposal.data); emit ChangeAdmin(proposal.target, proposal.data); } else if ( keccak256(bytes(proposal.proposalType)) == keccak256(bytes(Constants.PROPOSAL_TYPE_UPGRADE)) ) { ITransparentUpgradeableProxy(proposal.target).upgradeTo(proposal.data); emit Upgrade(proposal.target, proposal.data); } else { revert("Unexpected proposal type"); } // update proposal _deletePendingProposalId(proposalId); proposals[proposalId].status = Constants.PROPOSAL_STATUS_EXECUTED; } function _deletePendingProposalId(uint256 proposalId) internal { // find index to be deleted uint256 valueIndex = 0; for (uint256 i = 0; i < pendingProposalIds.length; i++) { if (proposalId == pendingProposalIds[i]) { // plus 1 because index 0 // means a value is not in the array. valueIndex = i + 1; break; } } if (valueIndex != 0) { uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = pendingProposalIds.length - 1; if (lastIndex != toDeleteIndex) { pendingProposalIds[toDeleteIndex] = pendingProposalIds[lastIndex]; } // delete the slot pendingProposalIds.pop(); } } function _hasApproved(address owner, uint256 proposalId) internal view returns (bool) { uint256 valueIndex; Proposal memory proposal = proposals[proposalId]; for (uint256 i = 0; i < proposal.approvals.length; i++) { if (owner == proposal.approvals[i]) { // plus 1 because index 0 // means a value is not in the array. valueIndex = i + 1; break; } } return valueIndex != 0; } function _isPendingProposal(uint256 proposalId) internal view returns (bool) { uint256 valueIndex; for (uint256 i = 0; i < pendingProposalIds.length; i++) { if (proposalId == pendingProposalIds[i]) { // plus 1 because index 0 // means a value is not in the array. valueIndex = i + 1; break; } } return valueIndex != 0; } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address[]","name":"_owners","internalType":"address[]"},{"type":"uint256","name":"_threshold","internalType":"uint256"}]},{"type":"error","name":"AlreadyApproved","inputs":[]},{"type":"error","name":"InvalidOwner","inputs":[]},{"type":"error","name":"NotEnoughApproval","inputs":[]},{"type":"error","name":"NotOwner","inputs":[]},{"type":"error","name":"NotPendingProposal","inputs":[]},{"type":"error","name":"OwnerExists","inputs":[]},{"type":"error","name":"ThresholdExceedsOwnersCount","inputs":[{"type":"uint256","name":"threshold","internalType":"uint256"},{"type":"uint256","name":"ownersCount","internalType":"uint256"}]},{"type":"error","name":"ThresholdIsZero","inputs":[]},{"type":"error","name":"UnexpectedProposalType","inputs":[]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"proposalId","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"ChangeAdmin","inputs":[{"type":"address","name":"target","internalType":"address","indexed":false},{"type":"address","name":"newAdmin","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Delete","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"proposalId","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"Execution","inputs":[{"type":"uint256","name":"proposalId","internalType":"uint256","indexed":true},{"type":"address","name":"target","internalType":"address","indexed":false},{"type":"string","name":"proposalType","internalType":"string","indexed":false},{"type":"address","name":"data","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Propose","inputs":[{"type":"uint256","name":"proposalId","internalType":"uint256","indexed":true},{"type":"address","name":"target","internalType":"address","indexed":false},{"type":"string","name":"proposalType","internalType":"string","indexed":false},{"type":"address","name":"data","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Setup","inputs":[{"type":"address","name":"initiator","internalType":"address","indexed":true},{"type":"address[]","name":"owners","internalType":"address[]","indexed":false},{"type":"uint256","name":"ownerCount","internalType":"uint256","indexed":true},{"type":"uint256","name":"threshold","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"Upgrade","inputs":[{"type":"address","name":"target","internalType":"address","indexed":false},{"type":"address","name":"implementation","internalType":"address","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"approveProposal","inputs":[{"type":"uint256","name":"proposalId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deleteProposal","inputs":[{"type":"uint256","name":"proposalId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"results","internalType":"struct ProxyAdminMultisig.Proposal[]","components":[{"type":"uint256","name":"proposalId","internalType":"uint256"},{"type":"address","name":"target","internalType":"address"},{"type":"string","name":"proposalType","internalType":"string"},{"type":"address","name":"data","internalType":"address"},{"type":"uint256","name":"approvalCount","internalType":"uint256"},{"type":"address[]","name":"approvals","internalType":"address[]"},{"type":"string","name":"status","internalType":"string"}]}],"name":"getAllProposals","inputs":[{"type":"uint256","name":"offset","internalType":"uint256"},{"type":"uint256","name":"limit","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"results","internalType":"struct ProxyAdminMultisig.Proposal[]","components":[{"type":"uint256","name":"proposalId","internalType":"uint256"},{"type":"address","name":"target","internalType":"address"},{"type":"string","name":"proposalType","internalType":"string"},{"type":"address","name":"data","internalType":"address"},{"type":"uint256","name":"approvalCount","internalType":"uint256"},{"type":"address[]","name":"approvals","internalType":"address[]"},{"type":"string","name":"status","internalType":"string"}]}],"name":"getPendingProposals","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getProposalCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_threshold","internalType":"uint256"},{"type":"uint256","name":"_ownersCount","internalType":"uint256"},{"type":"address[]","name":"_owners","internalType":"address[]"}],"name":"getWalletDetail","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"propose","inputs":[{"type":"address","name":"target","internalType":"address"},{"type":"string","name":"proposalType","internalType":"string"},{"type":"address","name":"data","internalType":"address"}]}]
Contract Creation Code
0x60806040523480156200001157600080fd5b5060405162001d1838038062001d18833981016040819052620000349162000256565b806200005357604051631fc460bf60e11b815260040160405180910390fd5b81518111156200008d57815160405163c9745ceb60e01b815262000084918391600401918252602082015260400190565b60405180910390fd5b600160005b8351811015620001a2576000848281518110620000b357620000b362000330565b6020026020010151905060006001600160a01b0316816001600160a01b03161480620000e857506001600160a01b0381166001145b80620001055750806001600160a01b0316836001600160a01b0316145b1562000124576040516349e27cff60e01b815260040160405180910390fd5b6001600160a01b0381811660009081526020819052604090205416156200015e576040516315d7cf2960e31b815260040160405180910390fd5b6001600160a01b03928316600090815260208190526040902080546001600160a01b0319169382169390931790925580620001998162000346565b91505062000092565b506001600160a01b0381166000908152602081905260409081902080546001600160a01b03191660019081179091558451908190556002849055905183919033907f9ef8de4d179f3fe64ea3a0574dbfe6a3f869ee559b34bf42d25b7ac41ef1c213906200021290889062000370565b60405180910390a4505050620003bf565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b03811681146200025157600080fd5b919050565b600080604083850312156200026a57600080fd5b82516001600160401b03808211156200028257600080fd5b818501915085601f8301126200029757600080fd5b8151602082821115620002ae57620002ae62000223565b8160051b604051601f19603f83011681018181108682111715620002d657620002d662000223565b604052928352818301935084810182019289841115620002f557600080fd5b948201945b838610156200031e576200030e8662000239565b85529482019493820193620002fa565b97909101519698969750505050505050565b634e487b7160e01b600052603260045260246000fd5b60006000198214156200036957634e487b7160e01b600052601160045260246000fd5b5060010190565b6020808252825182820181905260009190848201906040850190845b81811015620003b35783516001600160a01b0316835292840192918401916001016200038c565b50909695505050505050565b61194980620003cf6000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063a3c393f71161005b578063a3c393f714610101578063a80db6fc14610118578063c08cc02d14610120578063e49422051461013157600080fd5b80632376efbc1461008d5780632f54bf6e146100b65780638259d553146100d957806398951b56146100ee575b600080fd5b6100a061009b36600461149f565b610144565b6040516100ad9190611552565b60405180910390f35b6100c96100c436600461164c565b610421565b60405190151581526020016100ad565b6100ec6100e7366004611667565b610459565b005b6100ec6100fc366004611667565b61052f565b61010961065b565b6040516100ad93929190611680565b6100a0610672565b6003546040519081526020016100ad565b6100ec61013f3660046116a8565b610928565b606060035483106101545761041b565b600061016d83856003546101689190611752565b610b74565b90508067ffffffffffffffff81111561018857610188611769565b6040519080825280602002602001820160405280156101c157816020015b6101ae611343565b8152602001906001900390816101a65790505b509150835b6101d0828661177f565b81101561041857600460006101e683600161177f565b81526020808201929092526040908101600020815160e0810183528154815260018201546001600160a01b031693810193909352600281018054919284019161022e90611797565b80601f016020809104026020016040519081016040528092919081815260200182805461025a90611797565b80156102a75780601f1061027c576101008083540402835291602001916102a7565b820191906000526020600020905b81548152906001019060200180831161028a57829003601f168201915b505050505081526020016003820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600482015481526020016005820180548060200260200160405190810160405280929190818152602001828054801561034257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610324575b5050505050815260200160068201805461035b90611797565b80601f016020809104026020016040519081016040528092919081815260200182805461038790611797565b80156103d45780601f106103a9576101008083540402835291602001916103d4565b820191906000526020600020905b8154815290600101906020018083116103b757829003601f168201915b5050505050815250508386836103ea9190611752565b815181106103fa576103fa6117d2565b60200260200101819052508080610410906117e8565b9150506101c6565b50505b92915050565b60006001600160a01b03821660011480159061041b5750506001600160a01b0390811660009081526020819052604090205416151590565b336000908152602081905260409020546001600160a01b031661048f576040516330cd747160e01b815260040160405180910390fd5b61049881610b8c565b6104b557604051631fc0cfbb60e11b815260040160405180910390fd5b6104be81610bee565b604080518082018252600781526611195b195d195960ca1b6020808301918252600085815260049091529290922090516104fe9260069092019190611392565b50604051819033907fd5f8e8e971a13eefd39d2b144a79e89a46c05e862e0e165e058de3bbedb27b6090600090a350565b336000908152602081905260409020546001600160a01b0316610565576040516330cd747160e01b815260040160405180910390fd5b61056e81610b8c565b61058b57604051631fc0cfbb60e11b815260040160405180910390fd5b6105953382610ce3565b156105b35760405163080fc0bd60e11b815260040160405180910390fd5b60008181526004602081905260408220018054916105d0836117e8565b90915550506000818152600460209081526040808320600501805460018101825590845291832090910180546001600160a01b03191633908117909155905183927f1e4109814b4fb1210f81ef6540a9bf7e5834ff79536859d16d6398f0e417c44f91a360025460008281526004602081905260409091200154106106585761065881610f56565b50565b600254600154606061066b611253565b9050909192565b6005546060908067ffffffffffffffff81111561069157610691611769565b6040519080825280602002602001820160405280156106ca57816020015b6106b7611343565b8152602001906001900390816106af5790505b50915060005b81811015610923576000600582815481106106ed576106ed6117d2565b600091825260208083209091015480835260048252604092839020835160e0810185528154815260018201546001600160a01b031693810193909352600281018054929550929390929084019161074390611797565b80601f016020809104026020016040519081016040528092919081815260200182805461076f90611797565b80156107bc5780601f10610791576101008083540402835291602001916107bc565b820191906000526020600020905b81548152906001019060200180831161079f57829003601f168201915b505050505081526020016003820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600482015481526020016005820180548060200260200160405190810160405280929190818152602001828054801561085757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610839575b5050505050815260200160068201805461087090611797565b80601f016020809104026020016040519081016040528092919081815260200182805461089c90611797565b80156108e95780601f106108be576101008083540402835291602001916108e9565b820191906000526020600020905b8154815290600101906020018083116108cc57829003601f168201915b505050505081525050848381518110610904576109046117d2565b602002602001018190525050808061091b906117e8565b9150506106d0565b505090565b336000908152602081905260409020546001600160a01b031661095e576040516330cd747160e01b815260040160405180910390fd5b604080518082018252600b81526a21b430b733b2a0b236b4b760a91b602090910152517fefd55ed9dfbf676b0ab91f0770a93483a7071f13b003dcc371938f7d0c600788906109b09085908590611803565b604051809103902014158015610a1a575060408051808201825260078152665570677261646560c81b602090910152517f19add3273ac31967a744b01bbed9306f6881ceaa67df8aea5b8977e6da9b97bc90610a0f9085908590611803565b604051809103902014155b15610a38576040516359a2579b60e11b815260040160405180910390fd5b60038054906000610a48836117e8565b909155505060035460008181526004602052604090208181556001810180546001600160a01b0319166001600160a01b038816179055610a8c906002018585611416565b5060008181526004602081815260408084206003810180546001600160a01b0319166001600160a01b0389161790558084018590558151808301909252600782526650656e64696e6760c81b828401908152948690529290915251610af79260069092019190611392565b50600580546001810182556000919091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00181905560405181907feb99a8f3715db0a65e28b58a1738e840c9538a24ff9c0b2cd6e5c94f3b2321f290610b65908890889088908890611813565b60405180910390a25050505050565b6000818310610b835781610b85565b825b9392505050565b60008060005b600554811015610be55760058181548110610baf57610baf6117d2565b9060005260206000200154841415610bd357610bcc81600161177f565b9150610be5565b80610bdd816117e8565b915050610b92565b50151592915050565b6000805b600554811015610c455760058181548110610c0f57610c0f6117d2565b9060005260206000200154831415610c3357610c2c81600161177f565b9150610c45565b80610c3d816117e8565b915050610bf2565b508015610cdf576000610c59600183611752565b600554909150600090610c6e90600190611752565b9050818114610cb55760058181548110610c8a57610c8a6117d2565b906000526020600020015460058381548110610ca857610ca86117d2565b6000918252602090912001555b6005805480610cc657610cc6611861565b6001900381819060005260206000200160009055905550505b5050565b6000818152600460209081526040808320815160e0810183528154815260018201546001600160a01b0316938101939093526002810180548594859490939290840191610d2f90611797565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5b90611797565b8015610da85780601f10610d7d57610100808354040283529160200191610da8565b820191906000526020600020905b815481529060010190602001808311610d8b57829003601f168201915b505050505081526020016003820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016004820154815260200160058201805480602002602001604051908101604052809291908181526020018280548015610e4357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610e25575b50505050508152602001600682018054610e5c90611797565b80601f0160208091040260200160405190810160405280929190818152602001828054610e8890611797565b8015610ed55780601f10610eaa57610100808354040283529160200191610ed5565b820191906000526020600020905b815481529060010190602001808311610eb857829003601f168201915b505050505081525050905060005b8160a0015151811015610f4b578160a001518181518110610f0657610f066117d2565b60200260200101516001600160a01b0316866001600160a01b03161415610f3957610f3281600161177f565b9250610f4b565b80610f43816117e8565b915050610ee3565b505015159392505050565b60008181526004602081905260409091206002549181015490911115610f8f576040516323cf61af60e21b815260040160405180910390fd5b604080518082018252600b81526a21b430b733b2a0b236b4b760a91b602090910152517fefd55ed9dfbf676b0ab91f0770a93483a7071f13b003dcc371938f7d0c60078890610fe2906002840190611877565b604051809103902014156110aa57600181015460038201546040516308f2839760e41b81526001600160a01b039182166004820152911690638f28397090602401600060405180830381600087803b15801561103d57600080fd5b505af1158015611051573d6000803e3d6000fd5b5050505060018101546003820154604080516001600160a01b0393841681529290911660208301527fcf9b665e0639e0b81a8db37b60ac7ddf45aeb1b484e11adeb7dff4bf4a3a625891015b60405180910390a1611204565b60408051808201825260078152665570677261646560c81b602090910152517f19add3273ac31967a744b01bbed9306f6881ceaa67df8aea5b8977e6da9b97bc906110f9906002840190611877565b604051809103902014156111b85760018101546003820154604051631b2ce7f360e11b81526001600160a01b039182166004820152911690633659cfe690602401600060405180830381600087803b15801561115457600080fd5b505af1158015611168573d6000803e3d6000fd5b5050505060018101546003820154604080516001600160a01b0393841681529290911660208301527fd23ce5645530506727523fe6d7939e72bb49102454460bc72f0f5baec60ac718910161109d565b60405162461bcd60e51b815260206004820152601860248201527f556e65787065637465642070726f706f73616c20747970650000000000000000604482015260640160405180910390fd5b61120d82610bee565b6040805180820182526008815267115e1958dd5d195960c21b60208083019182526000868152600490915292909220905161124e9260069092019190611392565b505050565b6060600060015467ffffffffffffffff81111561127257611272611769565b60405190808252806020026020018201604052801561129b578160200160208202803683370190505b506001600090815260208190527fada5013122d395ba3c54772283fb069b10426056ef8ca54750cb9bb552a59e7d54919250906001600160a01b03165b6001600160a01b03811660011461133b57808383815181106112fc576112fc6117d2565b6001600160a01b039283166020918202929092018101919091529181166000908152918290526040909120541681611333816117e8565b9250506112d8565b509092915050565b6040518060e001604052806000815260200160006001600160a01b031681526020016060815260200160006001600160a01b031681526020016000815260200160608152602001606081525090565b82805461139e90611797565b90600052602060002090601f0160209004810192826113c05760008555611406565b82601f106113d957805160ff1916838001178555611406565b82800160010185558215611406579182015b828111156114065782518255916020019190600101906113eb565b5061141292915061148a565b5090565b82805461142290611797565b90600052602060002090601f0160209004810192826114445760008555611406565b82601f1061145d5782800160ff19823516178555611406565b82800160010185558215611406579182015b8281111561140657823582559160200191906001019061146f565b5b80821115611412576000815560010161148b565b600080604083850312156114b257600080fd5b50508035926020909101359150565b6000815180845260005b818110156114e7576020818501810151868301820152016114cb565b818111156114f9576000602083870101525b50601f01601f19169290920160200192915050565b600081518084526020808501945080840160005b838110156115475781516001600160a01b031687529582019590820190600101611522565b509495945050505050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561162257888303603f19018552815180518452878101516001600160a01b03908116898601528782015160e0898701819052916115bc838801836114c1565b925060609150808285015116828801525050608080830151818701525060a080830151868303828801526115f0838261150e565b9250505060c0808301519250858203818701525061160e81836114c1565b968901969450505090860190600101611579565b509098975050505050505050565b80356001600160a01b038116811461164757600080fd5b919050565b60006020828403121561165e57600080fd5b610b8582611630565b60006020828403121561167957600080fd5b5035919050565b83815282602082015260606040820152600061169f606083018461150e565b95945050505050565b600080600080606085870312156116be57600080fd5b6116c785611630565b9350602085013567ffffffffffffffff808211156116e457600080fd5b818701915087601f8301126116f857600080fd5b81358181111561170757600080fd5b88602082850101111561171957600080fd5b60208301955080945050505061173160408601611630565b905092959194509250565b634e487b7160e01b600052601160045260246000fd5b6000828210156117645761176461173c565b500390565b634e487b7160e01b600052604160045260246000fd5b600082198211156117925761179261173c565b500190565b600181811c908216806117ab57607f821691505b602082108114156117cc57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b60006000198214156117fc576117fc61173c565b5060010190565b8183823760009101908152919050565b6001600160a01b03858116825260606020830181905282018490526000908486608085013760008386016080908101919091529316604083015250601f909201601f19169091010192915050565b634e487b7160e01b600052603160045260246000fd5b600080835481600182811c91508083168061189357607f831692505b60208084108214156118b357634e487b7160e01b86526022600452602486fd5b8180156118c757600181146118d857611905565b60ff19861689528489019650611905565b60008a81526020902060005b868110156118fd5781548b8201529085019083016118e4565b505084890196505b50949897505050505050505056fea2646970667358221220bfcce50368ce1fc716d33f637a8c26f3b661763814b8021c7d0136021cf0dcc664736f6c634300080a0033000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000561293bc75993bbd53f63fdfdb43847f91cfd079000000000000000000000000742408a71603159b3074fa83e52e9c37ca1a6810000000000000000000000000f8f67ba5b24ceb288b48a8cfbd878f7b2c057d7a
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106100885760003560e01c8063a3c393f71161005b578063a3c393f714610101578063a80db6fc14610118578063c08cc02d14610120578063e49422051461013157600080fd5b80632376efbc1461008d5780632f54bf6e146100b65780638259d553146100d957806398951b56146100ee575b600080fd5b6100a061009b36600461149f565b610144565b6040516100ad9190611552565b60405180910390f35b6100c96100c436600461164c565b610421565b60405190151581526020016100ad565b6100ec6100e7366004611667565b610459565b005b6100ec6100fc366004611667565b61052f565b61010961065b565b6040516100ad93929190611680565b6100a0610672565b6003546040519081526020016100ad565b6100ec61013f3660046116a8565b610928565b606060035483106101545761041b565b600061016d83856003546101689190611752565b610b74565b90508067ffffffffffffffff81111561018857610188611769565b6040519080825280602002602001820160405280156101c157816020015b6101ae611343565b8152602001906001900390816101a65790505b509150835b6101d0828661177f565b81101561041857600460006101e683600161177f565b81526020808201929092526040908101600020815160e0810183528154815260018201546001600160a01b031693810193909352600281018054919284019161022e90611797565b80601f016020809104026020016040519081016040528092919081815260200182805461025a90611797565b80156102a75780601f1061027c576101008083540402835291602001916102a7565b820191906000526020600020905b81548152906001019060200180831161028a57829003601f168201915b505050505081526020016003820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600482015481526020016005820180548060200260200160405190810160405280929190818152602001828054801561034257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610324575b5050505050815260200160068201805461035b90611797565b80601f016020809104026020016040519081016040528092919081815260200182805461038790611797565b80156103d45780601f106103a9576101008083540402835291602001916103d4565b820191906000526020600020905b8154815290600101906020018083116103b757829003601f168201915b5050505050815250508386836103ea9190611752565b815181106103fa576103fa6117d2565b60200260200101819052508080610410906117e8565b9150506101c6565b50505b92915050565b60006001600160a01b03821660011480159061041b5750506001600160a01b0390811660009081526020819052604090205416151590565b336000908152602081905260409020546001600160a01b031661048f576040516330cd747160e01b815260040160405180910390fd5b61049881610b8c565b6104b557604051631fc0cfbb60e11b815260040160405180910390fd5b6104be81610bee565b604080518082018252600781526611195b195d195960ca1b6020808301918252600085815260049091529290922090516104fe9260069092019190611392565b50604051819033907fd5f8e8e971a13eefd39d2b144a79e89a46c05e862e0e165e058de3bbedb27b6090600090a350565b336000908152602081905260409020546001600160a01b0316610565576040516330cd747160e01b815260040160405180910390fd5b61056e81610b8c565b61058b57604051631fc0cfbb60e11b815260040160405180910390fd5b6105953382610ce3565b156105b35760405163080fc0bd60e11b815260040160405180910390fd5b60008181526004602081905260408220018054916105d0836117e8565b90915550506000818152600460209081526040808320600501805460018101825590845291832090910180546001600160a01b03191633908117909155905183927f1e4109814b4fb1210f81ef6540a9bf7e5834ff79536859d16d6398f0e417c44f91a360025460008281526004602081905260409091200154106106585761065881610f56565b50565b600254600154606061066b611253565b9050909192565b6005546060908067ffffffffffffffff81111561069157610691611769565b6040519080825280602002602001820160405280156106ca57816020015b6106b7611343565b8152602001906001900390816106af5790505b50915060005b81811015610923576000600582815481106106ed576106ed6117d2565b600091825260208083209091015480835260048252604092839020835160e0810185528154815260018201546001600160a01b031693810193909352600281018054929550929390929084019161074390611797565b80601f016020809104026020016040519081016040528092919081815260200182805461076f90611797565b80156107bc5780601f10610791576101008083540402835291602001916107bc565b820191906000526020600020905b81548152906001019060200180831161079f57829003601f168201915b505050505081526020016003820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600482015481526020016005820180548060200260200160405190810160405280929190818152602001828054801561085757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610839575b5050505050815260200160068201805461087090611797565b80601f016020809104026020016040519081016040528092919081815260200182805461089c90611797565b80156108e95780601f106108be576101008083540402835291602001916108e9565b820191906000526020600020905b8154815290600101906020018083116108cc57829003601f168201915b505050505081525050848381518110610904576109046117d2565b602002602001018190525050808061091b906117e8565b9150506106d0565b505090565b336000908152602081905260409020546001600160a01b031661095e576040516330cd747160e01b815260040160405180910390fd5b604080518082018252600b81526a21b430b733b2a0b236b4b760a91b602090910152517fefd55ed9dfbf676b0ab91f0770a93483a7071f13b003dcc371938f7d0c600788906109b09085908590611803565b604051809103902014158015610a1a575060408051808201825260078152665570677261646560c81b602090910152517f19add3273ac31967a744b01bbed9306f6881ceaa67df8aea5b8977e6da9b97bc90610a0f9085908590611803565b604051809103902014155b15610a38576040516359a2579b60e11b815260040160405180910390fd5b60038054906000610a48836117e8565b909155505060035460008181526004602052604090208181556001810180546001600160a01b0319166001600160a01b038816179055610a8c906002018585611416565b5060008181526004602081815260408084206003810180546001600160a01b0319166001600160a01b0389161790558084018590558151808301909252600782526650656e64696e6760c81b828401908152948690529290915251610af79260069092019190611392565b50600580546001810182556000919091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00181905560405181907feb99a8f3715db0a65e28b58a1738e840c9538a24ff9c0b2cd6e5c94f3b2321f290610b65908890889088908890611813565b60405180910390a25050505050565b6000818310610b835781610b85565b825b9392505050565b60008060005b600554811015610be55760058181548110610baf57610baf6117d2565b9060005260206000200154841415610bd357610bcc81600161177f565b9150610be5565b80610bdd816117e8565b915050610b92565b50151592915050565b6000805b600554811015610c455760058181548110610c0f57610c0f6117d2565b9060005260206000200154831415610c3357610c2c81600161177f565b9150610c45565b80610c3d816117e8565b915050610bf2565b508015610cdf576000610c59600183611752565b600554909150600090610c6e90600190611752565b9050818114610cb55760058181548110610c8a57610c8a6117d2565b906000526020600020015460058381548110610ca857610ca86117d2565b6000918252602090912001555b6005805480610cc657610cc6611861565b6001900381819060005260206000200160009055905550505b5050565b6000818152600460209081526040808320815160e0810183528154815260018201546001600160a01b0316938101939093526002810180548594859490939290840191610d2f90611797565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5b90611797565b8015610da85780601f10610d7d57610100808354040283529160200191610da8565b820191906000526020600020905b815481529060010190602001808311610d8b57829003601f168201915b505050505081526020016003820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016004820154815260200160058201805480602002602001604051908101604052809291908181526020018280548015610e4357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610e25575b50505050508152602001600682018054610e5c90611797565b80601f0160208091040260200160405190810160405280929190818152602001828054610e8890611797565b8015610ed55780601f10610eaa57610100808354040283529160200191610ed5565b820191906000526020600020905b815481529060010190602001808311610eb857829003601f168201915b505050505081525050905060005b8160a0015151811015610f4b578160a001518181518110610f0657610f066117d2565b60200260200101516001600160a01b0316866001600160a01b03161415610f3957610f3281600161177f565b9250610f4b565b80610f43816117e8565b915050610ee3565b505015159392505050565b60008181526004602081905260409091206002549181015490911115610f8f576040516323cf61af60e21b815260040160405180910390fd5b604080518082018252600b81526a21b430b733b2a0b236b4b760a91b602090910152517fefd55ed9dfbf676b0ab91f0770a93483a7071f13b003dcc371938f7d0c60078890610fe2906002840190611877565b604051809103902014156110aa57600181015460038201546040516308f2839760e41b81526001600160a01b039182166004820152911690638f28397090602401600060405180830381600087803b15801561103d57600080fd5b505af1158015611051573d6000803e3d6000fd5b5050505060018101546003820154604080516001600160a01b0393841681529290911660208301527fcf9b665e0639e0b81a8db37b60ac7ddf45aeb1b484e11adeb7dff4bf4a3a625891015b60405180910390a1611204565b60408051808201825260078152665570677261646560c81b602090910152517f19add3273ac31967a744b01bbed9306f6881ceaa67df8aea5b8977e6da9b97bc906110f9906002840190611877565b604051809103902014156111b85760018101546003820154604051631b2ce7f360e11b81526001600160a01b039182166004820152911690633659cfe690602401600060405180830381600087803b15801561115457600080fd5b505af1158015611168573d6000803e3d6000fd5b5050505060018101546003820154604080516001600160a01b0393841681529290911660208301527fd23ce5645530506727523fe6d7939e72bb49102454460bc72f0f5baec60ac718910161109d565b60405162461bcd60e51b815260206004820152601860248201527f556e65787065637465642070726f706f73616c20747970650000000000000000604482015260640160405180910390fd5b61120d82610bee565b6040805180820182526008815267115e1958dd5d195960c21b60208083019182526000868152600490915292909220905161124e9260069092019190611392565b505050565b6060600060015467ffffffffffffffff81111561127257611272611769565b60405190808252806020026020018201604052801561129b578160200160208202803683370190505b506001600090815260208190527fada5013122d395ba3c54772283fb069b10426056ef8ca54750cb9bb552a59e7d54919250906001600160a01b03165b6001600160a01b03811660011461133b57808383815181106112fc576112fc6117d2565b6001600160a01b039283166020918202929092018101919091529181166000908152918290526040909120541681611333816117e8565b9250506112d8565b509092915050565b6040518060e001604052806000815260200160006001600160a01b031681526020016060815260200160006001600160a01b031681526020016000815260200160608152602001606081525090565b82805461139e90611797565b90600052602060002090601f0160209004810192826113c05760008555611406565b82601f106113d957805160ff1916838001178555611406565b82800160010185558215611406579182015b828111156114065782518255916020019190600101906113eb565b5061141292915061148a565b5090565b82805461142290611797565b90600052602060002090601f0160209004810192826114445760008555611406565b82601f1061145d5782800160ff19823516178555611406565b82800160010185558215611406579182015b8281111561140657823582559160200191906001019061146f565b5b80821115611412576000815560010161148b565b600080604083850312156114b257600080fd5b50508035926020909101359150565b6000815180845260005b818110156114e7576020818501810151868301820152016114cb565b818111156114f9576000602083870101525b50601f01601f19169290920160200192915050565b600081518084526020808501945080840160005b838110156115475781516001600160a01b031687529582019590820190600101611522565b509495945050505050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561162257888303603f19018552815180518452878101516001600160a01b03908116898601528782015160e0898701819052916115bc838801836114c1565b925060609150808285015116828801525050608080830151818701525060a080830151868303828801526115f0838261150e565b9250505060c0808301519250858203818701525061160e81836114c1565b968901969450505090860190600101611579565b509098975050505050505050565b80356001600160a01b038116811461164757600080fd5b919050565b60006020828403121561165e57600080fd5b610b8582611630565b60006020828403121561167957600080fd5b5035919050565b83815282602082015260606040820152600061169f606083018461150e565b95945050505050565b600080600080606085870312156116be57600080fd5b6116c785611630565b9350602085013567ffffffffffffffff808211156116e457600080fd5b818701915087601f8301126116f857600080fd5b81358181111561170757600080fd5b88602082850101111561171957600080fd5b60208301955080945050505061173160408601611630565b905092959194509250565b634e487b7160e01b600052601160045260246000fd5b6000828210156117645761176461173c565b500390565b634e487b7160e01b600052604160045260246000fd5b600082198211156117925761179261173c565b500190565b600181811c908216806117ab57607f821691505b602082108114156117cc57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b60006000198214156117fc576117fc61173c565b5060010190565b8183823760009101908152919050565b6001600160a01b03858116825260606020830181905282018490526000908486608085013760008386016080908101919091529316604083015250601f909201601f19169091010192915050565b634e487b7160e01b600052603160045260246000fd5b600080835481600182811c91508083168061189357607f831692505b60208084108214156118b357634e487b7160e01b86526022600452602486fd5b8180156118c757600181146118d857611905565b60ff19861689528489019650611905565b60008a81526020902060005b868110156118fd5781548b8201529085019083016118e4565b505084890196505b50949897505050505050505056fea2646970667358221220bfcce50368ce1fc716d33f637a8c26f3b661763814b8021c7d0136021cf0dcc664736f6c634300080a0033