Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- CallistoBridge
- Optimization enabled
- true
- Compiler version
- v0.8.7+commit.e28d00a7
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2024-09-26T08:16:40.702009Z
Contract source code
// SPDX-License-Identifier: No License (None) pragma solidity ^0.8.0; interface IERC223TokenCloned { // initialize cloned token just for ERC223TokenCloned function initialize(address newOwner, string calldata name, string calldata symbol, uint8 decimals) external; function mint(address user, uint256 amount) external; function burnFrom(address account, uint256 amount) external returns(bool); function burn(uint256 amount) external returns(bool); function balanceOf(address account) external view returns (uint256); function allowance(address _owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); } interface IContractCaller { function callContract(address user, address token, uint256 value, address toContract, bytes memory data) external payable; } /** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. * * _Available since v3.4._ */ library Clones { /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create opcode, which should never revert. */ function clone(address implementation) internal returns (address instance) { assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create(0, ptr, 0x37) } require(instance != address(0), "ERC1167: create failed"); } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `implementation` and `salt` multiple time will revert, since * the clones cannot be deployed twice at the same address. */ function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create2(0, ptr, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) mstore(add(ptr, 0x38), shl(0x60, deployer)) mstore(add(ptr, 0x4c), salt) mstore(add(ptr, 0x6c), keccak256(ptr, 0x37)) predicted := keccak256(add(ptr, 0x37), 0x55) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress(address implementation, bytes32 salt) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } } // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false library TransferHelper { function safeApprove(address token, address to, uint value) internal { // bytes4(keccak256(bytes('approve(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED'); } function safeTransfer(address token, address to, uint value) internal { // bytes4(keccak256(bytes('transfer(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED'); } function safeTransferFrom(address token, address from, address to, uint value) internal { // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED'); } function safeTransferETH(address to, uint value) internal { (bool success,) = to.call{value:value}(new bytes(0)); require(success, 'TransferHelper: ETH_TRANSFER_FAILED'); } } /** * @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]; } } abstract contract Ownable { address internal _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ /* will use initialize instead constructor () { _owner = msg.sender; emit OwnershipTransferred(address(0), msg.sender); } */ /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == msg.sender, "Ownable: caller is not the owner"); _; } } contract CallistoBridge is Ownable { using TransferHelper for address; using EnumerableSet for EnumerableSet.AddressSet; EnumerableSet.AddressSet authorities; // authority has to sign claim transaction (message) address constant MAX_NATIVE_COINS = address(31); // addresses from address(1) to MAX_NATIVE_COINS are considered as native coins // CLO = address(1) struct Token { address token; // foreign token address bool isWrapped; // is native token wrapped of foreign } struct Upgrade { address newContract; uint64 validFrom; } uint256 public threshold; // minimum number of signatures required to approve swap address public tokenImplementation; // implementation of wrapped token address public feeTo; // send fee to this address bool public frozen; // if frozen - swap will not work uint256 public wrapNonce; // the last nonce used to create wrapped token address begin with 0xCC.... mapping(uint256 => mapping(bytes32 => bool)) public isTxProcessed; // chainID => txID => isProcessed mapping(uint256 => mapping(address => Token)) public tokenPair; // chainID => native token address => Token struct mapping(uint256 => mapping(address => address)) public tokenForeign; // chainID => foreign token address => native token mapping(address => uint256) public tokenDeposits; // amount of tokens were deposited by users mapping(address => bool) public isFreezer; // addresses that have right to freeze contract uint256 public setupMode; // time when setup mode will start, 0 if disable Upgrade public upgradeData; address public founders; address public requiredAuthority; // authority address that MUST sign swap transaction mapping(address => address) public migration; // migration oldToken => newToken bool public migrationSetupForbidden; // forbid adding migration tokens address public contractCaller; // intermediate contract that calls third-party contract functions (toContract) uint256 public functionMapping; // bitmap of locked functions (one bit per function) event SetAuthority(address authority, bool isEnable); event SetFeeTo(address previousFeeTo, address newFeeTo); event SetThreshold(uint256 threshold); event SetContractCaller(address newContractCaller); event Deposit(address indexed token, address indexed sender, uint256 value, uint256 toChainId, address toToken); event Claim(address indexed token, address indexed to, uint256 value, bytes32 txId, uint256 fromChainId, address fromToken); event Fee(address indexed sender, uint256 fee); event CreatePair(address toToken, bool isWrapped, address fromToken, uint256 fromChainId); event Frozen(bool status); event RescuedERC20(address token, address to, uint256 value); event SetFreezer(address freezer, bool isActive); event SetupMode(uint time); event UpgradeRequest(address newContract, uint256 validFrom); event AddTokenMigration(address tokenFrom, address tokenTo); event BridgeToContract(address indexed token, address indexed sender, uint256 value, uint256 toChainId, address toToken, address toContract, bytes data); event ClaimToContract(address indexed token, address indexed to, uint256 value, bytes32 txId, uint256 fromChainId, address fromToken, address toContract); // run only once from proxy function initialize(address newOwner, address newFounders, address _tokenImplementation) external { require(newOwner != address(0) && newFounders != address(0) && founders == address(0)); // run only once _owner = newOwner; founders = newFounders; emit OwnershipTransferred(address(0), msg.sender); require(_tokenImplementation != address(0), "Wrong tokenImplementation"); tokenImplementation = _tokenImplementation; feeTo = msg.sender; threshold = 1; setupMode = 1; // allow setup after deployment } /* constructor (address _tokenImplementation) { require(_tokenImplementation != address(0), "Wrong tokenImplementation"); tokenImplementation = _tokenImplementation; feeTo = msg.sender; threshold = 1; } */ modifier notFrozen() { require(!frozen, "Bridge is frozen"); _; } // allowed only in setup mode modifier onlySetup() { uint256 mode = setupMode; //use local variable to save gas require(mode != 0 && mode < block.timestamp, "Not in setup mode"); _; } function upgradeTo() external view returns(address newContract) { Upgrade memory upg = upgradeData; require(upg.validFrom < block.timestamp && upg.newContract != address(0), "Upgrade not allowed"); newContract = upg.newContract; } function requestUpgrade(address newContract) external onlyOwner { require(newContract != address(0), "Zero address"); uint256 validFrom = block.timestamp + 3 days; upgradeData = Upgrade(newContract, uint64(validFrom)); emit UpgradeRequest(newContract, validFrom); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public { require(founders == msg.sender, "Ownable: caller is not the founders"); require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } function ChangeFounder(address newFounders) public { require(founders == msg.sender, "caller is not the founders"); require(newFounders != address(0), "new owner is the zero address"); emit OwnershipTransferred(founders, newFounders); founders = newFounders; } // get number of authorities function getAuthoritiesNumber() external view returns(uint256) { return authorities.length(); } // returns list of authorities addresses function getAuthorities() external view returns(address[] memory) { return authorities._values; } // Owner or Authority may freeze bridge in case of anomaly detection function freeze() external { require(msg.sender == owner() || authorities.contains(msg.sender) || isFreezer[msg.sender]); frozen = true; emit Frozen(true); } // Only owner can manually unfreeze contract function unfreeze() external onlyOwner onlySetup { frozen = false; emit Frozen(false); } function lockFunctions(uint256 _functionMapping) external onlyOwner { functionMapping = _functionMapping; } // add authority function setFreezer(address freezer, bool isActive) external onlyOwner { require(freezer != address(0), "Zero address"); isFreezer[freezer] = isActive; emit SetFreezer(freezer, isActive); } // add authority function addAuthority(address authority) external onlyOwner onlySetup { require(authority != address(0), "Zero address"); require(authorities.length() < 255, "Too many authorities"); require(authorities.add(authority), "Authority already added"); emit SetAuthority(authority, true); } // remove authority function removeAuthority(address authority) external onlyOwner { require(authorities.remove(authority), "Authority does not exist"); emit SetAuthority(authority, false); } // set authority address that MUST sign claim request function setRequiredAuthority(address authority) external onlyOwner onlySetup { requiredAuthority = authority; } // set fee receiver address function setFeeTo(address newFeeTo) external onlyOwner onlySetup { require(newFeeTo != address(0), "Zero address"); address previousFeeTo = feeTo; feeTo = newFeeTo; emit SetFeeTo(previousFeeTo, newFeeTo); } // set threshold - minimum number of signatures required to approve swap function setThreshold(uint256 _threshold) external onlyOwner onlySetup { require(threshold != 0 && threshold <= authorities.length(), "Wrong threshold"); threshold = _threshold; emit SetThreshold(threshold); } // set contractCaller address function setContractCaller(address newContractCaller) external onlyOwner onlySetup { contractCaller = newContractCaller; emit SetContractCaller(newContractCaller); } function disableSetupMode() external onlyOwner { setupMode = 0; emit SetupMode(0); } function enableSetupMode() external onlyOwner { setupMode = block.timestamp + 1 days; emit SetupMode(setupMode); } // returns `nonce` to use in `createWrappedToken()` to create address starting with 0xCC..... function calculateNonce() external view returns(uint256 nonce, address addr) { nonce = wrapNonce; address implementation = tokenImplementation; while (true) { nonce++; addr = Clones.predictDeterministicAddress(implementation, bytes32(nonce)); if (uint160(addr) & uint160(0xfF00000000000000000000000000000000000000) == uint160(0xCc00000000000000000000000000000000000000)) break; } } function rescueERC20(address token, address to) external onlyOwner { uint256 value = IERC223TokenCloned(token).balanceOf(address(this)) - tokenDeposits[token]; token.safeTransfer(to, value); emit RescuedERC20(token, to, value); } // Create wrapped token for foreign token function createWrappedToken( address fromToken, // foreign token address uint256 fromChainId, // foreign chain ID where token deployed string memory name, // wrapped token name string memory symbol, // wrapped token symbol uint8 decimals, // wrapped token decimals (should be the same as in original token) uint256 nonce // nonce to create wrapped token address begin with 0xCC.... ) external onlyOwner onlySetup { require(fromToken != address(0), "Wrong token address"); require(tokenForeign[fromChainId][fromToken] == address(0), "This token already wrapped"); require(nonce > wrapNonce, "Nonce must be higher then wrapNonce"); wrapNonce = nonce; address wrappedToken = Clones.cloneDeterministic(tokenImplementation, bytes32(nonce)); IERC223TokenCloned(wrappedToken).initialize(owner(), name, symbol, decimals); tokenPair[fromChainId][wrappedToken] = Token(fromToken, true); tokenForeign[fromChainId][fromToken] = wrappedToken; emit CreatePair(wrappedToken, true, fromToken, fromChainId); //wrappedToken - wrapped token contract address } /** * @dev Create pair between existing tokens on native and foreign chains * @param toToken token address on native chain * @param fromToken token address on foreign chain * @param fromChainId foreign chain ID * @param isWrapped `true` if `toToken` is our wrapped token otherwise `false` */ function createPair(address toToken, address fromToken, uint256 fromChainId, bool isWrapped) external onlyOwner onlySetup { require(tokenPair[fromChainId][toToken].token == address(0), "Pair already exist"); tokenPair[fromChainId][toToken] = Token(fromToken, isWrapped); tokenForeign[fromChainId][fromToken] = toToken; emit CreatePair(toToken, isWrapped, fromToken, fromChainId); } /** * @dev Delete unused pair * @param toToken token address on native chain * @param fromChainId foreign chain ID */ function deletePair(address toToken, uint256 fromChainId) external onlyOwner onlySetup { delete tokenPair[fromChainId][toToken]; } // Move tokens through the bridge and call the contract with 'data' parameters on the destination chain function bridgeToContract( address receiver, // address of token receiver on destination chain address token, // token that user send (if token address < 32, then send native coin) uint256 value, // tokens value uint256 toChainId, // destination chain Id where will be claimed tokens address toContract, // this contract will be called on destination chain bytes memory data // this data will be passed to contract call (ABI encoded parameters) ) external payable notFrozen { require(functionMapping & 2 == 0, "locked"); // check bit 1 require(receiver != address(0), "Incorrect receiver address"); address pair_token = _deposit(token, value, toChainId); if (token == address(0xbf6c50889d3a620eb42C0F188b65aDe90De958c4) && // BUSDT token on the Callisto chain pair_token == address(0xdAC17F958D2ee523a2206206994597C13D831ec7) && // USDT token on the ETH chain toChainId == 1 ) // destination is ETH chain { // Since USDT token on ETH chain has 6 decimals we have to convert 18 decimals of BUSDT to 6 decimals value = value / 10**12; } emit BridgeToContract(token, receiver, value, toChainId, pair_token, toContract, data); } // Claim tokens from the bridge and call the contract with 'data' parameters function claimToContract( address token, // token to receive bytes32 txId, // deposit transaction hash on fromChain address to, // user address uint256 value, // value of tokens uint256 fromChainId, // chain ID where user deposited address toContract, // this contract will be called on destination chain bytes memory data, // this data will be passed to contract call (ABI encoded parameters) bytes[] memory sig // authority signatures ) external payable notFrozen { require(functionMapping & 4 == 0, "locked"); // check bit 2 require(!isTxProcessed[fromChainId][txId], "Transaction already processed"); Token memory pair = tokenPair[fromChainId][token]; require(pair.token != address(0), "There is no pair"); { isTxProcessed[fromChainId][txId] = true; // Check signature address must = requiredAuthority; bytes32 messageHash = keccak256(abi.encodePacked(token, to, value, txId, fromChainId, block.chainid, toContract, data)); messageHash = prefixed(messageHash); uint256 uniqSig; uint256 set; // maximum number of authorities is 255 for (uint i = 0; i < sig.length; i++) { address authority = recoverSigner(messageHash, sig[i]); if (authority == must) must = address(0); uint256 index = authorities.indexOf(authority); uint256 mask = 1 << index; if (index != 0 && (set & mask) == 0 ) { set |= mask; uniqSig++; } } require(threshold <= uniqSig, "Require more signatures"); require(must == address(0), "The required authority does not sign"); } // fix decimals for USDT on ETH if (token == address(0xbf6c50889d3a620eb42C0F188b65aDe90De958c4) && // BUSDT token on the Callisto chain pair.token == address(0xdAC17F958D2ee523a2206206994597C13D831ec7) && // USDT token on the ETH chain fromChainId == 1 ) // from ETH chain { // Since USDT token on ETH chain has 6 decimals we have to convert 6 decimals to 18 decimals of BUSDT value = value * 10**12; } if (msg.value != 0) to.safeTransferETH(msg.value); // send CLO to user as bonus // Call toContract if(isContract(toContract) && toContract != address(this)) { if (token <= MAX_NATIVE_COINS) { IContractCaller(contractCaller).callContract{value: value}(to, token, value, toContract, data); } else { if(pair.isWrapped) { IERC223TokenCloned(token).mint(contractCaller, value); } else { tokenDeposits[token] -= value; token.safeTransfer(contractCaller, value); } IContractCaller(contractCaller).callContract(to, token, value, toContract, data); } } else { // if not contract if (token <= MAX_NATIVE_COINS) { to.safeTransferETH(value); } else { if(pair.isWrapped) { IERC223TokenCloned(token).mint(to, value); } else { tokenDeposits[token] -= value; token.safeTransfer(to, value); } } } emit ClaimToContract(token, to, value, txId, fromChainId, pair.token, toContract); } // Due to issue in Callisto Explorer when createPair with isWrapped = 0 it sends transaction with isWrapped = 1 // It makes this pair unusable without chance to fix it. // function reversIsWrapped allow to reverse isWrapped value function reversIsWrapped(address toToken, uint256 fromChainId) external onlyOwner onlySetup { bool isWrapped = tokenPair[fromChainId][toToken].isWrapped; tokenPair[fromChainId][toToken].isWrapped = !isWrapped; } function depositTokens( address receiver, // address of token receiver on destination chain address token, // token that user send (if token address < 32, then send native coin) uint256 value, // tokens value uint256 toChainId // destination chain Id where will be claimed tokens ) external payable notFrozen { require(functionMapping & 1 == 0, "locked"); // check bit 0 require(receiver != address(0), "Incorrect receiver address"); address pair_token = _deposit(token, value, toChainId); if (token == address(0xbf6c50889d3a620eb42C0F188b65aDe90De958c4) && // BUSDT token on the Callisto chain pair_token == address(0xdAC17F958D2ee523a2206206994597C13D831ec7) && // USDT token on the ETH chain toChainId == 1 ) // destination is ETH chain { // Since USDT token on ETH chain has 6 decimals we have to convert 18 decimals of BUSDT to 6 decimals value = value / 10**12; } emit Deposit(token, receiver, value, toChainId, pair_token); } function depositTokens( address token, // token that user send (if token address < 32, then send native coin) uint256 value, // tokens value uint256 toChainId // destination chain Id where will be claimed tokens ) external payable notFrozen { address pair_token = _deposit(token, value, toChainId); if (token == address(0xbf6c50889d3a620eb42C0F188b65aDe90De958c4) && // BUSDT token on the Callisto chain pair_token == address(0xdAC17F958D2ee523a2206206994597C13D831ec7) && // USDT token on the ETH chain toChainId == 1 ) // destination is ETH chain { // Since USDT token on ETH chain has 6 decimals we have to convert 18 decimals of BUSDT to 6 decimals value = value / 10**12; } emit Deposit(token, msg.sender, value, toChainId, pair_token); } // ERC223 token transfer callback // bytes _data = abi.encode(address receiver, uint256 toChainId) function tokenReceived(address _from, uint _value, bytes calldata _data) external { require(_data.length == 64, "Incorrect _data"); ( address receiver, // address of token receiver on destination chain uint256 toChainId // destination chain Id where will be claimed tokens ) = abi.decode(_data, (address, uint256)); require(receiver != address(0), "Incorrect receiver address"); address token = msg.sender; Token memory pair = tokenPair[toChainId][token]; require(pair.token != address(0), "There is no pair"); if(pair.isWrapped) { IERC223TokenCloned(token).burn(_value); } else { tokenDeposits[token] += _value; } emit Deposit(token, receiver, _value, toChainId, pair.token); } // migrate from ERC20 to ERC223 function migrate(address token, uint value) external { address newToken = migration[token]; require(newToken != address(0), "No migration token"); IERC223TokenCloned(token).burnFrom(msg.sender, value); IERC223TokenCloned(newToken).mint(msg.sender, value); } /* // setup token migration function setupTokenMigration(address tokenFrom, address tokenTo) external onlyOwner onlySetup { require(!migrationSetupForbidden); // assign tokenImplementation here to avoid creation unnecessary function tokenImplementation = address(0x4320e2310274dF1C1A46319044286389C6D16987); // ERC223 token implementation. migration[tokenFrom] = tokenTo; emit AddTokenMigration(tokenFrom, tokenTo); } // forbid setup token migration function forbidMigrationSetup() external onlyOwner onlySetup { migrationSetupForbidden = true; } */ function _deposit( address token, // token that user send (if token address < 32, then send native coin) uint256 value, // tokens value uint256 toChainId // destination chain Id where will be claimed tokens ) internal returns (address pair_token) { Token memory pair = tokenPair[toChainId][token]; require(pair.token != address(0), "There is no pair"); pair_token = pair.token; uint256 fee = msg.value; if (token <= MAX_NATIVE_COINS) { require(value <= msg.value, "Wrong value"); fee -= value; } else { if(pair.isWrapped) { IERC223TokenCloned(token).burnFrom(msg.sender, value); } else { tokenDeposits[token] += value; token.safeTransferFrom(msg.sender, address(this), value); } } if (fee != 0) { feeTo.safeTransferETH(fee); emit Fee(msg.sender, fee); } } // claim function claim( address token, // token to receive bytes32 txId, // deposit transaction hash on fromChain address to, // user address uint256 value, // value of tokens uint256 fromChainId, // chain ID where user deposited bytes[] memory sig // authority signatures ) external notFrozen { require(!isTxProcessed[fromChainId][txId], "Transaction already processed"); Token memory pair = tokenPair[fromChainId][token]; require(pair.token != address(0), "There is no pair"); isTxProcessed[fromChainId][txId] = true; address must = requiredAuthority; bytes32 messageHash = keccak256(abi.encodePacked(token, to, value, txId, fromChainId, block.chainid)); messageHash = prefixed(messageHash); uint256 uniqSig; uint256 set; // maximum number of authorities is 255 for (uint i = 0; i < sig.length; i++) { address authority = recoverSigner(messageHash, sig[i]); if (authority == must) must = address(0); uint256 index = authorities.indexOf(authority); uint256 mask = 1 << index; if (index != 0 && (set & mask) == 0 ) { set |= mask; uniqSig++; } } require(threshold <= uniqSig, "Require more signatures"); require(must == address(0), "The required authority does not sign"); if (token == address(0xbf6c50889d3a620eb42C0F188b65aDe90De958c4) && // BUSDT token on the Callisto chain pair.token == address(0xdAC17F958D2ee523a2206206994597C13D831ec7) && // USDT token on the ETH chain fromChainId == 1 ) // from ETH chain { // Since USDT token on ETH chain has 6 decimals we have to convert 6 decimals to 18 decimals of BUSDT value = value * 10**12; } if (token <= MAX_NATIVE_COINS) { to.safeTransferETH(value); } else { if(pair.isWrapped) { IERC223TokenCloned(token).mint(to, value); } else { tokenDeposits[token] -= value; token.safeTransfer(to, value); } } emit Claim(token, to, value, txId, fromChainId, pair.token); } // Signature methods function splitSignature(bytes memory sig) internal pure returns (uint8 v, bytes32 r, bytes32 s) { require(sig.length == 65); assembly { // first 32 bytes, after the length prefix r := mload(add(sig, 32)) // second 32 bytes s := mload(add(sig, 64)) // final byte (first byte of the next 32 bytes) v := byte(0, mload(add(sig, 96))) } } function recoverSigner(bytes32 message, bytes memory sig) internal pure returns (address) { uint8 v; bytes32 r; bytes32 s; (v, r, s) = splitSignature(sig); return ecrecover(message, v, r, s); } // Builds a prefixed hash to mimic the behavior of eth_sign. function prefixed(bytes32 hash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } function isContract(address account) internal view returns (bool) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } }
Contract ABI
[{"type":"event","name":"AddTokenMigration","inputs":[{"type":"address","name":"tokenFrom","internalType":"address","indexed":false},{"type":"address","name":"tokenTo","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"BridgeToContract","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"uint256","name":"toChainId","internalType":"uint256","indexed":false},{"type":"address","name":"toToken","internalType":"address","indexed":false},{"type":"address","name":"toContract","internalType":"address","indexed":false},{"type":"bytes","name":"data","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"Claim","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"bytes32","name":"txId","internalType":"bytes32","indexed":false},{"type":"uint256","name":"fromChainId","internalType":"uint256","indexed":false},{"type":"address","name":"fromToken","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"ClaimToContract","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"bytes32","name":"txId","internalType":"bytes32","indexed":false},{"type":"uint256","name":"fromChainId","internalType":"uint256","indexed":false},{"type":"address","name":"fromToken","internalType":"address","indexed":false},{"type":"address","name":"toContract","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"CreatePair","inputs":[{"type":"address","name":"toToken","internalType":"address","indexed":false},{"type":"bool","name":"isWrapped","internalType":"bool","indexed":false},{"type":"address","name":"fromToken","internalType":"address","indexed":false},{"type":"uint256","name":"fromChainId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Deposit","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"uint256","name":"toChainId","internalType":"uint256","indexed":false},{"type":"address","name":"toToken","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Fee","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":true},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Frozen","inputs":[{"type":"bool","name":"status","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RescuedERC20","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"address","name":"to","internalType":"address","indexed":false},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetAuthority","inputs":[{"type":"address","name":"authority","internalType":"address","indexed":false},{"type":"bool","name":"isEnable","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetContractCaller","inputs":[{"type":"address","name":"newContractCaller","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SetFeeTo","inputs":[{"type":"address","name":"previousFeeTo","internalType":"address","indexed":false},{"type":"address","name":"newFeeTo","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SetFreezer","inputs":[{"type":"address","name":"freezer","internalType":"address","indexed":false},{"type":"bool","name":"isActive","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetThreshold","inputs":[{"type":"uint256","name":"threshold","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetupMode","inputs":[{"type":"uint256","name":"time","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UpgradeRequest","inputs":[{"type":"address","name":"newContract","internalType":"address","indexed":false},{"type":"uint256","name":"validFrom","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"ChangeFounder","inputs":[{"type":"address","name":"newFounders","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addAuthority","inputs":[{"type":"address","name":"authority","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"bridgeToContract","inputs":[{"type":"address","name":"receiver","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"toChainId","internalType":"uint256"},{"type":"address","name":"toContract","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"address","name":"addr","internalType":"address"}],"name":"calculateNonce","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claim","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"bytes32","name":"txId","internalType":"bytes32"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"fromChainId","internalType":"uint256"},{"type":"bytes[]","name":"sig","internalType":"bytes[]"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"claimToContract","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"bytes32","name":"txId","internalType":"bytes32"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"fromChainId","internalType":"uint256"},{"type":"address","name":"toContract","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"bytes[]","name":"sig","internalType":"bytes[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"contractCaller","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"createPair","inputs":[{"type":"address","name":"toToken","internalType":"address"},{"type":"address","name":"fromToken","internalType":"address"},{"type":"uint256","name":"fromChainId","internalType":"uint256"},{"type":"bool","name":"isWrapped","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"createWrappedToken","inputs":[{"type":"address","name":"fromToken","internalType":"address"},{"type":"uint256","name":"fromChainId","internalType":"uint256"},{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"symbol","internalType":"string"},{"type":"uint8","name":"decimals","internalType":"uint8"},{"type":"uint256","name":"nonce","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deletePair","inputs":[{"type":"address","name":"toToken","internalType":"address"},{"type":"uint256","name":"fromChainId","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"depositTokens","inputs":[{"type":"address","name":"receiver","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"toChainId","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"depositTokens","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"toChainId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"disableSetupMode","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"enableSetupMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feeTo","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"founders","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"freeze","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"frozen","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"functionMapping","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getAuthorities","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAuthoritiesNumber","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"newOwner","internalType":"address"},{"type":"address","name":"newFounders","internalType":"address"},{"type":"address","name":"_tokenImplementation","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isFreezer","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isTxProcessed","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"lockFunctions","inputs":[{"type":"uint256","name":"_functionMapping","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"migrate","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"migration","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"migrationSetupForbidden","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeAuthority","inputs":[{"type":"address","name":"authority","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"requestUpgrade","inputs":[{"type":"address","name":"newContract","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"requiredAuthority","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescueERC20","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"address","name":"to","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"reversIsWrapped","inputs":[{"type":"address","name":"toToken","internalType":"address"},{"type":"uint256","name":"fromChainId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setContractCaller","inputs":[{"type":"address","name":"newContractCaller","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeTo","inputs":[{"type":"address","name":"newFeeTo","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFreezer","inputs":[{"type":"address","name":"freezer","internalType":"address"},{"type":"bool","name":"isActive","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRequiredAuthority","inputs":[{"type":"address","name":"authority","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setThreshold","inputs":[{"type":"uint256","name":"_threshold","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"setupMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"threshold","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenDeposits","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"tokenForeign","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"tokenImplementation","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"token","internalType":"address"},{"type":"bool","name":"isWrapped","internalType":"bool"}],"name":"tokenPair","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"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":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unfreeze","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"newContract","internalType":"address"},{"type":"uint64","name":"validFrom","internalType":"uint64"}],"name":"upgradeData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"newContract","internalType":"address"}],"name":"upgradeTo","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"wrapNonce","inputs":[]}]
Contract Creation Code
0x608060405234801561001057600080fd5b506144ec806100206000396000f3fe6080604052600436106102e45760003560e01c80636b9f97ef11610190578063c21b4865116100dc578063db43968811610095578063f0f201271161006f578063f0f2012714610935578063f2fde38b14610955578063f46901ed14610975578063fa0876711461099557600080fd5b8063db439688146108ba578063df42fd36146108cd578063e6074da71461090857600080fd5b8063c21b4865146107f1578063c987c79414610813578063cda7f83f14610833578063cea9e11014610865578063d04567f314610885578063d544e0101461089a57600080fd5b8063960bfe0411610149578063ad68ebf711610123578063ad68ebf714610771578063b2e916d614610791578063bfd06304146107b1578063c0c53b8b146107d157600080fd5b8063960bfe041461071b578063a02a66ec1461073b578063abb718631461075b57600080fd5b80636b9f97ef146106585780636c65fd6a146106785780638943ec02146106a85780638da5cb5b146106c85780638f715701146106e65780638f995234146106fb57600080fd5b8063411b007e1161024f5780635c5b9f8f1161020857806362a5af3b116101e257806362a5af3b146105de578063685e2486146105f35780636a28f000146106295780636adf74121461063e57600080fd5b80635c5b9f8f1461058b5780635d799f871461059e5780635e14e319146105be57600080fd5b8063411b007e146104f457806342cde4e81461051457806344ddcb601461052a578063487cda0d1461053d5780634dead7321461055057806354cf428a1461056657600080fd5b806326defa73116102a157806326defa73146103f35780632a94a9c8146104135780632b1a7b58146104335780632f3a3d5d1461049f5780633af84ac4146104bf5780633cbdef56146104d457600080fd5b8063017e7e58146102e9578063054f7d9c1461032657806313bf81261461035757806316a27ecd1461037b57806318d27b04146103905780631c673ab8146103b2575b600080fd5b3480156102f557600080fd5b50600554610309906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561033257600080fd5b5060055461034790600160a01b900460ff1681565b604051901515815260200161031d565b34801561036357600080fd5b5061036d600c5481565b60405190815260200161031d565b34801561038757600080fd5b506103096109f0565b34801561039c57600080fd5b506103b06103ab366004613f91565b610a89565b005b3480156103be57600080fd5b506103096103cd366004613fc3565b60096020908152600092835260408084209091529082529020546001600160a01b031681565b3480156103ff57600080fd5b506103b061040e366004613ace565b610ac7565b34801561041f57600080fd5b506103b061042e366004613ace565b610c40565b34801561043f57600080fd5b5061048061044e366004613fc3565b60086020908152600092835260408084209091529082529020546001600160a01b03811690600160a01b900460ff1682565b604080516001600160a01b03909316835290151560208301520161031d565b3480156104ab57600080fd5b50600454610309906001600160a01b031681565b3480156104cb57600080fd5b5061036d610cfc565b3480156104e057600080fd5b506103b06104ef366004613ace565b610d0c565b34801561050057600080fd5b50600e54610309906001600160a01b031681565b34801561052057600080fd5b5061036d60035481565b6103b0610538366004613c34565b610e18565b6103b061054b366004613bee565b610f61565b34801561055c57600080fd5b5061036d60125481565b34801561057257600080fd5b506011546103099061010090046001600160a01b031681565b6103b0610599366004613f3f565b6110a6565b3480156105aa57600080fd5b506103b06105b9366004613b17565b61119f565b3480156105ca57600080fd5b506103b06105d9366004613cbb565b6112d2565b3480156105ea57600080fd5b506103b061138d565b3480156105ff57600080fd5b5061030961060e366004613ace565b6010602052600090815260409020546001600160a01b031681565b34801561063557600080fd5b506103b0611421565b34801561064a57600080fd5b506011546103479060ff1681565b34801561066457600080fd5b506103b0610673366004613ace565b6114cc565b34801561068457600080fd5b50610347610693366004613ace565b600b6020526000908152604090205460ff1681565b3480156106b457600080fd5b506103b06106c3366004613e13565b6115b7565b3480156106d457600080fd5b506000546001600160a01b0316610309565b3480156106f257600080fd5b506103b06117ab565b34801561070757600080fd5b506103b0610716366004613da2565b611826565b34801561072757600080fd5b506103b0610736366004613f91565b611c8d565b34801561074757600080fd5b506103b0610756366004613ace565b611d7b565b34801561076757600080fd5b5061036d60065481565b34801561077d57600080fd5b506103b061078c366004613aeb565b611e04565b34801561079d57600080fd5b506103b06107ac366004613b9b565b611f47565b3480156107bd57600080fd5b506103b06107cc366004613e9c565b6120e3565b3480156107dd57600080fd5b506103b06107ec366004613b50565b612468565b3480156107fd57600080fd5b5061080661258a565b60405161031d9190614151565b34801561081f57600080fd5b506103b061082e366004613aeb565b6125ef565b34801561083f57600080fd5b50610848612698565b604080519283526001600160a01b0390911660208301520161031d565b34801561087157600080fd5b506103b0610880366004613aeb565b6126e1565b34801561089157600080fd5b506103b061277a565b3480156108a657600080fd5b506103b06108b5366004613ace565b6127ea565b6103b06108c8366004613ce9565b6128b9565b3480156108d957600080fd5b506103476108e8366004613fe8565b600760209081526000928352604080842090915290825290205460ff1681565b34801561091457600080fd5b5061036d610923366004613ace565b600a6020526000908152604090205481565b34801561094157600080fd5b50600f54610309906001600160a01b031681565b34801561096157600080fd5b506103b0610970366004613ace565b612eda565b34801561098157600080fd5b506103b0610990366004613ace565b613000565b3480156109a157600080fd5b50600d546109c8906001600160a01b03811690600160a01b900467ffffffffffffffff1682565b604080516001600160a01b03909316835267ffffffffffffffff90911660208301520161031d565b60408051808201909152600d546001600160a01b0381168252600160a01b900467ffffffffffffffff16602082018190526000919042118015610a3c575080516001600160a01b031615155b610a835760405162461bcd60e51b8152602060048201526013602482015272155c19dc985919481b9bdd08185b1b1bddd959606a1b60448201526064015b60405180910390fd5b51919050565b33610a9c6000546001600160a01b031690565b6001600160a01b031614610ac25760405162461bcd60e51b8152600401610a7a90614287565b601255565b33610ada6000546001600160a01b031690565b6001600160a01b031614610b005760405162461bcd60e51b8152600401610a7a90614287565b600c548015801590610b1157504281105b610b2d5760405162461bcd60e51b8152600401610a7a9061420c565b6001600160a01b038216610b535760405162461bcd60e51b8152600401610a7a90614237565b60ff610b5e60015490565b10610ba25760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610a7a565b610bad6001836130e6565b610bf95760405162461bcd60e51b815260206004820152601760248201527f417574686f7269747920616c72656164792061646465640000000000000000006044820152606401610a7a565b604080516001600160a01b0384168152600160208201527f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c36199391015b60405180910390a15050565b33610c536000546001600160a01b031690565b6001600160a01b031614610c795760405162461bcd60e51b8152600401610a7a90614287565b600c548015801590610c8a57504281105b610ca65760405162461bcd60e51b8152600401610a7a9061420c565b60118054610100600160a81b0319166101006001600160a01b038516908102919091179091556040519081527f850b65e0a4a0af8155b0d56212b309166a3618bcd7ba7c1e83f09f3e721f294c90602001610c34565b6000610d0760015490565b905090565b600e546001600160a01b03163314610d665760405162461bcd60e51b815260206004820152601a60248201527f63616c6c6572206973206e6f742074686520666f756e646572730000000000006044820152606401610a7a565b6001600160a01b038116610dbc5760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610a7a565b600e546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600e80546001600160a01b0319166001600160a01b0392909216919091179055565b600554600160a01b900460ff1615610e425760405162461bcd60e51b8152600401610a7a906141e2565b60125460021615610e655760405162461bcd60e51b8152600401610a7a906142bc565b6001600160a01b038616610e8b5760405162461bcd60e51b8152600401610a7a906142dc565b6000610e9886868661315a565b90506001600160a01b03861673bf6c50889d3a620eb42c0f188b65ade90de958c4148015610ee257506001600160a01b03811673dac17f958d2ee523a2206206994597c13d831ec7145b8015610eee5750836001145b15610f0557610f0264e8d4a5100086614395565b94505b866001600160a01b0316866001600160a01b03167f8e3af9ffa3a105195ae58520a6e3ab241268521cd0a0ca519896e650d4fbebe48787858888604051610f50959493929190614313565b60405180910390a350505050505050565b600554600160a01b900460ff1615610f8b5760405162461bcd60e51b8152600401610a7a906141e2565b60125460011615610fae5760405162461bcd60e51b8152600401610a7a906142bc565b6001600160a01b038416610fd45760405162461bcd60e51b8152600401610a7a906142dc565b6000610fe184848461315a565b90506001600160a01b03841673bf6c50889d3a620eb42c0f188b65ade90de958c414801561102b57506001600160a01b03811673dac17f958d2ee523a2206206994597c13d831ec7145b80156110375750816001145b1561104e5761104b64e8d4a5100084614395565b92505b60408051848152602081018490526001600160a01b03838116828401529151878316928716917ff5dd9317b9e63ac316ce44acc85f670b54b339cfa3e9076e1dd55065b922314b919081900360600190a35050505050565b600554600160a01b900460ff16156110d05760405162461bcd60e51b8152600401610a7a906141e2565b60006110dd84848461315a565b90506001600160a01b03841673bf6c50889d3a620eb42c0f188b65ade90de958c414801561112757506001600160a01b03811673dac17f958d2ee523a2206206994597c13d831ec7145b80156111335750816001145b1561114a5761114764e8d4a5100084614395565b92505b60408051848152602081018490526001600160a01b0383811682840152915133928716917ff5dd9317b9e63ac316ce44acc85f670b54b339cfa3e9076e1dd55065b922314b919081900360600190a350505050565b336111b26000546001600160a01b031690565b6001600160a01b0316146111d85760405162461bcd60e51b8152600401610a7a90614287565b6001600160a01b0382166000818152600a60205260408082205490516370a0823160e01b8152306004820152919290916370a082319060240160206040518083038186803b15801561122957600080fd5b505afa15801561123d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112619190613faa565b61126b91906143d6565b90506112816001600160a01b0384168383613351565b604080516001600160a01b038086168252841660208201529081018290527f2c5650189f92c7058626efc371b51fe7e71f37dacb696bc7cad0b1320931974a906060015b60405180910390a1505050565b336112e56000546001600160a01b031690565b6001600160a01b03161461130b5760405162461bcd60e51b8152600401610a7a90614287565b6001600160a01b0382166113315760405162461bcd60e51b8152600401610a7a90614237565b6001600160a01b0382166000818152600b6020908152604091829020805460ff19168515159081179091558251938452908301527feabe320fe7911eab2e5125ac393caa5937659b712f0c3ac43316c61d4bc088019101610c34565b6000546001600160a01b03163314806113b457503360009081526002602052604090205415155b806113ce5750336000908152600b602052604090205460ff165b6113d757600080fd5b6005805460ff60a01b1916600160a01b179055604051600181527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a1565b336114346000546001600160a01b031690565b6001600160a01b03161461145a5760405162461bcd60e51b8152600401610a7a90614287565b600c54801580159061146b57504281105b6114875760405162461bcd60e51b8152600401610a7a9061420c565b6005805460ff60a01b19169055604051600081527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a150565b336114df6000546001600160a01b031690565b6001600160a01b0316146115055760405162461bcd60e51b8152600401610a7a90614287565b6001600160a01b03811661152b5760405162461bcd60e51b8152600401610a7a90614237565b600061153a426203f48061437d565b6040805180820182526001600160a01b03851680825267ffffffffffffffff84166020928301819052600d80546001600160e01b0319168317600160a01b90920291909117905582519081529081018390529192507fd990f8f4f90cd3307c50ab3d095cfb65516e999b7584aee60c0af83eb48118de9101610c34565b604081146115f95760405162461bcd60e51b815260206004820152600f60248201526e496e636f7272656374205f6461746160881b6044820152606401610a7a565b60008061160883850185613aeb565b90925090506001600160a01b0382166116335760405162461bcd60e51b8152600401610a7a906142dc565b600081815260086020908152604080832033808552908352928190208151808301909252546001600160a01b038116808352600160a01b90910460ff16151592820192909252906116965760405162461bcd60e51b8152600401610a7a9061425d565b80602001511561172057604051630852cd8d60e31b8152600481018890526001600160a01b038316906342966c6890602401602060405180830381600087803b1580156116e257600080fd5b505af11580156116f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171a9190613f74565b5061174e565b6001600160a01b0382166000908152600a60205260408120805489929061174890849061437d565b90915550505b805160408051898152602081018690526001600160a01b03928316818301529051868316928516917ff5dd9317b9e63ac316ce44acc85f670b54b339cfa3e9076e1dd55065b922314b919081900360600190a35050505050505050565b336117be6000546001600160a01b031690565b6001600160a01b0316146117e45760405162461bcd60e51b8152600401610a7a90614287565b6117f1426201518061437d565b600c8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611417565b600554600160a01b900460ff16156118505760405162461bcd60e51b8152600401610a7a906141e2565b600082815260076020908152604080832088845290915290205460ff16156118ba5760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a7a565b60008281526008602090815260408083206001600160a01b038a8116855290835292819020815180830190925254928316808252600160a01b90930460ff161515918101919091529061191f5760405162461bcd60e51b8152600401610a7a9061425d565b60008381526007602090815260408083208984528252808320805460ff19166001179055600f54905160608b811b6bffffffffffffffffffffffff199081169483019490945289901b90921660348301526048820187905260688201899052608882018690524660a88301526001600160a01b0316919060c8016040516020818303038152906040528051906020012090506119ba8161346c565b905060008060005b8651811015611a6a5760006119f0858984815181106119e3576119e3614464565b60200260200101516134bf565b9050856001600160a01b0316816001600160a01b03161415611a1157600095505b6001600160a01b0381166000908152600260205260409020546001811b8115801590611a3d5750848116155b15611a54579384179385611a508161441d565b9650505b5050508080611a629061441d565b9150506119c2565b50816003541115611ab75760405162461bcd60e51b815260206004820152601760248201527652657175697265206d6f7265207369676e61747572657360481b6044820152606401610a7a565b6001600160a01b03841615611ade5760405162461bcd60e51b8152600401610a7a9061419e565b6001600160a01b038b1673bf6c50889d3a620eb42c0f188b65ade90de958c4148015611b27575084516001600160a01b031673dac17f958d2ee523a2206206994597c13d831ec7145b8015611b335750866001145b15611b4a57611b478864e8d4a510006143b7565b97505b601f6001600160a01b038c1611611b7357611b6e6001600160a01b038a168961353e565b611c26565b846020015115611be4576040516340c10f1960e01b81526001600160a01b038a81166004830152602482018a90528c16906340c10f1990604401600060405180830381600087803b158015611bc757600080fd5b505af1158015611bdb573d6000803e3d6000fd5b50505050611c26565b6001600160a01b038b166000908152600a6020526040812080548a9290611c0c9084906143d6565b90915550611c2690506001600160a01b038c168a8a613351565b8451604080518a8152602081018d90529081018990526001600160a01b039182166060820152818b16918d16907fc9e45b9f44cc745053533754942aa17989494514aeadbb624b4b5e34a0ce5fc29060800160405180910390a35050505050505050505050565b33611ca06000546001600160a01b031690565b6001600160a01b031614611cc65760405162461bcd60e51b8152600401610a7a90614287565b600c548015801590611cd757504281105b611cf35760405162461bcd60e51b8152600401610a7a9061420c565b60035415801590611d08575060015460035411155b611d465760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610a7a565b60038290556040518281527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf90602001610c34565b33611d8e6000546001600160a01b031690565b6001600160a01b031614611db45760405162461bcd60e51b8152600401610a7a90614287565b600c548015801590611dc557504281105b611de15760405162461bcd60e51b8152600401610a7a9061420c565b50600f80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038083166000908152601060205260409020541680611e615760405162461bcd60e51b815260206004820152601260248201527127379036b4b3b930ba34b7b7103a37b5b2b760711b6044820152606401610a7a565b60405163079cc67960e41b8152336004820152602481018390526001600160a01b038416906379cc679090604401602060405180830381600087803b158015611ea957600080fd5b505af1158015611ebd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee19190613f74565b506040516340c10f1960e01b8152336004820152602481018390526001600160a01b038216906340c10f1990604401600060405180830381600087803b158015611f2a57600080fd5b505af1158015611f3e573d6000803e3d6000fd5b50505050505050565b33611f5a6000546001600160a01b031690565b6001600160a01b031614611f805760405162461bcd60e51b8152600401610a7a90614287565b600c548015801590611f9157504281105b611fad5760405162461bcd60e51b8152600401610a7a9061420c565b60008381526008602090815260408083206001600160a01b03898116855292529091205416156120145760405162461bcd60e51b815260206004820152601260248201527114185a5c88185b1c9958591e48195e1a5cdd60721b6044820152606401610a7a565b6040805180820182526001600160a01b03868116808352851515602080850182815260008a8152600883528781208d87168083529084528882209751885493511515600160a01b026001600160a81b0319909416971696909617919091179095558885526009815285852083865281529385902080546001600160a01b0319168417905584519283529282019290925291820152606081018490527f4e37907d987e2429cd26da336a410ffe2d567dc727ed293e6c500023525af2959060800160405180910390a15050505050565b336120f66000546001600160a01b031690565b6001600160a01b03161461211c5760405162461bcd60e51b8152600401610a7a90614287565b600c54801580159061212d57504281105b6121495760405162461bcd60e51b8152600401610a7a9061420c565b6001600160a01b0387166121955760405162461bcd60e51b815260206004820152601360248201527257726f6e6720746f6b656e206164647265737360681b6044820152606401610a7a565b60008681526009602090815260408083206001600160a01b038b8116855292529091205416156122075760405162461bcd60e51b815260206004820152601a60248201527f5468697320746f6b656e20616c726561647920777261707065640000000000006044820152606401610a7a565b60065482116122645760405162461bcd60e51b815260206004820152602360248201527f4e6f6e6365206d75737420626520686967686572207468656e20777261704e6f6044820152626e636560e81b6064820152608401610a7a565b6006829055600454600090612282906001600160a01b03168461360c565b9050806001600160a01b031663f6d2ee866122a56000546001600160a01b031690565b8888886040518563ffffffff1660e01b81526004016122c79493929190614106565b600060405180830381600087803b1580156122e157600080fd5b505af11580156122f5573d6000803e3d6000fd5b505050506040518060400160405280896001600160a01b0316815260200160011515815250600860008981526020019081526020016000206000836001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548160ff021916908315150217905550905050806009600089815260200190815260200160002060008a6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055507f4e37907d987e2429cd26da336a410ffe2d567dc727ed293e6c500023525af2958160018a8a60405161245694939291906001600160a01b039485168152921515602084015292166040820152606081019190915260800190565b60405180910390a15050505050505050565b6001600160a01b0383161580159061248857506001600160a01b03821615155b801561249d5750600e546001600160a01b0316155b6124a657600080fd5b600080546001600160a01b038086166001600160a01b0319928316178355600e8054918616919092161790556040513391907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a36001600160a01b0381166125535760405162461bcd60e51b815260206004820152601960248201527f57726f6e6720746f6b656e496d706c656d656e746174696f6e000000000000006044820152606401610a7a565b600480546001600160a01b039092166001600160a01b03199283161790556005805490911633179055505060016003819055600c55565b606060016000018054806020026020016040519081016040528092919081815260200182805480156125e557602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116125c7575b5050505050905090565b336126026000546001600160a01b031690565b6001600160a01b0316146126285760405162461bcd60e51b8152600401610a7a90614287565b600c54801580159061263957504281105b6126555760405162461bcd60e51b8152600401610a7a9061420c565b5060009081526008602090815260408083206001600160a01b0394909416835292905220805460ff60a01b198116600160a01b9182900460ff1615909102179055565b6006546004546000906001600160a01b03165b826126b58161441d565b93506126c3905081846136ac565b915060ff60981b82166033609a1b14156126dc57509091565b6126ab565b336126f46000546001600160a01b031690565b6001600160a01b03161461271a5760405162461bcd60e51b8152600401610a7a90614287565b600c54801580159061272b57504281105b6127475760405162461bcd60e51b8152600401610a7a9061420c565b5060009081526008602090815260408083206001600160a01b0390941683529290522080546001600160a81b0319169055565b3361278d6000546001600160a01b031690565b6001600160a01b0316146127b35760405162461bcd60e51b8152600401610a7a90614287565b6000600c8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611417565b336127fd6000546001600160a01b031690565b6001600160a01b0316146128235760405162461bcd60e51b8152600401610a7a90614287565b61282e600182613719565b61287a5760405162461bcd60e51b815260206004820152601860248201527f417574686f7269747920646f6573206e6f7420657869737400000000000000006044820152606401610a7a565b604080516001600160a01b0383168152600060208201527f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c36199391016114c1565b600554600160a01b900460ff16156128e35760405162461bcd60e51b8152600401610a7a906141e2565b601254600416156129065760405162461bcd60e51b8152600401610a7a906142bc565b60008481526007602090815260408083208a845290915290205460ff16156129705760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a7a565b60008481526008602090815260408083206001600160a01b038c8116855290835292819020815180830190925254928316808252600160a01b90930460ff16151591810191909152906129d55760405162461bcd60e51b8152600401610a7a9061425d565b60008581526007602090815260408083208b84528252808320805460ff19166001179055600f5490516001600160a01b039091169291612a25918d918c918c918f918d9146918e918e9101614036565b604051602081830303815290604052805190602001209050612a468161346c565b905060008060005b8651811015612ae9576000612a6f858984815181106119e3576119e3614464565b9050856001600160a01b0316816001600160a01b03161415612a9057600095505b6001600160a01b0381166000908152600260205260409020546001811b8115801590612abc5750848116155b15612ad3579384179385612acf8161441d565b9650505b5050508080612ae19061441d565b915050612a4e565b50816003541115612b365760405162461bcd60e51b815260206004820152601760248201527652657175697265206d6f7265207369676e61747572657360481b6044820152606401610a7a565b6001600160a01b03841615612b5d5760405162461bcd60e51b8152600401610a7a9061419e565b505050506001600160a01b03891673bf6c50889d3a620eb42c0f188b65ade90de958c4148015612baa575080516001600160a01b031673dac17f958d2ee523a2206206994597c13d831ec7145b8015612bb65750846001145b15612bcd57612bca8664e8d4a510006143b7565b95505b3415612be657612be66001600160a01b0388163461353e565b833b15158015612bff57506001600160a01b0384163014155b15612dc357601f6001600160a01b038a1611612c8a57601154604051631490ba2d60e31b81526101009091046001600160a01b03169063a485d168908890612c53908b908e9084908b908b906004016140c0565b6000604051808303818588803b158015612c6c57600080fd5b505af1158015612c80573d6000803e3d6000fd5b5050505050612e6d565b806020015115612d04576011546040516340c10f1960e01b81526101009091046001600160a01b039081166004830152602482018890528a16906340c10f1990604401600060405180830381600087803b158015612ce757600080fd5b505af1158015612cfb573d6000803e3d6000fd5b50505050612d50565b6001600160a01b0389166000908152600a602052604081208054889290612d2c9084906143d6565b9091555050601154612d50906001600160a01b038b81169161010090041688613351565b601154604051631490ba2d60e31b81526101009091046001600160a01b03169063a485d16890612d8c908a908d908b908a908a906004016140c0565b600060405180830381600087803b158015612da657600080fd5b505af1158015612dba573d6000803e3d6000fd5b50505050612e6d565b601f6001600160a01b038a1611612dec57612de76001600160a01b0388168761353e565b612e6d565b806020015115612e2b576040516340c10f1960e01b81526001600160a01b038881166004830152602482018890528a16906340c10f1990604401612d8c565b6001600160a01b0389166000908152600a602052604081208054889290612e539084906143d6565b90915550612e6d90506001600160a01b038a168888613351565b805160408051888152602081018b90529081018790526001600160a01b0391821660608201528582166080820152818916918b16907f28c02ecb5177e8f760c85b230b3c9ca9529c7412274a05918bfe438f55dd46429060a00160405180910390a3505050505050505050565b600e546001600160a01b03163314612f405760405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f742074686520666f756e6460448201526265727360e81b6064820152608401610a7a565b6001600160a01b038116612fa55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a7a565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b336130136000546001600160a01b031690565b6001600160a01b0316146130395760405162461bcd60e51b8152600401610a7a90614287565b600c54801580159061304a57504281105b6130665760405162461bcd60e51b8152600401610a7a9061420c565b6001600160a01b03821661308c5760405162461bcd60e51b8152600401610a7a90614237565b600580546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca491016112c5565b6001600160a01b038116600090815260018301602052604081205461315057508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155613154565b5060005b92915050565b60008181526008602090815260408083206001600160a01b038781168552908352818420825180840190935254908116808352600160a01b90910460ff16151592820192909252906131be5760405162461bcd60e51b8152600401610a7a9061425d565b8051915034601f6001600160a01b0387161161322357348511156132125760405162461bcd60e51b815260206004820152600b60248201526a57726f6e672076616c756560a81b6044820152606401610a7a565b61321c85826143d6565b90506132f6565b8160200151156132b35760405163079cc67960e41b8152336004820152602481018690526001600160a01b038716906379cc679090604401602060405180830381600087803b15801561327557600080fd5b505af1158015613289573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132ad9190613f74565b506132f6565b6001600160a01b0386166000908152600a6020526040812080548792906132db90849061437d565b909155506132f690506001600160a01b03871633308861385b565b801561334857600554613312906001600160a01b03168261353e565b60405181815233907f7bd3aa7d673767f759ebf216e7f6c12844986c661ae6e0f1d988cf7eb7394d1d9060200160405180910390a25b50509392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916133ad91906140a4565b6000604051808303816000865af19150503d80600081146133ea576040519150601f19603f3d011682016040523d82523d6000602084013e6133ef565b606091505b50915091508180156134195750805115806134195750808060200190518101906134199190613f74565b6134655760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610a7a565b5050505050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b6000806000806134ce8561398b565b6040805160008152602081018083528b905260ff8516918101919091526060810183905260808101829052929550909350915060019060a0016020604051602081039080840390855afa158015613529573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b604080516000808252602082019092526001600160a01b03841690839060405161356891906140a4565b60006040518083038185875af1925050503d80600081146135a5576040519150601f19603f3d011682016040523d82523d6000602084013e6135aa565b606091505b50509050806136075760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610a7a565b505050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b0381166131545760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610a7a565b6000613712838330604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b8152606093841b60148201526f5af43d82803e903d91602b57fd5bf3ff60801b6028820152921b6038830152604c8201526037808220606c830152605591012090565b9392505050565b6001600160a01b038116600090815260018301602052604081205480156138515760006137476001836143d6565b855490915060009061375b906001906143d6565b9050600086600001828154811061377457613774614464565b60009182526020909120015487546001600160a01b03909116915081908890859081106137a3576137a3614464565b600091825260209091200180546001600160a01b0319166001600160a01b03929092169190911790556137d783600161437d565b6001600160a01b038216600090815260018901602052604090205586548790806138035761380361444e565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506131549350505050565b6000915050613154565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916138bf91906140a4565b6000604051808303816000865af19150503d80600081146138fc576040519150601f19603f3d011682016040523d82523d6000602084013e613901565b606091505b509150915081801561392b57508051158061392b57508080602001905181019061392b9190613f74565b6139835760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610a7a565b505050505050565b6000806000835160411461399e57600080fd5b5050506020810151604082015160609092015160001a92909190565b600082601f8301126139cb57600080fd5b8135602067ffffffffffffffff808311156139e8576139e861447a565b8260051b6139f783820161434c565b8481528381019087850183890186018a1015613a1257600080fd5b60009350835b87811015613a4f57813586811115613a2e578586fd5b613a3c8c89838e0101613a5e565b8552509286019290860190600101613a18565b50909998505050505050505050565b600082601f830112613a6f57600080fd5b813567ffffffffffffffff811115613a8957613a8961447a565b613a9c601f8201601f191660200161434c565b818152846020838601011115613ab157600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613ae057600080fd5b813561371281614490565b60008060408385031215613afe57600080fd5b8235613b0981614490565b946020939093013593505050565b60008060408385031215613b2a57600080fd5b8235613b3581614490565b91506020830135613b4581614490565b809150509250929050565b600080600060608486031215613b6557600080fd5b8335613b7081614490565b92506020840135613b8081614490565b91506040840135613b9081614490565b809150509250925092565b60008060008060808587031215613bb157600080fd5b8435613bbc81614490565b93506020850135613bcc81614490565b9250604085013591506060850135613be3816144a8565b939692955090935050565b60008060008060808587031215613c0457600080fd5b8435613c0f81614490565b93506020850135613c1f81614490565b93969395505050506040820135916060013590565b60008060008060008060c08789031215613c4d57600080fd5b8635613c5881614490565b95506020870135613c6881614490565b945060408701359350606087013592506080870135613c8681614490565b915060a087013567ffffffffffffffff811115613ca257600080fd5b613cae89828a01613a5e565b9150509295509295509295565b60008060408385031215613cce57600080fd5b8235613cd981614490565b91506020830135613b45816144a8565b600080600080600080600080610100898b031215613d0657600080fd5b8835613d1181614490565b9750602089013596506040890135613d2881614490565b9550606089013594506080890135935060a0890135613d4681614490565b925060c089013567ffffffffffffffff80821115613d6357600080fd5b613d6f8c838d01613a5e565b935060e08b0135915080821115613d8557600080fd5b50613d928b828c016139ba565b9150509295985092959890939650565b60008060008060008060c08789031215613dbb57600080fd5b8635613dc681614490565b9550602087013594506040870135613ddd81614490565b9350606087013592506080870135915060a087013567ffffffffffffffff811115613e0757600080fd5b613cae89828a016139ba565b60008060008060608587031215613e2957600080fd5b8435613e3481614490565b935060208501359250604085013567ffffffffffffffff80821115613e5857600080fd5b818701915087601f830112613e6c57600080fd5b813581811115613e7b57600080fd5b886020828501011115613e8d57600080fd5b95989497505060200194505050565b60008060008060008060c08789031215613eb557600080fd5b8635613ec081614490565b955060208701359450604087013567ffffffffffffffff80821115613ee457600080fd5b613ef08a838b01613a5e565b95506060890135915080821115613f0657600080fd5b50613f1389828a01613a5e565b935050608087013560ff81168114613f2a57600080fd5b8092505060a087013590509295509295509295565b600080600060608486031215613f5457600080fd5b8335613f5f81614490565b95602085013595506040909401359392505050565b600060208284031215613f8657600080fd5b8151613712816144a8565b600060208284031215613fa357600080fd5b5035919050565b600060208284031215613fbc57600080fd5b5051919050565b60008060408385031215613fd657600080fd5b823591506020830135613b4581614490565b60008060408385031215613ffb57600080fd5b50508035926020909101359150565b600081518084526140228160208601602086016143ed565b601f01601f19169290920160200192915050565b60006bffffffffffffffffffffffff19808b60601b168352808a60601b166014840152886028840152876048840152866068840152856088840152808560601b1660a88401525082516140908160bc8501602087016143ed565b9190910160bc019998505050505050505050565b600082516140b68184602087016143ed565b9190910192915050565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a0608082018190526000906140fb9083018461400a565b979650505050505050565b6001600160a01b038516815260806020820181905260009061412a9083018661400a565b828103604084015261413c818661400a565b91505060ff8316606083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156141925783516001600160a01b03168352928401929184019160010161416d565b50909695505050505050565b60208082526024908201527f54686520726571756972656420617574686f7269747920646f6573206e6f742060408201526339b4b3b760e11b606082015260800190565b60208082526010908201526f213934b233b29034b990333937bd32b760811b604082015260600190565b6020808252601190820152704e6f7420696e207365747570206d6f646560781b604082015260600190565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b60208082526010908201526f2a3432b9329034b9903737903830b4b960811b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252600690820152651b1bd8dad95960d21b604082015260600190565b6020808252601a908201527f496e636f72726563742072656365697665722061646472657373000000000000604082015260600190565b858152602081018590526001600160a01b0384811660408301528316606082015260a0608082018190526000906140fb9083018461400a565b604051601f8201601f1916810167ffffffffffffffff811182821017156143755761437561447a565b604052919050565b6000821982111561439057614390614438565b500190565b6000826143b257634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156143d1576143d1614438565b500290565b6000828210156143e8576143e8614438565b500390565b60005b838110156144085781810151838201526020016143f0565b83811115614417576000848401525b50505050565b600060001982141561443157614431614438565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146144a557600080fd5b50565b80151581146144a557600080fdfea2646970667358221220c754242ef14fc5391e99bf5373eea3041adc0aaedc01346f940786d4a5d23f7864736f6c63430008070033
Deployed ByteCode
0x6080604052600436106102e45760003560e01c80636b9f97ef11610190578063c21b4865116100dc578063db43968811610095578063f0f201271161006f578063f0f2012714610935578063f2fde38b14610955578063f46901ed14610975578063fa0876711461099557600080fd5b8063db439688146108ba578063df42fd36146108cd578063e6074da71461090857600080fd5b8063c21b4865146107f1578063c987c79414610813578063cda7f83f14610833578063cea9e11014610865578063d04567f314610885578063d544e0101461089a57600080fd5b8063960bfe0411610149578063ad68ebf711610123578063ad68ebf714610771578063b2e916d614610791578063bfd06304146107b1578063c0c53b8b146107d157600080fd5b8063960bfe041461071b578063a02a66ec1461073b578063abb718631461075b57600080fd5b80636b9f97ef146106585780636c65fd6a146106785780638943ec02146106a85780638da5cb5b146106c85780638f715701146106e65780638f995234146106fb57600080fd5b8063411b007e1161024f5780635c5b9f8f1161020857806362a5af3b116101e257806362a5af3b146105de578063685e2486146105f35780636a28f000146106295780636adf74121461063e57600080fd5b80635c5b9f8f1461058b5780635d799f871461059e5780635e14e319146105be57600080fd5b8063411b007e146104f457806342cde4e81461051457806344ddcb601461052a578063487cda0d1461053d5780634dead7321461055057806354cf428a1461056657600080fd5b806326defa73116102a157806326defa73146103f35780632a94a9c8146104135780632b1a7b58146104335780632f3a3d5d1461049f5780633af84ac4146104bf5780633cbdef56146104d457600080fd5b8063017e7e58146102e9578063054f7d9c1461032657806313bf81261461035757806316a27ecd1461037b57806318d27b04146103905780631c673ab8146103b2575b600080fd5b3480156102f557600080fd5b50600554610309906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561033257600080fd5b5060055461034790600160a01b900460ff1681565b604051901515815260200161031d565b34801561036357600080fd5b5061036d600c5481565b60405190815260200161031d565b34801561038757600080fd5b506103096109f0565b34801561039c57600080fd5b506103b06103ab366004613f91565b610a89565b005b3480156103be57600080fd5b506103096103cd366004613fc3565b60096020908152600092835260408084209091529082529020546001600160a01b031681565b3480156103ff57600080fd5b506103b061040e366004613ace565b610ac7565b34801561041f57600080fd5b506103b061042e366004613ace565b610c40565b34801561043f57600080fd5b5061048061044e366004613fc3565b60086020908152600092835260408084209091529082529020546001600160a01b03811690600160a01b900460ff1682565b604080516001600160a01b03909316835290151560208301520161031d565b3480156104ab57600080fd5b50600454610309906001600160a01b031681565b3480156104cb57600080fd5b5061036d610cfc565b3480156104e057600080fd5b506103b06104ef366004613ace565b610d0c565b34801561050057600080fd5b50600e54610309906001600160a01b031681565b34801561052057600080fd5b5061036d60035481565b6103b0610538366004613c34565b610e18565b6103b061054b366004613bee565b610f61565b34801561055c57600080fd5b5061036d60125481565b34801561057257600080fd5b506011546103099061010090046001600160a01b031681565b6103b0610599366004613f3f565b6110a6565b3480156105aa57600080fd5b506103b06105b9366004613b17565b61119f565b3480156105ca57600080fd5b506103b06105d9366004613cbb565b6112d2565b3480156105ea57600080fd5b506103b061138d565b3480156105ff57600080fd5b5061030961060e366004613ace565b6010602052600090815260409020546001600160a01b031681565b34801561063557600080fd5b506103b0611421565b34801561064a57600080fd5b506011546103479060ff1681565b34801561066457600080fd5b506103b0610673366004613ace565b6114cc565b34801561068457600080fd5b50610347610693366004613ace565b600b6020526000908152604090205460ff1681565b3480156106b457600080fd5b506103b06106c3366004613e13565b6115b7565b3480156106d457600080fd5b506000546001600160a01b0316610309565b3480156106f257600080fd5b506103b06117ab565b34801561070757600080fd5b506103b0610716366004613da2565b611826565b34801561072757600080fd5b506103b0610736366004613f91565b611c8d565b34801561074757600080fd5b506103b0610756366004613ace565b611d7b565b34801561076757600080fd5b5061036d60065481565b34801561077d57600080fd5b506103b061078c366004613aeb565b611e04565b34801561079d57600080fd5b506103b06107ac366004613b9b565b611f47565b3480156107bd57600080fd5b506103b06107cc366004613e9c565b6120e3565b3480156107dd57600080fd5b506103b06107ec366004613b50565b612468565b3480156107fd57600080fd5b5061080661258a565b60405161031d9190614151565b34801561081f57600080fd5b506103b061082e366004613aeb565b6125ef565b34801561083f57600080fd5b50610848612698565b604080519283526001600160a01b0390911660208301520161031d565b34801561087157600080fd5b506103b0610880366004613aeb565b6126e1565b34801561089157600080fd5b506103b061277a565b3480156108a657600080fd5b506103b06108b5366004613ace565b6127ea565b6103b06108c8366004613ce9565b6128b9565b3480156108d957600080fd5b506103476108e8366004613fe8565b600760209081526000928352604080842090915290825290205460ff1681565b34801561091457600080fd5b5061036d610923366004613ace565b600a6020526000908152604090205481565b34801561094157600080fd5b50600f54610309906001600160a01b031681565b34801561096157600080fd5b506103b0610970366004613ace565b612eda565b34801561098157600080fd5b506103b0610990366004613ace565b613000565b3480156109a157600080fd5b50600d546109c8906001600160a01b03811690600160a01b900467ffffffffffffffff1682565b604080516001600160a01b03909316835267ffffffffffffffff90911660208301520161031d565b60408051808201909152600d546001600160a01b0381168252600160a01b900467ffffffffffffffff16602082018190526000919042118015610a3c575080516001600160a01b031615155b610a835760405162461bcd60e51b8152602060048201526013602482015272155c19dc985919481b9bdd08185b1b1bddd959606a1b60448201526064015b60405180910390fd5b51919050565b33610a9c6000546001600160a01b031690565b6001600160a01b031614610ac25760405162461bcd60e51b8152600401610a7a90614287565b601255565b33610ada6000546001600160a01b031690565b6001600160a01b031614610b005760405162461bcd60e51b8152600401610a7a90614287565b600c548015801590610b1157504281105b610b2d5760405162461bcd60e51b8152600401610a7a9061420c565b6001600160a01b038216610b535760405162461bcd60e51b8152600401610a7a90614237565b60ff610b5e60015490565b10610ba25760405162461bcd60e51b8152602060048201526014602482015273546f6f206d616e7920617574686f72697469657360601b6044820152606401610a7a565b610bad6001836130e6565b610bf95760405162461bcd60e51b815260206004820152601760248201527f417574686f7269747920616c72656164792061646465640000000000000000006044820152606401610a7a565b604080516001600160a01b0384168152600160208201527f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c36199391015b60405180910390a15050565b33610c536000546001600160a01b031690565b6001600160a01b031614610c795760405162461bcd60e51b8152600401610a7a90614287565b600c548015801590610c8a57504281105b610ca65760405162461bcd60e51b8152600401610a7a9061420c565b60118054610100600160a81b0319166101006001600160a01b038516908102919091179091556040519081527f850b65e0a4a0af8155b0d56212b309166a3618bcd7ba7c1e83f09f3e721f294c90602001610c34565b6000610d0760015490565b905090565b600e546001600160a01b03163314610d665760405162461bcd60e51b815260206004820152601a60248201527f63616c6c6572206973206e6f742074686520666f756e646572730000000000006044820152606401610a7a565b6001600160a01b038116610dbc5760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610a7a565b600e546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600e80546001600160a01b0319166001600160a01b0392909216919091179055565b600554600160a01b900460ff1615610e425760405162461bcd60e51b8152600401610a7a906141e2565b60125460021615610e655760405162461bcd60e51b8152600401610a7a906142bc565b6001600160a01b038616610e8b5760405162461bcd60e51b8152600401610a7a906142dc565b6000610e9886868661315a565b90506001600160a01b03861673bf6c50889d3a620eb42c0f188b65ade90de958c4148015610ee257506001600160a01b03811673dac17f958d2ee523a2206206994597c13d831ec7145b8015610eee5750836001145b15610f0557610f0264e8d4a5100086614395565b94505b866001600160a01b0316866001600160a01b03167f8e3af9ffa3a105195ae58520a6e3ab241268521cd0a0ca519896e650d4fbebe48787858888604051610f50959493929190614313565b60405180910390a350505050505050565b600554600160a01b900460ff1615610f8b5760405162461bcd60e51b8152600401610a7a906141e2565b60125460011615610fae5760405162461bcd60e51b8152600401610a7a906142bc565b6001600160a01b038416610fd45760405162461bcd60e51b8152600401610a7a906142dc565b6000610fe184848461315a565b90506001600160a01b03841673bf6c50889d3a620eb42c0f188b65ade90de958c414801561102b57506001600160a01b03811673dac17f958d2ee523a2206206994597c13d831ec7145b80156110375750816001145b1561104e5761104b64e8d4a5100084614395565b92505b60408051848152602081018490526001600160a01b03838116828401529151878316928716917ff5dd9317b9e63ac316ce44acc85f670b54b339cfa3e9076e1dd55065b922314b919081900360600190a35050505050565b600554600160a01b900460ff16156110d05760405162461bcd60e51b8152600401610a7a906141e2565b60006110dd84848461315a565b90506001600160a01b03841673bf6c50889d3a620eb42c0f188b65ade90de958c414801561112757506001600160a01b03811673dac17f958d2ee523a2206206994597c13d831ec7145b80156111335750816001145b1561114a5761114764e8d4a5100084614395565b92505b60408051848152602081018490526001600160a01b0383811682840152915133928716917ff5dd9317b9e63ac316ce44acc85f670b54b339cfa3e9076e1dd55065b922314b919081900360600190a350505050565b336111b26000546001600160a01b031690565b6001600160a01b0316146111d85760405162461bcd60e51b8152600401610a7a90614287565b6001600160a01b0382166000818152600a60205260408082205490516370a0823160e01b8152306004820152919290916370a082319060240160206040518083038186803b15801561122957600080fd5b505afa15801561123d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112619190613faa565b61126b91906143d6565b90506112816001600160a01b0384168383613351565b604080516001600160a01b038086168252841660208201529081018290527f2c5650189f92c7058626efc371b51fe7e71f37dacb696bc7cad0b1320931974a906060015b60405180910390a1505050565b336112e56000546001600160a01b031690565b6001600160a01b03161461130b5760405162461bcd60e51b8152600401610a7a90614287565b6001600160a01b0382166113315760405162461bcd60e51b8152600401610a7a90614237565b6001600160a01b0382166000818152600b6020908152604091829020805460ff19168515159081179091558251938452908301527feabe320fe7911eab2e5125ac393caa5937659b712f0c3ac43316c61d4bc088019101610c34565b6000546001600160a01b03163314806113b457503360009081526002602052604090205415155b806113ce5750336000908152600b602052604090205460ff165b6113d757600080fd5b6005805460ff60a01b1916600160a01b179055604051600181527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a1565b336114346000546001600160a01b031690565b6001600160a01b03161461145a5760405162461bcd60e51b8152600401610a7a90614287565b600c54801580159061146b57504281105b6114875760405162461bcd60e51b8152600401610a7a9061420c565b6005805460ff60a01b19169055604051600081527f59800d968fcce138300a0019410b4b75041610d65b3cdc5f31656b03ed14912e906020015b60405180910390a150565b336114df6000546001600160a01b031690565b6001600160a01b0316146115055760405162461bcd60e51b8152600401610a7a90614287565b6001600160a01b03811661152b5760405162461bcd60e51b8152600401610a7a90614237565b600061153a426203f48061437d565b6040805180820182526001600160a01b03851680825267ffffffffffffffff84166020928301819052600d80546001600160e01b0319168317600160a01b90920291909117905582519081529081018390529192507fd990f8f4f90cd3307c50ab3d095cfb65516e999b7584aee60c0af83eb48118de9101610c34565b604081146115f95760405162461bcd60e51b815260206004820152600f60248201526e496e636f7272656374205f6461746160881b6044820152606401610a7a565b60008061160883850185613aeb565b90925090506001600160a01b0382166116335760405162461bcd60e51b8152600401610a7a906142dc565b600081815260086020908152604080832033808552908352928190208151808301909252546001600160a01b038116808352600160a01b90910460ff16151592820192909252906116965760405162461bcd60e51b8152600401610a7a9061425d565b80602001511561172057604051630852cd8d60e31b8152600481018890526001600160a01b038316906342966c6890602401602060405180830381600087803b1580156116e257600080fd5b505af11580156116f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171a9190613f74565b5061174e565b6001600160a01b0382166000908152600a60205260408120805489929061174890849061437d565b90915550505b805160408051898152602081018690526001600160a01b03928316818301529051868316928516917ff5dd9317b9e63ac316ce44acc85f670b54b339cfa3e9076e1dd55065b922314b919081900360600190a35050505050505050565b336117be6000546001600160a01b031690565b6001600160a01b0316146117e45760405162461bcd60e51b8152600401610a7a90614287565b6117f1426201518061437d565b600c8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611417565b600554600160a01b900460ff16156118505760405162461bcd60e51b8152600401610a7a906141e2565b600082815260076020908152604080832088845290915290205460ff16156118ba5760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a7a565b60008281526008602090815260408083206001600160a01b038a8116855290835292819020815180830190925254928316808252600160a01b90930460ff161515918101919091529061191f5760405162461bcd60e51b8152600401610a7a9061425d565b60008381526007602090815260408083208984528252808320805460ff19166001179055600f54905160608b811b6bffffffffffffffffffffffff199081169483019490945289901b90921660348301526048820187905260688201899052608882018690524660a88301526001600160a01b0316919060c8016040516020818303038152906040528051906020012090506119ba8161346c565b905060008060005b8651811015611a6a5760006119f0858984815181106119e3576119e3614464565b60200260200101516134bf565b9050856001600160a01b0316816001600160a01b03161415611a1157600095505b6001600160a01b0381166000908152600260205260409020546001811b8115801590611a3d5750848116155b15611a54579384179385611a508161441d565b9650505b5050508080611a629061441d565b9150506119c2565b50816003541115611ab75760405162461bcd60e51b815260206004820152601760248201527652657175697265206d6f7265207369676e61747572657360481b6044820152606401610a7a565b6001600160a01b03841615611ade5760405162461bcd60e51b8152600401610a7a9061419e565b6001600160a01b038b1673bf6c50889d3a620eb42c0f188b65ade90de958c4148015611b27575084516001600160a01b031673dac17f958d2ee523a2206206994597c13d831ec7145b8015611b335750866001145b15611b4a57611b478864e8d4a510006143b7565b97505b601f6001600160a01b038c1611611b7357611b6e6001600160a01b038a168961353e565b611c26565b846020015115611be4576040516340c10f1960e01b81526001600160a01b038a81166004830152602482018a90528c16906340c10f1990604401600060405180830381600087803b158015611bc757600080fd5b505af1158015611bdb573d6000803e3d6000fd5b50505050611c26565b6001600160a01b038b166000908152600a6020526040812080548a9290611c0c9084906143d6565b90915550611c2690506001600160a01b038c168a8a613351565b8451604080518a8152602081018d90529081018990526001600160a01b039182166060820152818b16918d16907fc9e45b9f44cc745053533754942aa17989494514aeadbb624b4b5e34a0ce5fc29060800160405180910390a35050505050505050505050565b33611ca06000546001600160a01b031690565b6001600160a01b031614611cc65760405162461bcd60e51b8152600401610a7a90614287565b600c548015801590611cd757504281105b611cf35760405162461bcd60e51b8152600401610a7a9061420c565b60035415801590611d08575060015460035411155b611d465760405162461bcd60e51b815260206004820152600f60248201526e15dc9bdb99c81d1a1c995cda1bdb19608a1b6044820152606401610a7a565b60038290556040518281527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf90602001610c34565b33611d8e6000546001600160a01b031690565b6001600160a01b031614611db45760405162461bcd60e51b8152600401610a7a90614287565b600c548015801590611dc557504281105b611de15760405162461bcd60e51b8152600401610a7a9061420c565b50600f80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038083166000908152601060205260409020541680611e615760405162461bcd60e51b815260206004820152601260248201527127379036b4b3b930ba34b7b7103a37b5b2b760711b6044820152606401610a7a565b60405163079cc67960e41b8152336004820152602481018390526001600160a01b038416906379cc679090604401602060405180830381600087803b158015611ea957600080fd5b505af1158015611ebd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee19190613f74565b506040516340c10f1960e01b8152336004820152602481018390526001600160a01b038216906340c10f1990604401600060405180830381600087803b158015611f2a57600080fd5b505af1158015611f3e573d6000803e3d6000fd5b50505050505050565b33611f5a6000546001600160a01b031690565b6001600160a01b031614611f805760405162461bcd60e51b8152600401610a7a90614287565b600c548015801590611f9157504281105b611fad5760405162461bcd60e51b8152600401610a7a9061420c565b60008381526008602090815260408083206001600160a01b03898116855292529091205416156120145760405162461bcd60e51b815260206004820152601260248201527114185a5c88185b1c9958591e48195e1a5cdd60721b6044820152606401610a7a565b6040805180820182526001600160a01b03868116808352851515602080850182815260008a8152600883528781208d87168083529084528882209751885493511515600160a01b026001600160a81b0319909416971696909617919091179095558885526009815285852083865281529385902080546001600160a01b0319168417905584519283529282019290925291820152606081018490527f4e37907d987e2429cd26da336a410ffe2d567dc727ed293e6c500023525af2959060800160405180910390a15050505050565b336120f66000546001600160a01b031690565b6001600160a01b03161461211c5760405162461bcd60e51b8152600401610a7a90614287565b600c54801580159061212d57504281105b6121495760405162461bcd60e51b8152600401610a7a9061420c565b6001600160a01b0387166121955760405162461bcd60e51b815260206004820152601360248201527257726f6e6720746f6b656e206164647265737360681b6044820152606401610a7a565b60008681526009602090815260408083206001600160a01b038b8116855292529091205416156122075760405162461bcd60e51b815260206004820152601a60248201527f5468697320746f6b656e20616c726561647920777261707065640000000000006044820152606401610a7a565b60065482116122645760405162461bcd60e51b815260206004820152602360248201527f4e6f6e6365206d75737420626520686967686572207468656e20777261704e6f6044820152626e636560e81b6064820152608401610a7a565b6006829055600454600090612282906001600160a01b03168461360c565b9050806001600160a01b031663f6d2ee866122a56000546001600160a01b031690565b8888886040518563ffffffff1660e01b81526004016122c79493929190614106565b600060405180830381600087803b1580156122e157600080fd5b505af11580156122f5573d6000803e3d6000fd5b505050506040518060400160405280896001600160a01b0316815260200160011515815250600860008981526020019081526020016000206000836001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548160ff021916908315150217905550905050806009600089815260200190815260200160002060008a6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055507f4e37907d987e2429cd26da336a410ffe2d567dc727ed293e6c500023525af2958160018a8a60405161245694939291906001600160a01b039485168152921515602084015292166040820152606081019190915260800190565b60405180910390a15050505050505050565b6001600160a01b0383161580159061248857506001600160a01b03821615155b801561249d5750600e546001600160a01b0316155b6124a657600080fd5b600080546001600160a01b038086166001600160a01b0319928316178355600e8054918616919092161790556040513391907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a36001600160a01b0381166125535760405162461bcd60e51b815260206004820152601960248201527f57726f6e6720746f6b656e496d706c656d656e746174696f6e000000000000006044820152606401610a7a565b600480546001600160a01b039092166001600160a01b03199283161790556005805490911633179055505060016003819055600c55565b606060016000018054806020026020016040519081016040528092919081815260200182805480156125e557602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116125c7575b5050505050905090565b336126026000546001600160a01b031690565b6001600160a01b0316146126285760405162461bcd60e51b8152600401610a7a90614287565b600c54801580159061263957504281105b6126555760405162461bcd60e51b8152600401610a7a9061420c565b5060009081526008602090815260408083206001600160a01b0394909416835292905220805460ff60a01b198116600160a01b9182900460ff1615909102179055565b6006546004546000906001600160a01b03165b826126b58161441d565b93506126c3905081846136ac565b915060ff60981b82166033609a1b14156126dc57509091565b6126ab565b336126f46000546001600160a01b031690565b6001600160a01b03161461271a5760405162461bcd60e51b8152600401610a7a90614287565b600c54801580159061272b57504281105b6127475760405162461bcd60e51b8152600401610a7a9061420c565b5060009081526008602090815260408083206001600160a01b0390941683529290522080546001600160a81b0319169055565b3361278d6000546001600160a01b031690565b6001600160a01b0316146127b35760405162461bcd60e51b8152600401610a7a90614287565b6000600c8190556040519081527f14936c23481f8e50ff3a556eb966606eaa9dd8180100eb757f3dccb05eb8af4290602001611417565b336127fd6000546001600160a01b031690565b6001600160a01b0316146128235760405162461bcd60e51b8152600401610a7a90614287565b61282e600182613719565b61287a5760405162461bcd60e51b815260206004820152601860248201527f417574686f7269747920646f6573206e6f7420657869737400000000000000006044820152606401610a7a565b604080516001600160a01b0383168152600060208201527f9019659af698fad527191eef17d6d00706d88aa9fabff25a08edea756c36199391016114c1565b600554600160a01b900460ff16156128e35760405162461bcd60e51b8152600401610a7a906141e2565b601254600416156129065760405162461bcd60e51b8152600401610a7a906142bc565b60008481526007602090815260408083208a845290915290205460ff16156129705760405162461bcd60e51b815260206004820152601d60248201527f5472616e73616374696f6e20616c72656164792070726f6365737365640000006044820152606401610a7a565b60008481526008602090815260408083206001600160a01b038c8116855290835292819020815180830190925254928316808252600160a01b90930460ff16151591810191909152906129d55760405162461bcd60e51b8152600401610a7a9061425d565b60008581526007602090815260408083208b84528252808320805460ff19166001179055600f5490516001600160a01b039091169291612a25918d918c918c918f918d9146918e918e9101614036565b604051602081830303815290604052805190602001209050612a468161346c565b905060008060005b8651811015612ae9576000612a6f858984815181106119e3576119e3614464565b9050856001600160a01b0316816001600160a01b03161415612a9057600095505b6001600160a01b0381166000908152600260205260409020546001811b8115801590612abc5750848116155b15612ad3579384179385612acf8161441d565b9650505b5050508080612ae19061441d565b915050612a4e565b50816003541115612b365760405162461bcd60e51b815260206004820152601760248201527652657175697265206d6f7265207369676e61747572657360481b6044820152606401610a7a565b6001600160a01b03841615612b5d5760405162461bcd60e51b8152600401610a7a9061419e565b505050506001600160a01b03891673bf6c50889d3a620eb42c0f188b65ade90de958c4148015612baa575080516001600160a01b031673dac17f958d2ee523a2206206994597c13d831ec7145b8015612bb65750846001145b15612bcd57612bca8664e8d4a510006143b7565b95505b3415612be657612be66001600160a01b0388163461353e565b833b15158015612bff57506001600160a01b0384163014155b15612dc357601f6001600160a01b038a1611612c8a57601154604051631490ba2d60e31b81526101009091046001600160a01b03169063a485d168908890612c53908b908e9084908b908b906004016140c0565b6000604051808303818588803b158015612c6c57600080fd5b505af1158015612c80573d6000803e3d6000fd5b5050505050612e6d565b806020015115612d04576011546040516340c10f1960e01b81526101009091046001600160a01b039081166004830152602482018890528a16906340c10f1990604401600060405180830381600087803b158015612ce757600080fd5b505af1158015612cfb573d6000803e3d6000fd5b50505050612d50565b6001600160a01b0389166000908152600a602052604081208054889290612d2c9084906143d6565b9091555050601154612d50906001600160a01b038b81169161010090041688613351565b601154604051631490ba2d60e31b81526101009091046001600160a01b03169063a485d16890612d8c908a908d908b908a908a906004016140c0565b600060405180830381600087803b158015612da657600080fd5b505af1158015612dba573d6000803e3d6000fd5b50505050612e6d565b601f6001600160a01b038a1611612dec57612de76001600160a01b0388168761353e565b612e6d565b806020015115612e2b576040516340c10f1960e01b81526001600160a01b038881166004830152602482018890528a16906340c10f1990604401612d8c565b6001600160a01b0389166000908152600a602052604081208054889290612e539084906143d6565b90915550612e6d90506001600160a01b038a168888613351565b805160408051888152602081018b90529081018790526001600160a01b0391821660608201528582166080820152818916918b16907f28c02ecb5177e8f760c85b230b3c9ca9529c7412274a05918bfe438f55dd46429060a00160405180910390a3505050505050505050565b600e546001600160a01b03163314612f405760405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f742074686520666f756e6460448201526265727360e81b6064820152608401610a7a565b6001600160a01b038116612fa55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a7a565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b336130136000546001600160a01b031690565b6001600160a01b0316146130395760405162461bcd60e51b8152600401610a7a90614287565b600c54801580159061304a57504281105b6130665760405162461bcd60e51b8152600401610a7a9061420c565b6001600160a01b03821661308c5760405162461bcd60e51b8152600401610a7a90614237565b600580546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f41d2755f00068d89c23ebc6f1e73ce119a6236a44517ca061f544a3f91c9bca491016112c5565b6001600160a01b038116600090815260018301602052604081205461315057508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155613154565b5060005b92915050565b60008181526008602090815260408083206001600160a01b038781168552908352818420825180840190935254908116808352600160a01b90910460ff16151592820192909252906131be5760405162461bcd60e51b8152600401610a7a9061425d565b8051915034601f6001600160a01b0387161161322357348511156132125760405162461bcd60e51b815260206004820152600b60248201526a57726f6e672076616c756560a81b6044820152606401610a7a565b61321c85826143d6565b90506132f6565b8160200151156132b35760405163079cc67960e41b8152336004820152602481018690526001600160a01b038716906379cc679090604401602060405180830381600087803b15801561327557600080fd5b505af1158015613289573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132ad9190613f74565b506132f6565b6001600160a01b0386166000908152600a6020526040812080548792906132db90849061437d565b909155506132f690506001600160a01b03871633308861385b565b801561334857600554613312906001600160a01b03168261353e565b60405181815233907f7bd3aa7d673767f759ebf216e7f6c12844986c661ae6e0f1d988cf7eb7394d1d9060200160405180910390a25b50509392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916133ad91906140a4565b6000604051808303816000865af19150503d80600081146133ea576040519150601f19603f3d011682016040523d82523d6000602084013e6133ef565b606091505b50915091508180156134195750805115806134195750808060200190518101906134199190613f74565b6134655760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610a7a565b5050505050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b6000806000806134ce8561398b565b6040805160008152602081018083528b905260ff8516918101919091526060810183905260808101829052929550909350915060019060a0016020604051602081039080840390855afa158015613529573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b604080516000808252602082019092526001600160a01b03841690839060405161356891906140a4565b60006040518083038185875af1925050503d80600081146135a5576040519150601f19603f3d011682016040523d82523d6000602084013e6135aa565b606091505b50509050806136075760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610a7a565b505050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b0381166131545760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610a7a565b6000613712838330604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b8152606093841b60148201526f5af43d82803e903d91602b57fd5bf3ff60801b6028820152921b6038830152604c8201526037808220606c830152605591012090565b9392505050565b6001600160a01b038116600090815260018301602052604081205480156138515760006137476001836143d6565b855490915060009061375b906001906143d6565b9050600086600001828154811061377457613774614464565b60009182526020909120015487546001600160a01b03909116915081908890859081106137a3576137a3614464565b600091825260209091200180546001600160a01b0319166001600160a01b03929092169190911790556137d783600161437d565b6001600160a01b038216600090815260018901602052604090205586548790806138035761380361444e565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506131549350505050565b6000915050613154565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916138bf91906140a4565b6000604051808303816000865af19150503d80600081146138fc576040519150601f19603f3d011682016040523d82523d6000602084013e613901565b606091505b509150915081801561392b57508051158061392b57508080602001905181019061392b9190613f74565b6139835760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610a7a565b505050505050565b6000806000835160411461399e57600080fd5b5050506020810151604082015160609092015160001a92909190565b600082601f8301126139cb57600080fd5b8135602067ffffffffffffffff808311156139e8576139e861447a565b8260051b6139f783820161434c565b8481528381019087850183890186018a1015613a1257600080fd5b60009350835b87811015613a4f57813586811115613a2e578586fd5b613a3c8c89838e0101613a5e565b8552509286019290860190600101613a18565b50909998505050505050505050565b600082601f830112613a6f57600080fd5b813567ffffffffffffffff811115613a8957613a8961447a565b613a9c601f8201601f191660200161434c565b818152846020838601011115613ab157600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613ae057600080fd5b813561371281614490565b60008060408385031215613afe57600080fd5b8235613b0981614490565b946020939093013593505050565b60008060408385031215613b2a57600080fd5b8235613b3581614490565b91506020830135613b4581614490565b809150509250929050565b600080600060608486031215613b6557600080fd5b8335613b7081614490565b92506020840135613b8081614490565b91506040840135613b9081614490565b809150509250925092565b60008060008060808587031215613bb157600080fd5b8435613bbc81614490565b93506020850135613bcc81614490565b9250604085013591506060850135613be3816144a8565b939692955090935050565b60008060008060808587031215613c0457600080fd5b8435613c0f81614490565b93506020850135613c1f81614490565b93969395505050506040820135916060013590565b60008060008060008060c08789031215613c4d57600080fd5b8635613c5881614490565b95506020870135613c6881614490565b945060408701359350606087013592506080870135613c8681614490565b915060a087013567ffffffffffffffff811115613ca257600080fd5b613cae89828a01613a5e565b9150509295509295509295565b60008060408385031215613cce57600080fd5b8235613cd981614490565b91506020830135613b45816144a8565b600080600080600080600080610100898b031215613d0657600080fd5b8835613d1181614490565b9750602089013596506040890135613d2881614490565b9550606089013594506080890135935060a0890135613d4681614490565b925060c089013567ffffffffffffffff80821115613d6357600080fd5b613d6f8c838d01613a5e565b935060e08b0135915080821115613d8557600080fd5b50613d928b828c016139ba565b9150509295985092959890939650565b60008060008060008060c08789031215613dbb57600080fd5b8635613dc681614490565b9550602087013594506040870135613ddd81614490565b9350606087013592506080870135915060a087013567ffffffffffffffff811115613e0757600080fd5b613cae89828a016139ba565b60008060008060608587031215613e2957600080fd5b8435613e3481614490565b935060208501359250604085013567ffffffffffffffff80821115613e5857600080fd5b818701915087601f830112613e6c57600080fd5b813581811115613e7b57600080fd5b886020828501011115613e8d57600080fd5b95989497505060200194505050565b60008060008060008060c08789031215613eb557600080fd5b8635613ec081614490565b955060208701359450604087013567ffffffffffffffff80821115613ee457600080fd5b613ef08a838b01613a5e565b95506060890135915080821115613f0657600080fd5b50613f1389828a01613a5e565b935050608087013560ff81168114613f2a57600080fd5b8092505060a087013590509295509295509295565b600080600060608486031215613f5457600080fd5b8335613f5f81614490565b95602085013595506040909401359392505050565b600060208284031215613f8657600080fd5b8151613712816144a8565b600060208284031215613fa357600080fd5b5035919050565b600060208284031215613fbc57600080fd5b5051919050565b60008060408385031215613fd657600080fd5b823591506020830135613b4581614490565b60008060408385031215613ffb57600080fd5b50508035926020909101359150565b600081518084526140228160208601602086016143ed565b601f01601f19169290920160200192915050565b60006bffffffffffffffffffffffff19808b60601b168352808a60601b166014840152886028840152876048840152866068840152856088840152808560601b1660a88401525082516140908160bc8501602087016143ed565b9190910160bc019998505050505050505050565b600082516140b68184602087016143ed565b9190910192915050565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a0608082018190526000906140fb9083018461400a565b979650505050505050565b6001600160a01b038516815260806020820181905260009061412a9083018661400a565b828103604084015261413c818661400a565b91505060ff8316606083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156141925783516001600160a01b03168352928401929184019160010161416d565b50909695505050505050565b60208082526024908201527f54686520726571756972656420617574686f7269747920646f6573206e6f742060408201526339b4b3b760e11b606082015260800190565b60208082526010908201526f213934b233b29034b990333937bd32b760811b604082015260600190565b6020808252601190820152704e6f7420696e207365747570206d6f646560781b604082015260600190565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b60208082526010908201526f2a3432b9329034b9903737903830b4b960811b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252600690820152651b1bd8dad95960d21b604082015260600190565b6020808252601a908201527f496e636f72726563742072656365697665722061646472657373000000000000604082015260600190565b858152602081018590526001600160a01b0384811660408301528316606082015260a0608082018190526000906140fb9083018461400a565b604051601f8201601f1916810167ffffffffffffffff811182821017156143755761437561447a565b604052919050565b6000821982111561439057614390614438565b500190565b6000826143b257634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156143d1576143d1614438565b500290565b6000828210156143e8576143e8614438565b500390565b60005b838110156144085781810151838201526020016143f0565b83811115614417576000848401525b50505050565b600060001982141561443157614431614438565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146144a557600080fd5b50565b80151581146144a557600080fdfea2646970667358221220c754242ef14fc5391e99bf5373eea3041adc0aaedc01346f940786d4a5d23f7864736f6c63430008070033