Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- MultisigWallet
- Optimization enabled
- true
- Compiler version
- v0.8.7+commit.e28d00a7
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2024-09-26T15:33:22.236290Z
Constructor Arguments
0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000cb9539df5a8617c4b39105f3d3a614ab72b94f5b0000000000000000000000004cc3a18209517a09f472639551357db80a17412b000000000000000000000000c9bea9379a8fade01240ee583535fac713b7101400000000000000000000000050016fe5de82d818ab8190b2e32115cae7c0cbf5000000000000000000000000600360f031a22213522329c41ead9f0a4d6f37ff
Contract source code
// SPDX-License-Identifier: No License (None) pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256` * (`UintSet`) are supported. */ library EnumerableSet { struct AddressSet { // Storage of set values address[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping (address => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { if (!contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. address lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns 1-based index of value in the set. O(1). */ function indexOf(AddressSet storage set, address value) internal view returns (uint256) { return set._indexes[value]; } /** * @dev Returns the number of values on the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } } contract MultisigWallet { using EnumerableSet for EnumerableSet.AddressSet; struct Ballot { uint128 votes; // bitmap of unique votes (max 127 votes) uint64 expire; // time when ballot expire uint8 yea; // number of votes `Yea` } EnumerableSet.AddressSet owners; // founders may transfer contract's ownership uint256 public ownersSetCounter; // each time when change owners increase the counter uint256 public expirePeriod = 3 days; mapping(bytes32 => Ballot) public ballots; event SetOwner(address owner, bool isEnable); event CreateBallot(bytes32 ballotHash, uint256 expired); event Execute(bytes32 ballotHash, address to, uint256 value, bytes data); modifier onlyThis() { require(address(this) == msg.sender, "Only multisig allowed"); _; } constructor (address[] memory _owners) { for (uint i = 0; i < _owners.length; i++) { require(_owners[i] != address(0), "Zero address"); owners.add(_owners[i]); } } // get number of owners function getOwnersNumber() external view returns(uint256) { return owners.length(); } // returns list of owners addresses function getOwners() external view returns(address[] memory) { return owners._values; } // add owner function addOwner(address owner) external onlyThis{ require(owner != address(0), "Zero address"); require(owners.length() < 127, "Too many owners"); require(owners.add(owner), "Owner already added"); ownersSetCounter++; // change owners set emit SetOwner(owner, true); } // remove owner function removeOwner(address owner) external onlyThis{ require(owners.length() > 1, "Remove all owners is not allowed"); require(owners.remove(owner), "Owner does not exist"); ownersSetCounter++; // change owners set emit SetOwner(owner, false); } function setExpirePeriod(uint256 period) external onlyThis { require(period >= 1 days, "Too short period"); // avoid deadlock in case of set too short period expirePeriod = period; } function vote(address to, uint256 value, bytes calldata data) external { uint256 index = owners.indexOf(msg.sender); require(index != 0, "Only owner"); bytes32 ballotHash = keccak256(abi.encodePacked(to, value, data, ownersSetCounter)); Ballot memory b = ballots[ballotHash]; if (b.expire == 0 || b.expire < uint64(block.timestamp)) { // if no ballot or ballot expired - create new ballot b.expire = uint64(block.timestamp + expirePeriod); b.votes = 0; b.yea = 0; emit CreateBallot(ballotHash, b.expire); } uint256 mask = 1 << index; if (b.votes & mask == 0) { // this owner don't vote yet. b.votes = uint128(b.votes | mask); // record owner's vote b.yea += 1; // increase total votes "Yea" } if (b.yea >= owners.length() / 2 + 1) { // vote "Yea" > 50% of owners delete ballots[ballotHash]; execute(to, value, data); emit Execute(ballotHash, to, value, data); } else { // update ballot ballots[ballotHash] = b; } } function execute(address to, uint256 value, bytes memory data) internal { (bool success,) = to.call{value: value}(data); require(success, "Execute error"); } // allow receive ERC223 tokens function tokenReceived(address _from, uint _value, bytes calldata _data) external {} // allow receive ERC721 tokens (NFT) function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) external pure returns(bytes4) { return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")); } // allow receive coin receive() external payable {} }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address[]","name":"_owners","internalType":"address[]"}]},{"type":"event","name":"CreateBallot","inputs":[{"type":"bytes32","name":"ballotHash","internalType":"bytes32","indexed":false},{"type":"uint256","name":"expired","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Execute","inputs":[{"type":"bytes32","name":"ballotHash","internalType":"bytes32","indexed":false},{"type":"address","name":"to","internalType":"address","indexed":false},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"bytes","name":"data","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"SetOwner","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":false},{"type":"bool","name":"isEnable","internalType":"bool","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint128","name":"votes","internalType":"uint128"},{"type":"uint64","name":"expire","internalType":"uint64"},{"type":"uint8","name":"yea","internalType":"uint8"}],"name":"ballots","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"expirePeriod","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getOwners","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getOwnersNumber","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"onERC721Received","inputs":[{"type":"address","name":"_operator","internalType":"address"},{"type":"address","name":"_from","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"ownersSetCounter","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setExpirePeriod","inputs":[{"type":"uint256","name":"period","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"tokenReceived","inputs":[{"type":"address","name":"_from","internalType":"address"},{"type":"uint256","name":"_value","internalType":"uint256"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"vote","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"receive","stateMutability":"payable"}]
Contract Creation Code
0x60806040526203f4806003553480156200001857600080fd5b50604051620011a9380380620011a98339810160408190526200003b91620001a3565b60005b8151811015620001085760006001600160a01b0316828281518110620000685762000068620002a6565b60200260200101516001600160a01b03161415620000bb5760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b604482015260640160405180910390fd5b620000f2828281518110620000d457620000d4620002a6565b602002602001015160006200011060201b620008c71790919060201c565b5080620000ff816200027c565b9150506200003e565b5050620002d2565b6001600160a01b03811660009081526001830160205260408120546200017c57508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b0386169081179091558554908252828601909352604090209190915562000180565b5060005b92915050565b80516001600160a01b03811681146200019e57600080fd5b919050565b60006020808385031215620001b757600080fd5b82516001600160401b0380821115620001cf57600080fd5b818501915085601f830112620001e457600080fd5b815181811115620001f957620001f9620002bc565b8060051b604051601f19603f83011681018181108582111715620002215762000221620002bc565b604052828152858101935084860182860187018a10156200024157600080fd5b600095505b838610156200026f576200025a8162000186565b85526001959095019493860193860162000246565b5098975050505050505050565b60006000198214156200029f57634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b610ec780620002e26000396000f3fe6080604052600436106100a05760003560e01c80637dd0dd16116100645780637dd0dd161461018b5780638638fb5a1461021057806386cbaed8146102255780638943ec0214610245578063a0e67e2b14610266578063d7a52fa91461028857600080fd5b8063150b7a02146100ac578063163d262f1461010f578063173825d91461013357806321407e53146101555780637065cb481461016b57600080fd5b366100a757005b600080fd5b3480156100b857600080fd5b506100f16100c7366004610ba2565b7f150b7a023d4804d13e8c85fb27262cb750cf6ba9f9dd3bb30d90f482ceeb4b1f95945050505050565b6040516001600160e01b031990911681526020015b60405180910390f35b34801561011b57600080fd5b5061012560025481565b604051908152602001610106565b34801561013f57600080fd5b5061015361014e366004610b80565b6102a8565b005b34801561016157600080fd5b5061012560035481565b34801561017757600080fd5b50610153610186366004610b80565b6103d1565b34801561019757600080fd5b506101df6101a6366004610c6b565b6004602052600090815260409020546001600160801b03811690600160801b810467ffffffffffffffff1690600160c01b900460ff1683565b604080516001600160801b03909416845267ffffffffffffffff909216602084015260ff1690820152606001610106565b34801561021c57600080fd5b50600054610125565b34801561023157600080fd5b50610153610240366004610c11565b610520565b34801561025157600080fd5b50610153610260366004610c11565b50505050565b34801561027257600080fd5b5061027b6107f9565b6040516101069190610cf3565b34801561029457600080fd5b506101536102a3366004610c6b565b61085d565b3033146102d05760405162461bcd60e51b81526004016102c790610d8f565b60405180910390fd5b60016102db60005490565b116103285760405162461bcd60e51b815260206004820181905260248201527f52656d6f766520616c6c206f776e657273206973206e6f7420616c6c6f77656460448201526064016102c7565b61033360008261093b565b6103765760405162461bcd60e51b815260206004820152601460248201527313dddb995c88191bd95cc81b9bdd08195e1a5cdd60621b60448201526064016102c7565b6002805490600061038683610e34565b9091555050604080516001600160a01b0383168152600060208201527f5501576e82029b0850ec7c74ac25b5a46839bf523772a6ac579cc55b092281c891015b60405180910390a150565b3033146103f05760405162461bcd60e51b81526004016102c790610d8f565b6001600160a01b0381166104355760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b60448201526064016102c7565b607f61044060005490565b1061047f5760405162461bcd60e51b815260206004820152600f60248201526e546f6f206d616e79206f776e65727360881b60448201526064016102c7565b61048a6000826108c7565b6104cc5760405162461bcd60e51b815260206004820152601360248201527213dddb995c88185b1c9958591e481859191959606a1b60448201526064016102c7565b600280549060006104dc83610e34565b9091555050604080516001600160a01b0383168152600160208201527f5501576e82029b0850ec7c74ac25b5a46839bf523772a6ac579cc55b092281c891016103c6565b336000908152600160205260409020548061056a5760405162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b60448201526064016102c7565b600085858585600254604051602001610587959493929190610c84565b60408051808303601f190181528282528051602091820120600081815260048352839020606085018452546001600160801b0381168552600160801b810467ffffffffffffffff16928501839052600160c01b900460ff1692840192909252909250158061060c57504267ffffffffffffffff16816020015167ffffffffffffffff16105b156106765760035461061e9042610dbe565b67ffffffffffffffff16602082810182905260008084526040808501919091528051858152918201929092527fdba396e3f86ba92c12e944cda2d787eea52a24f6babcbd54c8ffb2d369bca7c9910160405180910390a15b80516001841b9081166001600160801b03166106ba5781516001600160801b038083169116178252604082018051600191906106b3908390610dd6565b60ff169052505b60026106c560005490565b6106cf9190610dfb565b6106da906001610dbe565b826040015160ff16106107895760008381526004602090815260409182902080546001600160c81b03191690558151601f8801829004820281018201909252868252610745918a918a91908a908a9081908401838280828437600092019190915250610a7d92505050565b7fc75495e0be082158e5855c35d211235055bf668ec3933eb9f3cf757c6493ee6d838989898960405161077c959493929190610d40565b60405180910390a16107ef565b60008381526004602090815260409182902084518154928601519386015160ff16600160c01b0260ff60c01b1967ffffffffffffffff909516600160801b026001600160c01b03199094166001600160801b039092169190911792909217929092161790555b5050505050505050565b60606000800180548060200260200160405190810160405280929190818152602001828054801561085357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610835575b5050505050905090565b30331461087c5760405162461bcd60e51b81526004016102c790610d8f565b620151808110156108c25760405162461bcd60e51b815260206004820152601060248201526f151bdbc81cda1bdc9d081c195c9a5bd960821b60448201526064016102c7565b600355565b6001600160a01b038116600090815260018301602052604081205461093157508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155610935565b5060005b92915050565b6001600160a01b03811660009081526001830160205260408120548015610a73576000610969600183610e1d565b855490915060009061097d90600190610e1d565b9050600086600001828154811061099657610996610e7b565b60009182526020909120015487546001600160a01b03909116915081908890859081106109c5576109c5610e7b565b600091825260209091200180546001600160a01b0319166001600160a01b03929092169190911790556109f9836001610dbe565b6001600160a01b03821660009081526001890160205260409020558654879080610a2557610a25610e65565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506109359350505050565b6000915050610935565b6000836001600160a01b03168383604051610a989190610cb8565b60006040518083038185875af1925050503d8060008114610ad5576040519150601f19603f3d011682016040523d82523d6000602084013e610ada565b606091505b50509050806102605760405162461bcd60e51b815260206004820152600d60248201526c22bc32b1baba329032b93937b960991b60448201526064016102c7565b80356001600160a01b0381168114610b3257600080fd5b919050565b60008083601f840112610b4957600080fd5b50813567ffffffffffffffff811115610b6157600080fd5b602083019150836020828501011115610b7957600080fd5b9250929050565b600060208284031215610b9257600080fd5b610b9b82610b1b565b9392505050565b600080600080600060808688031215610bba57600080fd5b610bc386610b1b565b9450610bd160208701610b1b565b935060408601359250606086013567ffffffffffffffff811115610bf457600080fd5b610c0088828901610b37565b969995985093965092949392505050565b60008060008060608587031215610c2757600080fd5b610c3085610b1b565b935060208501359250604085013567ffffffffffffffff811115610c5357600080fd5b610c5f87828801610b37565b95989497509550505050565b600060208284031215610c7d57600080fd5b5035919050565b6bffffffffffffffffffffffff198660601b1681528460148201528284603483013760349201918201526054019392505050565b6000825160005b81811015610cd95760208186018101518583015201610cbf565b81811115610ce8576000828501525b509190910192915050565b6020808252825182820181905260009190848201906040850190845b81811015610d345783516001600160a01b031683529284019291840191600101610d0f565b50909695505050505050565b8581526001600160a01b0385166020820152604081018490526080606082018190528101829052818360a0830137600081830160a090810191909152601f909201601f19160101949350505050565b60208082526015908201527413db9b1e481b5d5b1d1a5cda59c8185b1b1bddd959605a1b604082015260600190565b60008219821115610dd157610dd1610e4f565b500190565b600060ff821660ff84168060ff03821115610df357610df3610e4f565b019392505050565b600082610e1857634e487b7160e01b600052601260045260246000fd5b500490565b600082821015610e2f57610e2f610e4f565b500390565b6000600019821415610e4857610e48610e4f565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fdfea2646970667358221220202162f5d1bcf784f82920d60cd18e5397c571df146acd6d348f171370019a0a64736f6c6343000807003300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000cb9539df5a8617c4b39105f3d3a614ab72b94f5b0000000000000000000000004cc3a18209517a09f472639551357db80a17412b000000000000000000000000c9bea9379a8fade01240ee583535fac713b7101400000000000000000000000050016fe5de82d818ab8190b2e32115cae7c0cbf5000000000000000000000000600360f031a22213522329c41ead9f0a4d6f37ff
Deployed ByteCode
0x6080604052600436106100a05760003560e01c80637dd0dd16116100645780637dd0dd161461018b5780638638fb5a1461021057806386cbaed8146102255780638943ec0214610245578063a0e67e2b14610266578063d7a52fa91461028857600080fd5b8063150b7a02146100ac578063163d262f1461010f578063173825d91461013357806321407e53146101555780637065cb481461016b57600080fd5b366100a757005b600080fd5b3480156100b857600080fd5b506100f16100c7366004610ba2565b7f150b7a023d4804d13e8c85fb27262cb750cf6ba9f9dd3bb30d90f482ceeb4b1f95945050505050565b6040516001600160e01b031990911681526020015b60405180910390f35b34801561011b57600080fd5b5061012560025481565b604051908152602001610106565b34801561013f57600080fd5b5061015361014e366004610b80565b6102a8565b005b34801561016157600080fd5b5061012560035481565b34801561017757600080fd5b50610153610186366004610b80565b6103d1565b34801561019757600080fd5b506101df6101a6366004610c6b565b6004602052600090815260409020546001600160801b03811690600160801b810467ffffffffffffffff1690600160c01b900460ff1683565b604080516001600160801b03909416845267ffffffffffffffff909216602084015260ff1690820152606001610106565b34801561021c57600080fd5b50600054610125565b34801561023157600080fd5b50610153610240366004610c11565b610520565b34801561025157600080fd5b50610153610260366004610c11565b50505050565b34801561027257600080fd5b5061027b6107f9565b6040516101069190610cf3565b34801561029457600080fd5b506101536102a3366004610c6b565b61085d565b3033146102d05760405162461bcd60e51b81526004016102c790610d8f565b60405180910390fd5b60016102db60005490565b116103285760405162461bcd60e51b815260206004820181905260248201527f52656d6f766520616c6c206f776e657273206973206e6f7420616c6c6f77656460448201526064016102c7565b61033360008261093b565b6103765760405162461bcd60e51b815260206004820152601460248201527313dddb995c88191bd95cc81b9bdd08195e1a5cdd60621b60448201526064016102c7565b6002805490600061038683610e34565b9091555050604080516001600160a01b0383168152600060208201527f5501576e82029b0850ec7c74ac25b5a46839bf523772a6ac579cc55b092281c891015b60405180910390a150565b3033146103f05760405162461bcd60e51b81526004016102c790610d8f565b6001600160a01b0381166104355760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b60448201526064016102c7565b607f61044060005490565b1061047f5760405162461bcd60e51b815260206004820152600f60248201526e546f6f206d616e79206f776e65727360881b60448201526064016102c7565b61048a6000826108c7565b6104cc5760405162461bcd60e51b815260206004820152601360248201527213dddb995c88185b1c9958591e481859191959606a1b60448201526064016102c7565b600280549060006104dc83610e34565b9091555050604080516001600160a01b0383168152600160208201527f5501576e82029b0850ec7c74ac25b5a46839bf523772a6ac579cc55b092281c891016103c6565b336000908152600160205260409020548061056a5760405162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b60448201526064016102c7565b600085858585600254604051602001610587959493929190610c84565b60408051808303601f190181528282528051602091820120600081815260048352839020606085018452546001600160801b0381168552600160801b810467ffffffffffffffff16928501839052600160c01b900460ff1692840192909252909250158061060c57504267ffffffffffffffff16816020015167ffffffffffffffff16105b156106765760035461061e9042610dbe565b67ffffffffffffffff16602082810182905260008084526040808501919091528051858152918201929092527fdba396e3f86ba92c12e944cda2d787eea52a24f6babcbd54c8ffb2d369bca7c9910160405180910390a15b80516001841b9081166001600160801b03166106ba5781516001600160801b038083169116178252604082018051600191906106b3908390610dd6565b60ff169052505b60026106c560005490565b6106cf9190610dfb565b6106da906001610dbe565b826040015160ff16106107895760008381526004602090815260409182902080546001600160c81b03191690558151601f8801829004820281018201909252868252610745918a918a91908a908a9081908401838280828437600092019190915250610a7d92505050565b7fc75495e0be082158e5855c35d211235055bf668ec3933eb9f3cf757c6493ee6d838989898960405161077c959493929190610d40565b60405180910390a16107ef565b60008381526004602090815260409182902084518154928601519386015160ff16600160c01b0260ff60c01b1967ffffffffffffffff909516600160801b026001600160c01b03199094166001600160801b039092169190911792909217929092161790555b5050505050505050565b60606000800180548060200260200160405190810160405280929190818152602001828054801561085357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610835575b5050505050905090565b30331461087c5760405162461bcd60e51b81526004016102c790610d8f565b620151808110156108c25760405162461bcd60e51b815260206004820152601060248201526f151bdbc81cda1bdc9d081c195c9a5bd960821b60448201526064016102c7565b600355565b6001600160a01b038116600090815260018301602052604081205461093157508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155610935565b5060005b92915050565b6001600160a01b03811660009081526001830160205260408120548015610a73576000610969600183610e1d565b855490915060009061097d90600190610e1d565b9050600086600001828154811061099657610996610e7b565b60009182526020909120015487546001600160a01b03909116915081908890859081106109c5576109c5610e7b565b600091825260209091200180546001600160a01b0319166001600160a01b03929092169190911790556109f9836001610dbe565b6001600160a01b03821660009081526001890160205260409020558654879080610a2557610a25610e65565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506109359350505050565b6000915050610935565b6000836001600160a01b03168383604051610a989190610cb8565b60006040518083038185875af1925050503d8060008114610ad5576040519150601f19603f3d011682016040523d82523d6000602084013e610ada565b606091505b50509050806102605760405162461bcd60e51b815260206004820152600d60248201526c22bc32b1baba329032b93937b960991b60448201526064016102c7565b80356001600160a01b0381168114610b3257600080fd5b919050565b60008083601f840112610b4957600080fd5b50813567ffffffffffffffff811115610b6157600080fd5b602083019150836020828501011115610b7957600080fd5b9250929050565b600060208284031215610b9257600080fd5b610b9b82610b1b565b9392505050565b600080600080600060808688031215610bba57600080fd5b610bc386610b1b565b9450610bd160208701610b1b565b935060408601359250606086013567ffffffffffffffff811115610bf457600080fd5b610c0088828901610b37565b969995985093965092949392505050565b60008060008060608587031215610c2757600080fd5b610c3085610b1b565b935060208501359250604085013567ffffffffffffffff811115610c5357600080fd5b610c5f87828801610b37565b95989497509550505050565b600060208284031215610c7d57600080fd5b5035919050565b6bffffffffffffffffffffffff198660601b1681528460148201528284603483013760349201918201526054019392505050565b6000825160005b81811015610cd95760208186018101518583015201610cbf565b81811115610ce8576000828501525b509190910192915050565b6020808252825182820181905260009190848201906040850190845b81811015610d345783516001600160a01b031683529284019291840191600101610d0f565b50909695505050505050565b8581526001600160a01b0385166020820152604081018490526080606082018190528101829052818360a0830137600081830160a090810191909152601f909201601f19160101949350505050565b60208082526015908201527413db9b1e481b5d5b1d1a5cda59c8185b1b1bddd959605a1b604082015260600190565b60008219821115610dd157610dd1610e4f565b500190565b600060ff821660ff84168060ff03821115610df357610df3610e4f565b019392505050565b600082610e1857634e487b7160e01b600052601260045260246000fd5b500490565b600082821015610e2f57610e2f610e4f565b500390565b6000600019821415610e4857610e48610e4f565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fdfea2646970667358221220202162f5d1bcf784f82920d60cd18e5397c571df146acd6d348f171370019a0a64736f6c63430008070033