Contract
0x20975da6eb930d592b9d78f451a9156db5e4c77b
2
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
ExchangeV3
Compiler Version
v0.8.7+commit.e28d00a7
Contract Source Code (Solidity)
/** *Submitted for verification at optimistic.etherscan.io on 2022-02-10 */ // Sources flattened with hardhat v2.7.1 https://hardhat.org // File @openzeppelin/contracts/utils/[email protected] // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } } // File @openzeppelin/contracts/access/[email protected] // OpenZeppelin Contracts v4.4.0 (access/Ownable.sol) pragma solidity ^0.8.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @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() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } // File @openzeppelin/contracts/utils/introspection/[email protected] // OpenZeppelin Contracts v4.4.0 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // File @openzeppelin/contracts/token/ERC721/[email protected] // OpenZeppelin Contracts v4.4.0 (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; } // File @openzeppelin/contracts/interfaces/[email protected] // OpenZeppelin Contracts v4.4.0 (interfaces/IERC721.sol) pragma solidity ^0.8.0; // File @openzeppelin/contracts/token/ERC1155/[email protected] // OpenZeppelin Contracts v4.4.0 (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; } // File @openzeppelin/contracts/interfaces/[email protected] // OpenZeppelin Contracts v4.4.0 (interfaces/IERC1155.sol) pragma solidity ^0.8.0; // File @openzeppelin/contracts/token/ERC20/[email protected] // OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File @openzeppelin/contracts/interfaces/[email protected] // OpenZeppelin Contracts v4.4.0 (interfaces/IERC20.sol) pragma solidity ^0.8.0; // File @openzeppelin/contracts/utils/introspection/[email protected] // OpenZeppelin Contracts v4.4.0 (utils/introspection/ERC165Checker.sol) pragma solidity ^0.8.0; /** * @dev Library used to query support of an interface declared via {IERC165}. * * Note that these functions return the actual result of the query: they do not * `revert` if an interface is not supported. It is up to the caller to decide * what to do in these cases. */ library ERC165Checker { // As per the EIP-165 spec, no interface should ever match 0xffffffff bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; /** * @dev Returns true if `account` supports the {IERC165} interface, */ function supportsERC165(address account) internal view returns (bool) { // Any contract that implements ERC165 must explicitly indicate support of // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid return _supportsERC165Interface(account, type(IERC165).interfaceId) && !_supportsERC165Interface(account, _INTERFACE_ID_INVALID); } /** * @dev Returns true if `account` supports the interface defined by * `interfaceId`. Support for {IERC165} itself is queried automatically. * * See {IERC165-supportsInterface}. */ function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { // query support of both ERC165 as per the spec and support of _interfaceId return supportsERC165(account) && _supportsERC165Interface(account, interfaceId); } /** * @dev Returns a boolean array where each value corresponds to the * interfaces passed in and whether they're supported or not. This allows * you to batch check interfaces for a contract where your expectation * is that some interfaces may not be supported. * * See {IERC165-supportsInterface}. * * _Available since v3.4._ */ function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool[] memory) { // an array of booleans corresponding to interfaceIds and whether they're supported or not bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); // query support of ERC165 itself if (supportsERC165(account)) { // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]); } } return interfaceIdsSupported; } /** * @dev Returns true if `account` supports all the interfaces defined in * `interfaceIds`. Support for {IERC165} itself is queried automatically. * * Batch-querying can lead to gas savings by skipping repeated checks for * {IERC165} support. * * See {IERC165-supportsInterface}. */ function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { // query support of ERC165 itself if (!supportsERC165(account)) { return false; } // query support of each interface in _interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { if (!_supportsERC165Interface(account, interfaceIds[i])) { return false; } } // all interfaces supported return true; } /** * @notice Query if a contract implements an interface, does not check ERC165 support * @param account The address of the contract to query for support of an interface * @param interfaceId The interface identifier, as specified in ERC-165 * @return true if the contract at account indicates support of the interface with * identifier interfaceId, false otherwise * @dev Assumes that account contains a contract that supports ERC165, otherwise * the behavior of this method is undefined. This precondition can be checked * with {supportsERC165}. * Interface identification is specified in ERC-165. */ function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) { bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams); if (result.length < 32) return false; return success && abi.decode(result, (bool)); } } // File @openzeppelin/contracts/utils/[email protected] // OpenZeppelin Contracts v4.4.0 (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } } // File @openzeppelin/contracts/utils/cryptography/[email protected] // OpenZeppelin Contracts v4.4.0 (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } else if (error == RecoverError.InvalidSignatureV) { revert("ECDSA: invalid signature 'v' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { // Check the signature length // - case 65: r,s,v signature (standard) // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else if (signature.length == 64) { bytes32 r; bytes32 vs; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) vs := mload(add(signature, 0x40)) } return tryRecover(hash, r, vs); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s; uint8 v; assembly { s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) v := add(shr(255, vs), 27) } return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } if (v != 27 && v != 28) { return (address(0), RecoverError.InvalidSignatureV); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } } // File @openzeppelin/contracts/utils/[email protected] // OpenZeppelin Contracts v4.4.0 (utils/Address.sol) pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // File @openzeppelin/contracts/security/[email protected] // OpenZeppelin Contracts v4.4.0 (security/Pausable.sol) pragma solidity ^0.8.0; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } } // File @openzeppelin/contracts/security/[email protected] // OpenZeppelin Contracts v4.4.0 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } } // File Contracts/Exchange.sol pragma solidity ^0.8.0; interface IRoyaltyRegistry { function addRegistrant(address registrant) external; function removeRegistrant(address registrant) external; function setRoyalty(address _erc721address, address payable _payoutAddress, uint256 _payoutPerMille) external; function getRoyaltyPayoutAddress(address _erc721address) external view returns (address payable); function getRoyaltyPayoutRate(address _erc721address) external view returns (uint256); } interface ICancellationRegistry { function addRegistrant(address registrant) external; function removeRegistrant(address registrant) external; function cancelOrder(bytes memory signature) external; function isOrderCancelled(bytes memory signature) external view returns (bool); function cancelPreviousSellOrders(address seller, address tokenAddr, uint256 tokenId) external; function getSellOrderCancellationBlockNumber(address addr, address tokenAddr, uint256 tokenId) external view returns (uint256); } contract ExchangeV3 is Ownable, Pausable, ReentrancyGuard { using ERC165Checker for address; bytes4 private InterfaceId_ERC721 = 0x80ac58cd; // The ERC-165 identifier for 721 bytes4 private InterfaceId_ERC1155 = 0xd9b67a26; // The ERC-165 identifier for 1155 address payable _makerWallet; uint256 private _makerFeePerMille = 25; uint256 private _maxRoyaltyPerMille = 150; bytes32 private EIP712_DOMAIN_TYPE_HASH = keccak256("EIP712Domain(string name,string version)"); bytes32 private DOMAIN_SEPARATOR = keccak256(abi.encode( EIP712_DOMAIN_TYPE_HASH, keccak256(bytes("Quixotic")), keccak256(bytes("3")) )); IRoyaltyRegistry royaltyRegistry; ICancellationRegistry cancellationRegistry; IERC20 wethContract; event SellOrderFilled(address indexed seller, address payable buyer, address indexed contractAddress, uint256 indexed tokenId, uint256 price); event BuyOrderFilled(address indexed seller, address payable buyer, address indexed contractAddress, uint256 indexed tokenId, uint256 price); event DutchAuctionFilled(address indexed seller, address payable buyer, address indexed contractAddress, uint256 indexed tokenId, uint256 price); /* This contains all data of the SellOrder */ struct SellOrder { /* Seller of the NFT */ address payable seller; /* Contract address of NFT */ address contractAddress; /* Token id of NFT to sell */ uint256 tokenId; /* Start time in unix timestamp */ uint256 startTime; /* Expiration in unix timestamp */ uint256 expiration; /* Price in wei */ uint256 price; /* Number of tokens to transfer; should be 1 for ERC721 */ uint256 quantity; /* Block number that this order was created at */ uint256 createdAtBlockNumber; } /* This contains all data of the BuyOrder */ struct BuyOrder { /* Seller of the NFT */ address payable buyer; /* Contract address of NFT */ address contractAddress; /* Token id of NFT to sell */ uint256 tokenId; /* Start time in unix timestamp */ uint256 startTime; /* Expiration in unix timestamp */ uint256 expiration; /* Price in wei */ uint256 price; /* Number of tokens to transfer; should be 1 for ERC721 */ uint256 quantity; } struct DutchAuctionOrder { /* Seller of the NFT */ address payable seller; /* Contract address of NFT */ address contractAddress; /* Token id of NFT to sell */ uint256 tokenId; /* Start time in unix timestamp */ uint256 startTime; /* End time in unix timestamp */ uint256 endTime; /* Price in wei */ uint256 startPrice; /* Price in wei */ uint256 endPrice; /* Number of tokens to transfer; should be 1 for ERC721 */ uint256 quantity; /* Block number that this order was created at */ uint256 createdAtBlockNumber; } function setRegistryContracts(address royaltyRegistryAddr, address cancellationRegistryAddr) external onlyOwner { royaltyRegistry = IRoyaltyRegistry(royaltyRegistryAddr); cancellationRegistry = ICancellationRegistry(cancellationRegistryAddr); } function setWethContract(address wethAddress) external onlyOwner { wethContract = IERC20(wethAddress); } /* * @dev External trade function. This accepts the details of the sell order and signed sell * order (the signature) as a meta-transaction. * * Emits a {SellOrderFilled} event via `_fillSellOrder`. */ function fillSellOrder( address payable seller, address contractAddress, uint256 tokenId, uint256 startTime, uint256 expiration, uint256 price, uint256 quantity, uint256 createdAtBlockNumber, bytes memory signature, address payable buyer ) external payable whenNotPaused nonReentrant { require(msg.value >= price, "You're transaction doesn't have the required payment"); SellOrder memory sellOrder = SellOrder( seller, contractAddress, tokenId, startTime, expiration, price, quantity, createdAtBlockNumber ); _fillSellOrder(sellOrder, signature, buyer); } /* * @dev Executes a trade given a sell order. * * Emits a {SellOrderFilled} event. */ function _fillSellOrder(SellOrder memory sellOrder, bytes memory signature, address payable buyer) internal { ///////////////// /// Checks /// ///////////////// /* Make sure the order is not cancelled */ require( cancellationRegistry.getSellOrderCancellationBlockNumber(sellOrder.seller, sellOrder.contractAddress, sellOrder.tokenId) < sellOrder.createdAtBlockNumber, "This order has been cancelled." ); /* Check signature */ require(_validateSellerSignature(sellOrder, signature), "Signature is not valid for SellOrder."); // Check has started require((block.timestamp > sellOrder.startTime), "The startTime is in the future. You must wait to fill this Sell Order"); // Check not expired require((block.timestamp < sellOrder.expiration), "This sell order has expired."); /* Do final checks and transfer NFT */ ///////////////// /// Transfer /// ///////////////// _transferNFT(sellOrder.contractAddress, sellOrder.tokenId, sellOrder.seller, buyer, sellOrder.quantity); ////////////////////// /// Send Payment /// ///////////////////// _sendETHPaymentsWithRoyalties(sellOrder.contractAddress, sellOrder.seller); ///////////////// /// Finalize /// ///////////////// cancellationRegistry.cancelPreviousSellOrders(sellOrder.seller, sellOrder.contractAddress, sellOrder.tokenId); emit SellOrderFilled(sellOrder.seller, buyer, sellOrder.contractAddress, sellOrder.tokenId, sellOrder.price); } /* * @dev Sends out ETH payments to marketplace, royalty, and the final recipients */ function _sendETHPaymentsWithRoyalties(address contractAddress, address payable finalRecipient) internal { uint256 royaltyPayout = (royaltyRegistry.getRoyaltyPayoutRate(contractAddress) * msg.value) / 1000; uint256 makerPayout = (_makerFeePerMille * msg.value) / 1000; uint256 remainingPayout = msg.value - royaltyPayout - makerPayout; if (royaltyPayout > 0) { Address.sendValue(royaltyRegistry.getRoyaltyPayoutAddress(contractAddress), royaltyPayout); } Address.sendValue(_makerWallet, makerPayout); Address.sendValue(finalRecipient, remainingPayout); } /* * @dev Sets the royalty as a int out of 1000 that the creator should receive and the address to pay. */ function setRoyalty(address contractAddress, address payable _payoutAddress, uint256 _payoutPerMille) external { require(_payoutPerMille <= _maxRoyaltyPerMille, "Royalty must be between 0 and 15%"); require(contractAddress.supportsInterface(InterfaceId_ERC721) || contractAddress.supportsInterface(InterfaceId_ERC1155), "Is not ERC721 or ERC1155"); Ownable ownableNFTContract = Ownable(contractAddress); require(_msgSender() == ownableNFTContract.owner()); royaltyRegistry.setRoyalty(contractAddress, _payoutAddress, _payoutPerMille); } /* * @dev Gets the royalty payout address. */ function getRoyaltyPayoutAddress(address contractAddress) public view returns (address) { return royaltyRegistry.getRoyaltyPayoutAddress(contractAddress); } /* * @dev Gets the royalty as a int out of 1000 that the creator should receive. */ function getRoyaltyPayoutRate(address contractAddress) public view returns (uint256) { return royaltyRegistry.getRoyaltyPayoutRate(contractAddress); } /* * @dev Sets the wallet for the exchange. */ function setMakerWallet(address payable _newMakerWallet) external onlyOwner { _makerWallet = _newMakerWallet; } /* * @dev Pauses trading on the exchange. To be used for emergencies. */ function pause() external onlyOwner { _pause(); } /* * @dev Resumes trading on the exchange. To be used for emergencies. */ function unpause() external onlyOwner { _unpause(); } /* * @dev Cancels a buy order. */ function cancelBuyOrder( address payable buyer, address contractAddress, uint256 tokenId, uint256 startTime, uint256 expiration, uint256 price, uint256 quantity, bytes memory signature ) external { require((buyer == _msgSender() || owner() == _msgSender()), "Caller must be Exchange Owner or Order Signer"); BuyOrder memory buyOrder = BuyOrder( buyer, contractAddress, tokenId, startTime, expiration, price, quantity ); require(_validateBuyerSignature(buyOrder, signature), "Signature is not valid for BuyOrder."); cancellationRegistry.cancelOrder(signature); } /* * @dev Implements one-order-cancels-the-other (OCO) for a token */ function cancelPreviousSellOrders( address addr, address tokenAddr, uint256 tokenId ) external { require((addr == _msgSender() || owner() == _msgSender()), "Caller must be Exchange Owner or Order Signer"); cancellationRegistry.cancelPreviousSellOrders(addr, tokenAddr, tokenId); } /* * @dev Check if an order has been cancelled. */ function isOrderCancelled(bytes memory signature) public view returns (bool) { return cancellationRegistry.isOrderCancelled(signature); } /* * @dev Validate the sell order against the signature of the meta-transaction. */ function _validateSellerSignature(SellOrder memory sellOrder, bytes memory signature) internal view returns (bool) { bytes32 SELLORDER_TYPEHASH = keccak256( "SellOrder(address seller,address contractAddress,uint256 tokenId,uint256 startTime,uint256 expiration,uint256 price,uint256 quantity,uint256 createdAtBlockNumber)" ); bytes32 structHash = keccak256(abi.encode( SELLORDER_TYPEHASH, sellOrder.seller, sellOrder.contractAddress, sellOrder.tokenId, sellOrder.startTime, sellOrder.expiration, sellOrder.price, sellOrder.quantity, sellOrder.createdAtBlockNumber )); bytes32 digest = ECDSA.toTypedDataHash(DOMAIN_SEPARATOR, structHash); address recoveredAddress = ECDSA.recover(digest, signature); return recoveredAddress == sellOrder.seller; } /* * @dev Validate the sell order against the signature of the meta-transaction. */ function _validateBuyerSignature(BuyOrder memory buyOrder, bytes memory signature) internal view returns (bool) { bytes32 BUYORDER_TYPEHASH = keccak256( "BuyOrder(address buyer,address contractAddress,uint256 tokenId,uint256 startTime,uint256 expiration,uint256 price,uint256 quantity)" ); bytes32 structHash = keccak256(abi.encode( BUYORDER_TYPEHASH, buyOrder.buyer, buyOrder.contractAddress, buyOrder.tokenId, buyOrder.startTime, buyOrder.expiration, buyOrder.price, buyOrder.quantity )); bytes32 digest = ECDSA.toTypedDataHash(DOMAIN_SEPARATOR, structHash); address recoveredAddress = ECDSA.recover(digest, signature); return recoveredAddress == buyOrder.buyer; } /* * @dev Executes a trade given a buy order. * * Emits a {BuyOrderFilled} event. */ function fillBuyOrder( address payable buyer, address contractAddress, uint256 tokenId, uint256 startTime, uint256 expiration, uint256 price, uint256 quantity, bytes memory signature, address payable seller ) external payable whenNotPaused nonReentrant { BuyOrder memory buyOrder = BuyOrder( buyer, contractAddress, tokenId, startTime, expiration, price, quantity ); _fillBuyOrder(buyOrder, signature, seller); } function _fillBuyOrder(BuyOrder memory buyOrder, bytes memory signature, address payable seller) internal { /* Make sure the order is not cancelled */ require(!isOrderCancelled(signature), "This order has been cancelled."); /* First check signature */ require(_validateBuyerSignature(buyOrder, signature), "Signature is not valid for BuyOrder."); /* Check has started */ require((block.timestamp > buyOrder.startTime), "This buy order has expired."); /* Check not expired */ require((block.timestamp < buyOrder.expiration), "This buy order has expired."); /* require buyer has enough money */ require(wethContract.balanceOf(buyOrder.buyer) > buyOrder.price, "The buyer does not have enough WETH"); /* require that we have enough allowance */ require(wethContract.allowance(buyOrder.buyer, address(this)) > buyOrder.price, "The buyer must allow us to withdraw their WETH"); ///////////////// /// Transfer /// ///////////////// _transferNFT(buyOrder.contractAddress, buyOrder.tokenId, seller, buyOrder.buyer, buyOrder.quantity); ////////////////////// /// Send Payment /// ///////////////////// if (buyOrder.price > 0) { uint256 royaltyPayout = (royaltyRegistry.getRoyaltyPayoutRate(buyOrder.contractAddress) * buyOrder.price) / 1000; uint256 makerPayout = (_makerFeePerMille * buyOrder.price) / 1000; uint256 remainingPayout = buyOrder.price - royaltyPayout - makerPayout; if (royaltyPayout > 0) { wethContract.transferFrom(buyOrder.buyer, royaltyRegistry.getRoyaltyPayoutAddress(buyOrder.contractAddress), royaltyPayout); } wethContract.transferFrom(buyOrder.buyer, _makerWallet, makerPayout); wethContract.transferFrom(buyOrder.buyer, seller, remainingPayout); } ///////////////// /// Finalize /// ///////////////// cancellationRegistry.cancelOrder(signature); emit BuyOrderFilled(seller, buyOrder.buyer, buyOrder.contractAddress, buyOrder.tokenId, buyOrder.price); } /* * @dev External trade function. This accepts the details of the dutch auction order and signed dutch auction * order (the signature) as a meta-transaction. * * Emits a {DutchAuctionOrderFilled} event via `_fillDutchAuctionOrder`. */ function fillDutchAuctionOrder( address payable seller, address contractAddress, uint256 tokenId, uint256 startTime, uint256 endTime, uint256 startPrice, uint256 endPrice, uint256 quantity, uint256 createdAtBlockNumber, bytes memory signature, address payable buyer ) external payable whenNotPaused nonReentrant { uint256 currentPrice = calculateCurrentPrice(startTime, endTime, startPrice, endPrice); require(msg.value >= currentPrice, "The current price is higher than the payment submitted."); DutchAuctionOrder memory dutchAuctionOrder = DutchAuctionOrder( seller, contractAddress, tokenId, startTime, endTime, startPrice, endPrice, quantity, createdAtBlockNumber ); _fillDutchAuction(dutchAuctionOrder, signature, buyer); } function _fillDutchAuction( DutchAuctionOrder memory dutchAuctionOrder, bytes memory signature, address payable buyer ) internal { /* Make sure the order is not cancelled */ require( cancellationRegistry.getSellOrderCancellationBlockNumber(dutchAuctionOrder.seller, dutchAuctionOrder.contractAddress, dutchAuctionOrder.tokenId) < dutchAuctionOrder.createdAtBlockNumber, "This order has been cancelled." ); /* First check signature */ require(_validateDutchAuctionSignature(dutchAuctionOrder, signature), "Signature is not valid for DutchAuctionOrder."); // Check the dutch auction has started require((block.timestamp > dutchAuctionOrder.startTime), "This dutch auction order has not started yet."); // Check not expired require((block.timestamp < dutchAuctionOrder.endTime), "This dutch auction order has expired."); ///////////////// /// Transfer /// ///////////////// _transferNFT(dutchAuctionOrder.contractAddress, dutchAuctionOrder.tokenId, dutchAuctionOrder.seller, buyer, dutchAuctionOrder.quantity); ////////////////////// /// Send Payment /// ///////////////////// _sendETHPaymentsWithRoyalties(dutchAuctionOrder.contractAddress, dutchAuctionOrder.seller); ///////////////// /// Finalize /// ///////////////// cancellationRegistry.cancelPreviousSellOrders(dutchAuctionOrder.seller, dutchAuctionOrder.contractAddress, dutchAuctionOrder.tokenId); emit DutchAuctionFilled(dutchAuctionOrder.seller, buyer, dutchAuctionOrder.contractAddress, dutchAuctionOrder.tokenId, msg.value); } function calculateCurrentPrice(uint256 startTime, uint256 endTime, uint256 startPrice, uint256 endPrice) public view returns (uint256) { uint256 auctionDuration = (endTime - startTime); uint256 timeRemaining = (endTime - block.timestamp); uint256 perMilleRemaining = (1000000000000000 / auctionDuration) / (1000000000000 / timeRemaining); uint256 variableAmount = startPrice - endPrice; uint256 variableAmountRemaining = (perMilleRemaining * variableAmount) / 1000; return endPrice + variableAmountRemaining; } function _validateDutchAuctionSignature( DutchAuctionOrder memory dutchAuctionOrder, bytes memory signature ) internal view returns (bool) { bytes32 DUTCHAUCTIONORDER_TYPEHASH = keccak256( "DutchAuctionOrder(address seller,address contractAddress,uint256 tokenId,uint256 startTime,uint256 endTime,uint256 startPrice,uint256 endPrice,uint256 quantity,uint256 createdAtBlockNumber)" ); bytes32 structHash = keccak256(abi.encode( DUTCHAUCTIONORDER_TYPEHASH, dutchAuctionOrder.seller, dutchAuctionOrder.contractAddress, dutchAuctionOrder.tokenId, dutchAuctionOrder.startTime, dutchAuctionOrder.endTime, dutchAuctionOrder.startPrice, dutchAuctionOrder.endPrice, dutchAuctionOrder.quantity, dutchAuctionOrder.createdAtBlockNumber )); bytes32 digest = ECDSA.toTypedDataHash(DOMAIN_SEPARATOR, structHash); address recoveredAddress = ECDSA.recover(digest, signature); return recoveredAddress == dutchAuctionOrder.seller; } function _transferNFT(address contractAddress, uint256 tokenId, address seller, address buyer, uint256 quantity) internal { if (contractAddress.supportsInterface(InterfaceId_ERC721)) { IERC721 erc721 = IERC721(contractAddress); /* require is approved for all */ require((erc721.ownerOf(tokenId) == seller), "The seller does not own this NFT"); /* require we can operate the NFT */ require(erc721.isApprovedForAll(seller, address(this)), "The Trading contract is not approved to operate this NFT"); ///////////////// /// Transfer /// ///////////////// erc721.safeTransferFrom(seller, buyer, tokenId); } else if (contractAddress.supportsInterface(InterfaceId_ERC1155)) { IERC1155 erc1155 = IERC1155(contractAddress); /* require is approved for all */ require(erc1155.balanceOf(seller, tokenId) >= quantity, "The seller does not own enough of these NFTs"); /* require we can operate the NFT */ require(erc1155.isApprovedForAll(seller, address(this)), "The Trading contract is not approved to operate this NFT"); ///////////////// /// Transfer /// ///////////////// erc1155.safeTransferFrom(seller, buyer, tokenId, quantity, ""); } else { revert("We don't recognize the NFT as either an ERC721 or ERC1155."); } } /* * Withdraw just in case Ether is accidentally sent to this contract. */ function withdraw() public onlyOwner { uint balance = address(this).balance; payable(msg.sender).transfer(balance); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"address payable","name":"buyer","type":"address"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"BuyOrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"address payable","name":"buyer","type":"address"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"DutchAuctionFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"address payable","name":"buyer","type":"address"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"SellOrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"startPrice","type":"uint256"},{"internalType":"uint256","name":"endPrice","type":"uint256"}],"name":"calculateCurrentPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"buyer","type":"address"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"cancelBuyOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address","name":"tokenAddr","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"cancelPreviousSellOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"buyer","type":"address"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address payable","name":"seller","type":"address"}],"name":"fillBuyOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"seller","type":"address"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"startPrice","type":"uint256"},{"internalType":"uint256","name":"endPrice","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"createdAtBlockNumber","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address payable","name":"buyer","type":"address"}],"name":"fillDutchAuctionOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"seller","type":"address"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"createdAtBlockNumber","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address payable","name":"buyer","type":"address"}],"name":"fillSellOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"getRoyaltyPayoutAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"getRoyaltyPayoutRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"isOrderCancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_newMakerWallet","type":"address"}],"name":"setMakerWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"royaltyRegistryAddr","type":"address"},{"internalType":"address","name":"cancellationRegistryAddr","type":"address"}],"name":"setRegistryContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address payable","name":"_payoutAddress","type":"address"},{"internalType":"uint256","name":"_payoutPerMille","type":"uint256"}],"name":"setRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wethAddress","type":"address"}],"name":"setWethContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
600280546001600160401b03191667d9b67a2680ac58cd179055601960035560966004557fb03948446334eb9b2196d5eb166f69b9d49403eb4a12f36de8d3f9f3cb8e15c36005819055600860805267517569786f74696360c01b60a052600160c052603360f81b60e052610120527f0c0e2cc566869b7ad10c505184e86eea935bae95cc2069419092b16720f49925610140527f2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de610160526060610100526101806040527f55bfbf993402613c71f52a903df5d4815c70ce2a93399ac644d7834bcd9e895a6006553480156100f457600080fd5b506100fe33610114565b6000805460ff60a01b1916905560018055610164565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61332180620001746000396000f3fe60806040526004361061011f5760003560e01c80638456cb59116100a0578063c3fbdb7c11610064578063c3fbdb7c146102ea578063dc7e053f14610318578063ec4210ff14610338578063edf8301b14610358578063f2fde38b1461036b57600080fd5b80638456cb59146102645780638da5cb5b14610279578063abe0906a14610297578063ad6c8c5f146102b7578063b1216b79146102ca57600080fd5b806355c338aa116100e757806355c338aa146101cd57806355e4a3fa146101ed578063563166a9146102005780635c975abb14610230578063715018a61461024f57600080fd5b8063083d089d146101245780632b812a34146101465780632df5cb23146101665780633ccfd60b146101a35780633f4ba83a146101b8575b600080fd5b34801561013057600080fd5b5061014461013f366004612edb565b61038b565b005b34801561015257600080fd5b50610144610161366004612bc0565b61043c565b34801561017257600080fd5b50610186610181366004612bc0565b610497565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101af57600080fd5b5061014461051b565b3480156101c457600080fd5b50610144610578565b3480156101d957600080fd5b506101446101e8366004612edb565b6105ac565b6101446101fb366004612c8d565b610795565b34801561020c57600080fd5b5061022061021b366004612f3e565b610842565b604051901515815260200161019a565b34801561023c57600080fd5b50600054600160a01b900460ff16610220565b34801561025b57600080fd5b506101446108c3565b34801561027057600080fd5b506101446108f7565b34801561028557600080fd5b506000546001600160a01b0316610186565b3480156102a357600080fd5b506101446102b2366004612bc0565b610929565b6101446102c5366004612d35565b610975565b3480156102d657600080fd5b506101446102e5366004612ea2565b610aa0565b3480156102f657600080fd5b5061030a610305366004612f94565b610af8565b60405190815260200161019a565b34801561032457600080fd5b50610144610333366004612bfa565b610b84565b34801561034457600080fd5b5061030a610353366004612bc0565b610c9d565b610144610366366004612de8565b610d1b565b34801561037757600080fd5b50610144610386366004612bc0565b610e67565b6001600160a01b0383163314806103ac57506000546001600160a01b031633145b6103d15760405162461bcd60e51b81526004016103c8906130f7565b60405180910390fd5b60085460405163083d089d60e01b81526001600160a01b039091169063083d089d9061040590869086908690600401612fe2565b600060405180830381600087803b15801561041f57600080fd5b505af1158015610433573d6000803e3d6000fd5b50505050505050565b6000546001600160a01b031633146104665760405162461bcd60e51b81526004016103c890613144565b600280546001600160a01b03909216600160401b0268010000000000000000600160e01b0319909216919091179055565b600754604051632df5cb2360e01b81526001600160a01b0383811660048301526000921690632df5cb239060240160206040518083038186803b1580156104dd57600080fd5b505afa1580156104f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105159190612bdd565b92915050565b6000546001600160a01b031633146105455760405162461bcd60e51b81526004016103c890613144565b6040514790339082156108fc029083906000818181858888f19350505050158015610574573d6000803e3d6000fd5b5050565b6000546001600160a01b031633146105a25760405162461bcd60e51b81526004016103c890613144565b6105aa610f02565b565b6004548111156106085760405162461bcd60e51b815260206004820152602160248201527f526f79616c7479206d757374206265206265747765656e203020616e642031356044820152602560f81b60648201526084016103c8565b600254610622906001600160a01b0385169060e01b610f9f565b8061064a575060025461064a906001600160a01b03851690640100000000900460e01b610f9f565b6106965760405162461bcd60e51b815260206004820152601860248201527f4973206e6f7420455243373231206f722045524331313535000000000000000060448201526064016103c8565b6000839050806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156106d457600080fd5b505afa1580156106e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070c9190612bdd565b6001600160a01b0316336001600160a01b03161461072957600080fd5b600754604051632ae19c5560e11b81526001600160a01b03909116906355c338aa9061075d90879087908790600401612fe2565b600060405180830381600087803b15801561077757600080fd5b505af115801561078b573d6000803e3d6000fd5b5050505050505050565b600054600160a01b900460ff16156107bf5760405162461bcd60e51b81526004016103c8906130cd565b600260015414156107e25760405162461bcd60e51b81526004016103c890613179565b60026001556040805160e0810182526001600160a01b03808c1682528a166020820152908101889052606081018790526080810186905260a0810185905260c08101849052610832818484610fc2565b5050600180555050505050505050565b60085460405163563166a960e01b81526000916001600160a01b03169063563166a990610873908590600401613006565b60206040518083038186803b15801561088b57600080fd5b505afa15801561089f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105159190612f1c565b6000546001600160a01b031633146108ed5760405162461bcd60e51b81526004016103c890613144565b6105aa6000611679565b6000546001600160a01b031633146109215760405162461bcd60e51b81526004016103c890613144565b6105aa6116c9565b6000546001600160a01b031633146109535760405162461bcd60e51b81526004016103c890613144565b600980546001600160a01b0319166001600160a01b0392909216919091179055565b600054600160a01b900460ff161561099f5760405162461bcd60e51b81526004016103c8906130cd565b600260015414156109c25760405162461bcd60e51b81526004016103c890613179565b600260015534851115610a345760405162461bcd60e51b815260206004820152603460248201527f596f75277265207472616e73616374696f6e20646f65736e27742068617665206044820152731d1a19481c995c5d5a5c9959081c185e5b595b9d60621b60648201526084016103c8565b60006040518061010001604052808c6001600160a01b031681526020018b6001600160a01b031681526020018a8152602001898152602001888152602001878152602001868152602001858152509050610a8f81848461172e565b505060018055505050505050505050565b6000546001600160a01b03163314610aca5760405162461bcd60e51b81526004016103c890613144565b600780546001600160a01b039384166001600160a01b03199182161790915560088054929093169116179055565b600080610b05868661324d565b90506000610b13428761324d565b90506000610b268264e8d4a5100061320c565b610b378466038d7ea4c6800061320c565b610b41919061320c565b90506000610b4f868861324d565b905060006103e8610b60838561322e565b610b6a919061320c565b9050610b7681886131f4565b9a9950505050505050505050565b6001600160a01b038816331480610ba557506000546001600160a01b031633145b610bc15760405162461bcd60e51b81526004016103c8906130f7565b60006040518060e001604052808a6001600160a01b03168152602001896001600160a01b03168152602001888152602001878152602001868152602001858152602001848152509050610c148183611a25565b610c305760405162461bcd60e51b81526004016103c8906131b0565b600854604051632e442d9960e21b81526001600160a01b039091169063b910b66490610c60908590600401613006565b600060405180830381600087803b158015610c7a57600080fd5b505af1158015610c8e573d6000803e3d6000fd5b50505050505050505050505050565b60075460405163ec4210ff60e01b81526001600160a01b038381166004830152600092169063ec4210ff9060240160206040518083038186803b158015610ce357600080fd5b505afa158015610cf7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105159190612f7b565b600054600160a01b900460ff1615610d455760405162461bcd60e51b81526004016103c8906130cd565b60026001541415610d685760405162461bcd60e51b81526004016103c890613179565b60026001556000610d7b89898989610af8565b905080341015610df35760405162461bcd60e51b815260206004820152603760248201527f5468652063757272656e7420707269636520697320686967686572207468616e60448201527f20746865207061796d656e74207375626d69747465642e00000000000000000060648201526084016103c8565b60006040518061012001604052808e6001600160a01b031681526020018d6001600160a01b031681526020018c81526020018b81526020018a8152602001898152602001888152602001878152602001868152509050610e54818585611b3c565b5050600180555050505050505050505050565b6000546001600160a01b03163314610e915760405162461bcd60e51b81526004016103c890613144565b6001600160a01b038116610ef65760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016103c8565b610eff81611679565b50565b600054600160a01b900460ff16610f525760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016103c8565b6000805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000610faa83611e28565b8015610fbb5750610fbb8383611e5b565b9392505050565b610fcb82610842565b15610fe85760405162461bcd60e51b81526004016103c890613039565b610ff28383611a25565b61100e5760405162461bcd60e51b81526004016103c8906131b0565b826060015142116110615760405162461bcd60e51b815260206004820152601b60248201527f5468697320627579206f726465722068617320657870697265642e000000000060448201526064016103c8565b826080015142106110b45760405162461bcd60e51b815260206004820152601b60248201527f5468697320627579206f726465722068617320657870697265642e000000000060448201526064016103c8565b60a083015160095484516040516370a0823160e01b81526001600160a01b0391821660048201529116906370a082319060240160206040518083038186803b1580156110ff57600080fd5b505afa158015611113573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111379190612f7b565b116111905760405162461bcd60e51b815260206004820152602360248201527f54686520627579657220646f6573206e6f74206861766520656e6f756768205760448201526208aa8960eb1b60648201526084016103c8565b60a08301516009548451604051636eb1769f60e11b81526001600160a01b03918216600482015230602482015291169063dd62ed3e9060440160206040518083038186803b1580156111e157600080fd5b505afa1580156111f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112199190612f7b565b1161127d5760405162461bcd60e51b815260206004820152602e60248201527f546865206275796572206d75737420616c6c6f7720757320746f20776974686460448201526d0e4c2ee40e8d0cad2e440ae8aa8960931b60648201526084016103c8565b61129a836020015184604001518386600001518760c00151611f44565b60a0830151156115b75760a0830151600754602085015160405163ec4210ff60e01b81526001600160a01b0391821660048201526000936103e8939092169063ec4210ff9060240160206040518083038186803b1580156112fa57600080fd5b505afa15801561130e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113329190612f7b565b61133c919061322e565b611346919061320c565b905060006103e88560a0015160035461135f919061322e565b611369919061320c565b9050600081838760a0015161137e919061324d565b611388919061324d565b905082156114965760095486516007546020890151604051632df5cb2360e01b81526001600160a01b039182166004820152938116936323b872dd93929190911690632df5cb239060240160206040518083038186803b1580156113eb57600080fd5b505afa1580156113ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114239190612bdd565b866040518463ffffffff1660e01b815260040161144293929190612fe2565b602060405180830381600087803b15801561145c57600080fd5b505af1158015611470573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114949190612f1c565b505b60095486516002546040516323b872dd60e01b81526001600160a01b03938416936323b872dd936114d9939092600160401b909104909116908790600401612fe2565b602060405180830381600087803b1580156114f357600080fd5b505af1158015611507573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152b9190612f1c565b5060095486516040516323b872dd60e01b81526001600160a01b03909216916323b872dd916115609188908690600401612fe2565b602060405180830381600087803b15801561157a57600080fd5b505af115801561158e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b29190612f1c565b505050505b600854604051632e442d9960e21b81526001600160a01b039091169063b910b664906115e7908590600401613006565b600060405180830381600087803b15801561160157600080fd5b505af1158015611615573d6000803e3d6000fd5b505050604080850151602080870151875160a089015185516001600160a01b03928316815293840152929450821692918516917fcb3cd529428badade171c8b0ef6c2f25d13bc69785143c43ec869d386ae3414191015b60405180910390a4505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600054600160a01b900460ff16156116f35760405162461bcd60e51b81526004016103c8906130cd565b6000805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610f823390565b60e0830151600854845160208601516040808801519051631782713960e31b81526001600160a01b039094169363bc1389c8936117719390929091600401612fe2565b60206040518083038186803b15801561178957600080fd5b505afa15801561179d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c19190612f7b565b106117de5760405162461bcd60e51b81526004016103c890613039565b6117e883836123a9565b6118425760405162461bcd60e51b815260206004820152602560248201527f5369676e6174757265206973206e6f742076616c696420666f722053656c6c4f604482015264393232b91760d91b60648201526084016103c8565b826060015142116118c95760405162461bcd60e51b815260206004820152604560248201527f54686520737461727454696d6520697320696e20746865206675747572652e2060448201527f596f75206d757374207761697420746f2066696c6c20746869732053656c6c2060648201526427b93232b960d91b608482015260a4016103c8565b8260800151421061191c5760405162461bcd60e51b815260206004820152601c60248201527f546869732073656c6c206f726465722068617320657870697265642e0000000060448201526064016103c8565b611939836020015184604001518560000151848760c00151611f44565b61194b83602001518460000151612458565b60085483516020850151604080870151905163083d089d60e01b81526001600160a01b039094169363083d089d936119899390929091600401612fe2565b600060405180830381600087803b1580156119a357600080fd5b505af11580156119b7573d6000803e3d6000fd5b50505050826040015183602001516001600160a01b031684600001516001600160a01b03167f70ba0d31158674eea8365d0f7b9ac70e552cc28b8bb848664e4feb939c6578f8848760a0015160405161166c9291906001600160a01b03929092168252602082015260400190565b6000807f300c1745fa3a93210c7fdff8b927b058ee9bbc08263f54eabbe8c44ea8ee0ec49050600081856000015186602001518760400151886060015189608001518a60a001518b60c00151604051602001611ac59897969594939291909788526001600160a01b0396871660208901529490951660408701526060860192909252608085015260a084015260c083019190915260e08201526101000190565b60408051601f19818403018152828252805160209182012060065461190160f01b858401526022850152604280850182905283518086039091018152606290940190925282519201919091209091506000611b2082876125de565b87516001600160a01b0391821691161494505050505092915050565b610100830151600854845160208601516040808801519051631782713960e31b81526001600160a01b039094169363bc1389c893611b809390929091600401612fe2565b60206040518083038186803b158015611b9857600080fd5b505afa158015611bac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd09190612f7b565b10611bed5760405162461bcd60e51b81526004016103c890613039565b611bf78383612602565b611c595760405162461bcd60e51b815260206004820152602d60248201527f5369676e6174757265206973206e6f742076616c696420666f7220447574636860448201526c20bab1ba34b7b727b93232b91760991b60648201526084016103c8565b82606001514211611cc25760405162461bcd60e51b815260206004820152602d60248201527f546869732064757463682061756374696f6e206f7264657220686173206e6f7460448201526c1039ba30b93a32b2103cb2ba1760991b60648201526084016103c8565b82608001514210611d235760405162461bcd60e51b815260206004820152602560248201527f546869732064757463682061756374696f6e206f72646572206861732065787060448201526434b932b21760d91b60648201526084016103c8565b611d40836020015184604001518560000151848760e00151611f44565b611d5283602001518460000151612458565b60085483516020850151604080870151905163083d089d60e01b81526001600160a01b039094169363083d089d93611d909390929091600401612fe2565b600060405180830381600087803b158015611daa57600080fd5b505af1158015611dbe573d6000803e3d6000fd5b50505050826040015183602001516001600160a01b031684600001516001600160a01b03167fcd2ac775eba6d68eb3bdbba5c500751ed102e5d2b7bf9c459b3e7b808d132cbd843460405161166c9291906001600160a01b03929092168252602082015260400190565b6000611e3b826301ffc9a760e01b611e5b565b80156105155750611e54826001600160e01b0319611e5b565b1592915050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b179052905160009190829081906001600160a01b0387169061753090611ec2908690612fc6565b6000604051808303818686fa925050503d8060008114611efe576040519150601f19603f3d011682016040523d82523d6000602084013e611f03565b606091505b5091509150602081511015611f1e5760009350505050610515565b818015611f3a575080806020019051810190611f3a9190612f1c565b9695505050505050565b600254611f5e906001600160a01b0387169060e01b610f9f565b1561213b576040516331a9108f60e11b81526004810185905285906001600160a01b038581169190831690636352211e9060240160206040518083038186803b158015611faa57600080fd5b505afa158015611fbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fe29190612bdd565b6001600160a01b0316146120385760405162461bcd60e51b815260206004820181905260248201527f5468652073656c6c657220646f6573206e6f74206f776e2074686973204e465460448201526064016103c8565b60405163e985e9c560e01b81526001600160a01b03858116600483015230602483015282169063e985e9c59060440160206040518083038186803b15801561207f57600080fd5b505afa158015612093573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120b79190612f1c565b6120d35760405162461bcd60e51b81526004016103c890613070565b604051632142170760e11b81526001600160a01b038216906342842e0e9061210390879087908a90600401612fe2565b600060405180830381600087803b15801561211d57600080fd5b505af1158015612131573d6000803e3d6000fd5b50505050506123a2565b60025461215d906001600160a01b03871690640100000000900460e01b610f9f565b1561233457604051627eeac760e11b81526001600160a01b038481166004830152602482018690528691839183169062fdd58e9060440160206040518083038186803b1580156121ac57600080fd5b505afa1580156121c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e49190612f7b565b10156122475760405162461bcd60e51b815260206004820152602c60248201527f5468652073656c6c657220646f6573206e6f74206f776e20656e6f756768206f60448201526b66207468657365204e46547360a01b60648201526084016103c8565b60405163e985e9c560e01b81526001600160a01b03858116600483015230602483015282169063e985e9c59060440160206040518083038186803b15801561228e57600080fd5b505afa1580156122a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c69190612f1c565b6122e25760405162461bcd60e51b81526004016103c890613070565b604051637921219560e11b81526001600160a01b0385811660048301528481166024830152604482018790526064820184905260a06084830152600060a483015282169063f242432a9060c401612103565b60405162461bcd60e51b815260206004820152603a60248201527f576520646f6e2774207265636f676e697a6520746865204e465420617320656960448201527f7468657220616e20455243373231206f7220455243313135352e00000000000060648201526084016103c8565b5050505050565b6000807fa1256d2ec85dd26efb1698fa9529054aea4fa62544e3706929ea4369a070f9d59050600081856000015186602001518760400151886060015189608001518a60a001518b60c001518c60e00151604051602001611ac5999897969594939291909889526001600160a01b0397881660208a01529590961660408801526060870193909352608086019190915260a085015260c084015260e08301919091526101008201526101200190565b60075460405163ec4210ff60e01b81526001600160a01b0384811660048301526000926103e89234929091169063ec4210ff9060240160206040518083038186803b1580156124a657600080fd5b505afa1580156124ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124de9190612f7b565b6124e8919061322e565b6124f2919061320c565b905060006103e834600354612507919061322e565b612511919061320c565b9050600081612520843461324d565b61252a919061324d565b905082156125b757600754604051632df5cb2360e01b81526001600160a01b0387811660048301526125b7921690632df5cb239060240160206040518083038186803b15801561257957600080fd5b505afa15801561258d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125b19190612bdd565b846126be565b6002546125d490600160401b90046001600160a01b0316836126be565b6123a284826126be565b60008060006125ed85856127dc565b915091506125fa8161284c565b509392505050565b6000807fd8cd6ad6b8b9687d823bb6d654d776eca89193c4a9a90685e0428cd60268af619050600081856000015186602001518760400151886060015189608001518a60a001518b60c001518c60e001518d6101000151604051602001611ac59a99989796959493929190998a526001600160a01b0398891660208b01529690971660408901526060880194909452608087019290925260a086015260c085015260e08401526101008301919091526101208201526101400190565b8047101561270e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016103c8565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461275b576040519150601f19603f3d011682016040523d82523d6000602084013e612760565b606091505b50509050806127d75760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016103c8565b505050565b6000808251604114156128135760208301516040840151606085015160001a61280787828585612a07565b94509450505050612845565b82516040141561283d5760208301516040840151612832868383612af4565b935093505050612845565b506000905060025b9250929050565b6000816004811115612860576128606132aa565b14156128695750565b600181600481111561287d5761287d6132aa565b14156128cb5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016103c8565b60028160048111156128df576128df6132aa565b141561292d5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016103c8565b6003816004811115612941576129416132aa565b141561299a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016103c8565b60048160048111156129ae576129ae6132aa565b1415610eff5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016103c8565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612a3e5750600090506003612aeb565b8460ff16601b14158015612a5657508460ff16601c14155b15612a675750600090506004612aeb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612abb573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612ae457600060019250925050612aeb565b9150600090505b94509492505050565b6000806001600160ff1b03831660ff84901c601b01612b1587828885612a07565b935093505050935093915050565b8035612b2e816132d6565b919050565b600082601f830112612b4457600080fd5b813567ffffffffffffffff80821115612b5f57612b5f6132c0565b604051601f8301601f19908116603f01168101908282118183101715612b8757612b876132c0565b81604052838152866020858801011115612ba057600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215612bd257600080fd5b8135610fbb816132d6565b600060208284031215612bef57600080fd5b8151610fbb816132d6565b600080600080600080600080610100898b031215612c1757600080fd5b8835612c22816132d6565b97506020890135612c32816132d6565b965060408901359550606089013594506080890135935060a0890135925060c0890135915060e089013567ffffffffffffffff811115612c7157600080fd5b612c7d8b828c01612b33565b9150509295985092959890939650565b60008060008060008060008060006101208a8c031215612cac57600080fd5b8935612cb7816132d6565b985060208a0135612cc7816132d6565b975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff811115612d0657600080fd5b612d128c828d01612b33565b9250506101008a0135612d24816132d6565b809150509295985092959850929598565b6000806000806000806000806000806101408b8d031215612d5557600080fd5b8a35612d60816132d6565b995060208b0135612d70816132d6565b985060408b0135975060608b0135965060808b0135955060a08b0135945060c08b0135935060e08b013592506101008b013567ffffffffffffffff811115612db757600080fd5b612dc38d828e01612b33565b9250506101208b0135612dd5816132d6565b809150509295989b9194979a5092959850565b60008060008060008060008060008060006101608c8e031215612e0a57600080fd5b8b35612e15816132d6565b9a5060208c0135612e25816132d6565b995060408c0135985060608c0135975060808c0135965060a08c0135955060c08c0135945060e08c013593506101008c013592506101208c013567ffffffffffffffff811115612e7457600080fd5b612e808e828f01612b33565b925050612e906101408d01612b23565b90509295989b509295989b9093969950565b60008060408385031215612eb557600080fd5b8235612ec0816132d6565b91506020830135612ed0816132d6565b809150509250929050565b600080600060608486031215612ef057600080fd5b8335612efb816132d6565b92506020840135612f0b816132d6565b929592945050506040919091013590565b600060208284031215612f2e57600080fd5b81518015158114610fbb57600080fd5b600060208284031215612f5057600080fd5b813567ffffffffffffffff811115612f6757600080fd5b612f7384828501612b33565b949350505050565b600060208284031215612f8d57600080fd5b5051919050565b60008060008060808587031215612faa57600080fd5b5050823594602084013594506040840135936060013592509050565b60008251612fd8818460208701613264565b9190910192915050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6020815260008251806020840152613025816040850160208701613264565b601f01601f19169190910160400192915050565b6020808252601e908201527f54686973206f7264657220686173206265656e2063616e63656c6c65642e0000604082015260600190565b60208082526038908201527f5468652054726164696e6720636f6e7472616374206973206e6f74206170707260408201527f6f76656420746f206f7065726174652074686973204e46540000000000000000606082015260800190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252602d908201527f43616c6c6572206d7573742062652045786368616e6765204f776e6572206f7260408201526c1027b93232b91029b4b3b732b960991b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526024908201527f5369676e6174757265206973206e6f742076616c696420666f72204275794f726040820152633232b91760e11b606082015260800190565b6000821982111561320757613207613294565b500190565b60008261322957634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161561324857613248613294565b500290565b60008282101561325f5761325f613294565b500390565b60005b8381101561327f578181015183820152602001613267565b8381111561328e576000848401525b50505050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610eff57600080fdfea26469706673582212206e445daf296ab3f1ecf04535e7eacee47e6fdad02140113b516a5813b7717b8464736f6c63430008070033
Deployed ByteCode Sourcemap
47661:22198:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;57603:335;;;;;;;;;;-1:-1:-1;57603:335:0;;;;;:::i;:::-;;:::i;:::-;;56220:125;;;;;;;;;;-1:-1:-1;56220:125:0;;;;;:::i;:::-;;:::i;55707:170::-;;;;;;;;;;-1:-1:-1;55707:170:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;9875:32:1;;;9857:51;;9845:2;9830:18;55707:170:0;;;;;;;;69714:140;;;;;;;;;;;;;:::i;56601:67::-;;;;;;;;;;;;;:::i;55048:590::-;;;;;;;;;;-1:-1:-1;55048:590:0;;;;;:::i;:::-;;:::i;60384:623::-;;;;;;:::i;:::-;;:::i;58012:151::-;;;;;;;;;;-1:-1:-1;58012:151:0;;;;;:::i;:::-;;:::i;:::-;;;13692:14:1;;13685:22;13667:41;;13655:2;13640:18;58012:151:0;13527:187:1;42610:86:0;;;;;;;;;;-1:-1:-1;42657:4:0;42681:7;-1:-1:-1;;;42681:7:0;;;;42610:86;;2711:103;;;;;;;;;;;;;:::i;56441:63::-;;;;;;;;;;;;;:::i;2060:87::-;;;;;;;;;;-1:-1:-1;2106:7:0;2133:6;-1:-1:-1;;;;;2133:6:0;2060:87;;51210:118;;;;;;;;;;-1:-1:-1;51210:118:0;;;;;:::i;:::-;;:::i;51568:801::-;;;;;;:::i;:::-;;:::i;50933:267::-;;;;;;;;;;-1:-1:-1;50933:267:0;;;;;:::i;:::-;;:::i;66312:573::-;;;;;;;;;;-1:-1:-1;66312:573:0;;;;;:::i;:::-;;:::i;:::-;;;29525:25:1;;;29513:2;29498:18;66312:573:0;29379:177:1;56725:785:0;;;;;;;;;;-1:-1:-1;56725:785:0;;;;;:::i;:::-;;:::i;55984:164::-;;;;;;;;;;-1:-1:-1;55984:164:0;;;;;:::i;:::-;;:::i;63529:1005::-;;;;;;:::i;:::-;;:::i;2969:201::-;;;;;;;;;;-1:-1:-1;2969:201:0;;;;;:::i;:::-;;:::i;57603:335::-;-1:-1:-1;;;;;57750:20:0;;860:10;57750:20;;:47;;-1:-1:-1;2106:7:0;2133:6;-1:-1:-1;;;;;2133:6:0;860:10;57774:23;57750:47;57741:107;;;;-1:-1:-1;;;57741:107:0;;;;;;;:::i;:::-;;;;;;;;;57859:20;;:71;;-1:-1:-1;;;57859:71:0;;-1:-1:-1;;;;;57859:20:0;;;;:45;;:71;;57905:4;;57911:9;;57922:7;;57859:71;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;57603:335;;;:::o;56220:125::-;2106:7;2133:6;-1:-1:-1;;;;;2133:6:0;860:10;2280:23;2272:68;;;;-1:-1:-1;;;2272:68:0;;;;;;;:::i;:::-;56307:12:::1;:30:::0;;-1:-1:-1;;;;;56307:30:0;;::::1;-1:-1:-1::0;;;56307:30:0::1;-1:-1:-1::0;;;;;;56307:30:0;;::::1;::::0;;;::::1;::::0;;56220:125::o;55707:170::-;55813:15;;:56;;-1:-1:-1;;;55813:56:0;;-1:-1:-1;;;;;9875:32:1;;;55813:56:0;;;9857:51:1;55786:7:0;;55813:15;;:39;;9830:18:1;;55813:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;55806:63;55707:170;-1:-1:-1;;55707:170:0:o;69714:140::-;2106:7;2133:6;-1:-1:-1;;;;;2133:6:0;860:10;2280:23;2272:68;;;;-1:-1:-1;;;2272:68:0;;;;;;;:::i;:::-;69809:37:::1;::::0;69777:21:::1;::::0;69817:10:::1;::::0;69809:37;::::1;;;::::0;69777:21;;69762:12:::1;69809:37:::0;69762:12;69809:37;69777:21;69817:10;69809:37;::::1;;;;;;;;;;;;;::::0;::::1;;;;;;69751:103;69714:140::o:0;56601:67::-;2106:7;2133:6;-1:-1:-1;;;;;2133:6:0;860:10;2280:23;2272:68;;;;-1:-1:-1;;;2272:68:0;;;;;;;:::i;:::-;56650:10:::1;:8;:10::i;:::-;56601:67::o:0;55048:590::-;55197:19;;55178:15;:38;;55170:84;;;;-1:-1:-1;;;55170:84:0;;22427:2:1;55170:84:0;;;22409:21:1;22466:2;22446:18;;;22439:30;22505:34;22485:18;;;22478:62;-1:-1:-1;;;22556:18:1;;;22549:31;22597:19;;55170:84:0;22225:397:1;55170:84:0;55307:18;;55273:53;;-1:-1:-1;;;;;55273:33:0;;;55307:18;;55273:33;:53::i;:::-;:111;;;-1:-1:-1;55364:19:0;;55330:54;;-1:-1:-1;;;;;55330:33:0;;;55364:19;;;;;55330:33;:54::i;:::-;55265:148;;;;-1:-1:-1;;;55265:148:0;;22074:2:1;55265:148:0;;;22056:21:1;22113:2;22093:18;;;22086:30;22152:26;22132:18;;;22125:54;22196:18;;55265:148:0;21872:348:1;55265:148:0;55426:26;55463:15;55426:53;;55514:18;-1:-1:-1;;;;;55514:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;55498:42:0;860:10;-1:-1:-1;;;;;55498:42:0;;55490:51;;;;;;55554:15;;:76;;-1:-1:-1;;;55554:76:0;;-1:-1:-1;;;;;55554:15:0;;;;:26;;:76;;55581:15;;55598:14;;55614:15;;55554:76;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55159:479;55048:590;;;:::o;60384:623::-;42657:4;42681:7;-1:-1:-1;;;42681:7:0;;;;42935:9;42927:38;;;;-1:-1:-1;;;42927:38:0;;;;;;;:::i;:::-;45614:1:::1;46212:7;;:19;;46204:63;;;;-1:-1:-1::0;;;46204:63:0::1;;;;;;;:::i;:::-;45614:1;46345:7;:18:::0;60761:183:::2;::::0;;::::2;::::0;::::2;::::0;;-1:-1:-1;;;;;60761:183:0;;::::2;::::0;;;::::2;;::::0;::::2;::::0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60957:42:::2;60761:183:::0;60981:9;60992:6;60957:13:::2;:42::i;:::-;-1:-1:-1::0;;45570:1:0::1;46524:22:::0;;-1:-1:-1;;;;;;;;60384:623:0:o;58012:151::-;58107:20;;:48;;-1:-1:-1;;;58107:48:0;;58083:4;;-1:-1:-1;;;;;58107:20:0;;:37;;:48;;58145:9;;58107:48;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;2711:103::-;2106:7;2133:6;-1:-1:-1;;;;;2133:6:0;860:10;2280:23;2272:68;;;;-1:-1:-1;;;2272:68:0;;;;;;;:::i;:::-;2776:30:::1;2803:1;2776:18;:30::i;56441:63::-:0;2106:7;2133:6;-1:-1:-1;;;;;2133:6:0;860:10;2280:23;2272:68;;;;-1:-1:-1;;;2272:68:0;;;;;;;:::i;:::-;56488:8:::1;:6;:8::i;51210:118::-:0;2106:7;2133:6;-1:-1:-1;;;;;2133:6:0;860:10;2280:23;2272:68;;;;-1:-1:-1;;;2272:68:0;;;;;;;:::i;:::-;51286:12:::1;:34:::0;;-1:-1:-1;;;;;;51286:34:0::1;-1:-1:-1::0;;;;;51286:34:0;;;::::1;::::0;;;::::1;::::0;;51210:118::o;51568:801::-;42657:4;42681:7;-1:-1:-1;;;42681:7:0;;;;42935:9;42927:38;;;;-1:-1:-1;;;42927:38:0;;;;;;;:::i;:::-;45614:1:::1;46212:7;;:19;;46204:63;;;;-1:-1:-1::0;;;46204:63:0::1;;;;;;;:::i;:::-;45614:1;46345:7;:18:::0;51968:9:::2;:18:::0;-1:-1:-1;51968:18:0::2;51960:83;;;::::0;-1:-1:-1;;;51960:83:0;;26055:2:1;51960:83:0::2;::::0;::::2;26037:21:1::0;26094:2;26074:18;;;26067:30;26133:34;26113:18;;;26106:62;-1:-1:-1;;;26184:18:1;;;26177:50;26244:19;;51960:83:0::2;25853:416:1::0;51960:83:0::2;52056:26;52085:220;;;;;;;;52109:6;-1:-1:-1::0;;;;;52085:220:0::2;;;;;52130:15;-1:-1:-1::0;;;;;52085:220:0::2;;;;;52160:7;52085:220;;;;52182:9;52085:220;;;;52206:10;52085:220;;;;52231:5;52085:220;;;;52251:8;52085:220;;;;52274:20;52085:220;;::::0;52056:249:::2;;52318:43;52333:9;52344;52355:5;52318:14;:43::i;:::-;-1:-1:-1::0;;45570:1:0::1;46524:22:::0;;-1:-1:-1;;;;;;;;;51568:801:0:o;50933:267::-;2106:7;2133:6;-1:-1:-1;;;;;2133:6:0;860:10;2280:23;2272:68;;;;-1:-1:-1;;;2272:68:0;;;;;;;:::i;:::-;51056:15:::1;:55:::0;;-1:-1:-1;;;;;51056:55:0;;::::1;-1:-1:-1::0;;;;;;51056:55:0;;::::1;;::::0;;;51122:20:::1;:70:::0;;;;;::::1;::::0;::::1;;::::0;;50933:267::o;66312:573::-;66438:7;;66485:19;66495:9;66485:7;:19;:::i;:::-;66458:47;-1:-1:-1;66516:21:0;66541:25;66551:15;66541:7;:25;:::i;:::-;66516:51;-1:-1:-1;66580:25:0;66648:29;66516:51;66648:13;:29;:::i;:::-;66609:34;66628:15;66609:16;:34;:::i;:::-;66608:70;;;;:::i;:::-;66580:98;-1:-1:-1;66691:22:0;66716:21;66729:8;66716:10;:21;:::i;:::-;66691:46;-1:-1:-1;66748:31:0;66821:4;66783:34;66691:46;66783:17;:34;:::i;:::-;66782:43;;;;:::i;:::-;66748:77;-1:-1:-1;66843:34:0;66748:77;66843:8;:34;:::i;:::-;66836:41;66312:573;-1:-1:-1;;;;;;;;;;66312:573:0:o;56725:785::-;-1:-1:-1;;;;;57018:21:0;;860:10;57018:21;;:48;;-1:-1:-1;2106:7:0;2133:6;-1:-1:-1;;;;;2133:6:0;860:10;57043:23;57018:48;57009:108;;;;-1:-1:-1;;;57009:108:0;;;;;;;:::i;:::-;57130:24;57157:183;;;;;;;;57180:5;-1:-1:-1;;;;;57157:183:0;;;;;57200:15;-1:-1:-1;;;;;57157:183:0;;;;;57230:7;57157:183;;;;57252:9;57157:183;;;;57276:10;57157:183;;;;57301:5;57157:183;;;;57321:8;57157:183;;;57130:210;;57361:44;57385:8;57395:9;57361:23;:44::i;:::-;57353:93;;;;-1:-1:-1;;;57353:93:0;;;;;;;:::i;:::-;57459:20;;:43;;-1:-1:-1;;;57459:43:0;;-1:-1:-1;;;;;57459:20:0;;;;:32;;:43;;57492:9;;57459:43;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56998:512;56725:785;;;;;;;;:::o;55984:164::-;56087:15;;:53;;-1:-1:-1;;;56087:53:0;;-1:-1:-1;;;;;9875:32:1;;;56087:53:0;;;9857:51:1;56060:7:0;;56087:15;;:36;;9830:18:1;;56087:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;63529:1005::-;42657:4;42681:7;-1:-1:-1;;;42681:7:0;;;;42935:9;42927:38;;;;-1:-1:-1;;;42927:38:0;;;;;;;:::i;:::-;45614:1:::1;46212:7;;:19;;46204:63;;;;-1:-1:-1::0;;;46204:63:0::1;;;;;;;:::i;:::-;45614:1;46345:7;:18:::0;63958:20:::2;63981:63;64003:9:::0;64014:7;64023:10;64035:8;63981:21:::2;:63::i;:::-;63958:86;;64076:12;64063:9;:25;;64055:93;;;::::0;-1:-1:-1;;;64055:93:0;;28730:2:1;64055:93:0::2;::::0;::::2;28712:21:1::0;28769:2;28749:18;;;28742:30;28808:34;28788:18;;;28781:62;28879:25;28859:18;;;28852:53;28922:19;;64055:93:0::2;28528:419:1::0;64055:93:0::2;64161:42;64206:253;;;;;;;;64238:6;-1:-1:-1::0;;;;;64206:253:0::2;;;;;64259:15;-1:-1:-1::0;;;;;64206:253:0::2;;;;;64289:7;64206:253;;;;64311:9;64206:253;;;;64335:7;64206:253;;;;64357:10;64206:253;;;;64382:8;64206:253;;;;64405:8;64206:253;;;;64428:20;64206:253;;::::0;64161:298:::2;;64472:54;64490:17;64509:9;64520:5;64472:17;:54::i;:::-;-1:-1:-1::0;;45570:1:0::1;46524:22:::0;;-1:-1:-1;;;;;;;;;;;63529:1005:0:o;2969:201::-;2106:7;2133:6;-1:-1:-1;;;;;2133:6:0;860:10;2280:23;2272:68;;;;-1:-1:-1;;;2272:68:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;3058:22:0;::::1;3050:73;;;::::0;-1:-1:-1;;;3050:73:0;;18822:2:1;3050:73:0::1;::::0;::::1;18804:21:1::0;18861:2;18841:18;;;18834:30;18900:34;18880:18;;;18873:62;-1:-1:-1;;;18951:18:1;;;18944:36;18997:19;;3050:73:0::1;18620:402:1::0;3050:73:0::1;3134:28;3153:8;3134:18;:28::i;:::-;2969:201:::0;:::o;43669:120::-;42657:4;42681:7;-1:-1:-1;;;42681:7:0;;;;43205:41;;;;-1:-1:-1;;;43205:41:0;;17754:2:1;43205:41:0;;;17736:21:1;17793:2;17773:18;;;17766:30;-1:-1:-1;;;17812:18:1;;;17805:50;17872:18;;43205:41:0;17552:344:1;43205:41:0;43738:5:::1;43728:15:::0;;-1:-1:-1;;;;43728:15:0::1;::::0;;43759:22:::1;860:10:::0;43768:12:::1;43759:22;::::0;-1:-1:-1;;;;;9875:32:1;;;9857:51;;9845:2;9830:18;43759:22:0::1;;;;;;;43669:120::o:0;18235:277::-;18322:4;18431:23;18446:7;18431:14;:23::i;:::-;:73;;;;;18458:46;18483:7;18492:11;18458:24;:46::i;:::-;18424:80;18235:277;-1:-1:-1;;;18235:277:0:o;61015:2240::-;61195:27;61212:9;61195:16;:27::i;:::-;61194:28;61186:71;;;;-1:-1:-1;;;61186:71:0;;;;;;;:::i;:::-;61315:44;61339:8;61349:9;61315:23;:44::i;:::-;61307:93;;;;-1:-1:-1;;;61307:93:0;;;;;;;:::i;:::-;61473:8;:18;;;61455:15;:36;61446:78;;;;-1:-1:-1;;;61446:78:0;;27248:2:1;61446:78:0;;;27230:21:1;27287:2;27267:18;;;27260:30;27326:29;27306:18;;;27299:57;27373:18;;61446:78:0;27046:351:1;61446:78:0;61597:8;:19;;;61579:15;:37;61570:79;;;;-1:-1:-1;;;61570:79:0;;27248:2:1;61570:79:0;;;27230:21:1;27287:2;27267:18;;;27260:30;27326:29;27306:18;;;27299:57;27373:18;;61570:79:0;27046:351:1;61570:79:0;61757:14;;;;61716:12;;61739:14;;61716:38;;-1:-1:-1;;;61716:38:0;;-1:-1:-1;;;;;9875:32:1;;;61716:38:0;;;9857:51:1;61716:12:0;;;:22;;9830:18:1;;61716:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:55;61708:103;;;;-1:-1:-1;;;61708:103:0;;20482:2:1;61708:103:0;;;20464:21:1;20521:2;20501:18;;;20494:30;20560:34;20540:18;;;20533:62;-1:-1:-1;;;20611:18:1;;;20604:33;20654:19;;61708:103:0;20280:399:1;61708:103:0;61941:14;;;;61885:12;;61908:14;;61885:53;;-1:-1:-1;;;61885:53:0;;-1:-1:-1;;;;;10373:15:1;;;61885:53:0;;;10355:34:1;61932:4:0;10405:18:1;;;10398:43;61885:12:0;;;:22;;10290:18:1;;61885:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:70;61877:129;;;;-1:-1:-1;;;61877:129:0;;26833:2:1;61877:129:0;;;26815:21:1;26872:2;26852:18;;;26845:30;26911:34;26891:18;;;26884:62;-1:-1:-1;;;26962:18:1;;;26955:44;27016:19;;61877:129:0;26631:410:1;61877:129:0;62100:99;62113:8;:24;;;62139:8;:16;;;62157:6;62165:8;:14;;;62181:8;:17;;;62100:12;:99::i;:::-;62310:14;;;;:18;62306:691;;62435:14;;;;62370:15;;62407:24;;;;62370:62;;-1:-1:-1;;;62370:62:0;;-1:-1:-1;;;;;9875:32:1;;;62370:62:0;;;9857:51:1;62345:21:0;;62453:4;;62435:14;;62370:15;;:36;;9830:18:1;;62370:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:79;;;;:::i;:::-;62369:88;;;;:::i;:::-;62345:112;;62472:19;62533:4;62515:8;:14;;;62495:17;;:34;;;;:::i;:::-;62494:43;;;;:::i;:::-;62472:65;;62552:23;62611:11;62595:13;62578:8;:14;;;:30;;;;:::i;:::-;:44;;;;:::i;:::-;62552:70;-1:-1:-1;62643:17:0;;62639:181;;62681:12;;62707:14;;62723:15;;62763:24;;;;62723:65;;-1:-1:-1;;;62723:65:0;;-1:-1:-1;;;;;9875:32:1;;;62723:65:0;;;9857:51:1;62681:12:0;;;;:25;;62707:14;62723:15;;;;;:39;;9830:18:1;;62723:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;62790:13;62681:123;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;62639:181;62836:12;;62862:14;;62878:12;;62836:68;;-1:-1:-1;;;62836:68:0;;-1:-1:-1;;;;;62836:12:0;;;;:25;;:68;;62862:14;;-1:-1:-1;;;62878:12:0;;;;;;;62892:11;;62836:68;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;62919:12:0;;62945:14;;62919:66;;-1:-1:-1;;;62919:66:0;;-1:-1:-1;;;;;62919:12:0;;;;:25;;:66;;62961:6;;62969:15;;62919:66;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;62330:667;;;62306:691;63090:20;;:43;;-1:-1:-1;;;63090:43:0;;-1:-1:-1;;;;;63090:20:0;;;;:32;;:43;;63123:9;;63090:43;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;63214:16:0;;;;;63188:24;;;;;63172:14;;63232;;;;63149:98;;-1:-1:-1;;;;;11444:32:1;;;11426:51;;11493:18;;;11486:34;63214:16:0;;-1:-1:-1;63149:98:0;;;;;;;;;11399:18:1;63149:98:0;;;;;;;;61015:2240;;;:::o;3330:191::-;3404:16;3423:6;;-1:-1:-1;;;;;3440:17:0;;;-1:-1:-1;;;;;;3440:17:0;;;;;;3473:40;;3423:6;;;;;;;3473:40;;3404:16;3473:40;3393:128;3330:191;:::o;43410:118::-;42657:4;42681:7;-1:-1:-1;;;42681:7:0;;;;42935:9;42927:38;;;;-1:-1:-1;;;42927:38:0;;;;;;;:::i;:::-;43470:7:::1;:14:::0;;-1:-1:-1;;;;43470:14:0::1;-1:-1:-1::0;;;43470:14:0::1;::::0;;43500:20:::1;43507:12;860:10:::0;;780:98;52489:1677;52890:30;;;;52767:20;;52824:16;;52842:25;;;;52869:17;;;;;52767:120;;-1:-1:-1;;;52767:120:0;;-1:-1:-1;;;;;52767:20:0;;;;:56;;:120;;52824:16;;52842:25;;52767:120;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:153;52745:233;;;;-1:-1:-1;;;52745:233:0;;;;;;;:::i;:::-;53030:46;53055:9;53066;53030:24;:46::i;:::-;53022:96;;;;-1:-1:-1;;;53022:96:0;;24472:2:1;53022:96:0;;;24454:21:1;24511:2;24491:18;;;24484:30;24550:34;24530:18;;;24523:62;-1:-1:-1;;;24601:18:1;;;24594:35;24646:19;;53022:96:0;24270:401:1;53022:96:0;53188:9;:19;;;53170:15;:37;53161:121;;;;-1:-1:-1;;;53161:121:0;;22829:2:1;53161:121:0;;;22811:21:1;22868:2;22848:18;;;22841:30;22907:34;22887:18;;;22880:62;22978:34;22958:18;;;22951:62;-1:-1:-1;;;23029:19:1;;;23022:36;23075:19;;53161:121:0;22627:473:1;53161:121:0;53352:9;:20;;;53334:15;:38;53325:81;;;;-1:-1:-1;;;53325:81:0;;26476:2:1;53325:81:0;;;26458:21:1;26515:2;26495:18;;;26488:30;26554;26534:18;;;26527:58;26602:18;;53325:81:0;26274:352:1;53325:81:0;53550:103;53563:9;:25;;;53590:9;:17;;;53609:9;:16;;;53627:5;53634:9;:18;;;53550:12;:103::i;:::-;53762:74;53792:9;:25;;;53819:9;:16;;;53762:29;:74::i;:::-;53930:20;;53976:16;;53994:25;;;;54021:17;;;;;53930:109;;-1:-1:-1;;;53930:109:0;;-1:-1:-1;;;;;53930:20:0;;;;:45;;:109;;53976:16;;53994:25;;53930:109;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54123:9;:17;;;54096:9;:25;;;-1:-1:-1;;;;;54055:103:0;54071:9;:16;;;-1:-1:-1;;;;;54055:103:0;;54089:5;54142:9;:15;;;54055:103;;;;;;-1:-1:-1;;;;;11444:32:1;;;;11426:51;;11508:2;11493:18;;11486:34;11414:2;11399:18;;11236:290;59367:897:0;59473:4;59492:25;59520:168;59492:196;;59701:18;59761:17;59797:8;:14;;;59830:8;:24;;;59873:8;:16;;;59908:8;:18;;;59945:8;:19;;;59983:8;:14;;;60016:8;:17;;;59732:316;;;;;;;;;;;;;;14078:25:1;;;-1:-1:-1;;;;;14177:15:1;;;14172:2;14157:18;;14150:43;14229:15;;;;14224:2;14209:18;;14202:43;14276:2;14261:18;;14254:34;;;;14319:3;14304:19;;14297:35;14130:3;14348:19;;14341:35;14407:3;14392:19;;14385:35;;;;14451:3;14436:19;;14429:35;14065:3;14050:19;;13719:751;59732:316:0;;;;-1:-1:-1;;59732:316:0;;;;;;;;;59722:327;;59732:316;59722:327;;;;60101:16;;-1:-1:-1;;;33244:57:0;;;9362:27:1;9405:11;;;9398:27;9441:12;;;;9434:28;;;33244:57:0;;;;;;;;;;9478:12:1;;;;33244:57:0;;;33234:68;;;;;;;;59722:327;;-1:-1:-1;60143:24:0;60170:32;60184:6;60192:9;60170:13;:32::i;:::-;60242:14;;-1:-1:-1;;;;;60222:34:0;;;;;;;-1:-1:-1;;;;;59367:897:0;;;;:::o;64542:1762::-;64935:38;;;;64788:20;;64845:24;;64871:33;;;;64906:25;;;;;64788:144;;-1:-1:-1;;;64788:144:0;;-1:-1:-1;;;;;64788:20:0;;;;:56;;:144;;64845:24;;64871:33;;64788:144;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:185;64766:265;;;;-1:-1:-1;;;64766:265:0;;;;;;;:::i;:::-;65089:60;65120:17;65139:9;65089:30;:60::i;:::-;65081:118;;;;-1:-1:-1;;;65081:118:0;;19654:2:1;65081:118:0;;;19636:21:1;19693:2;19673:18;;;19666:30;19732:34;19712:18;;;19705:62;-1:-1:-1;;;19783:18:1;;;19776:43;19836:19;;65081:118:0;19452:409:1;65081:118:0;65287:17;:27;;;65269:15;:45;65260:105;;;;-1:-1:-1;;;65260:105:0;;20068:2:1;65260:105:0;;;20050:21:1;20107:2;20087:18;;;20080:30;20146:34;20126:18;;;20119:62;-1:-1:-1;;;20197:18:1;;;20190:43;20250:19;;65260:105:0;19866:409:1;65260:105:0;65435:17;:25;;;65417:15;:43;65408:95;;;;-1:-1:-1;;;65408:95:0;;24066:2:1;65408:95:0;;;24048:21:1;24105:2;24085:18;;;24078:30;24144:34;24124:18;;;24117:62;-1:-1:-1;;;24195:18:1;;;24188:35;24240:19;;65408:95:0;23864:401:1;65408:95:0;65597:135;65610:17;:33;;;65645:17;:25;;;65672:17;:24;;;65698:5;65705:17;:26;;;65597:12;:135::i;:::-;65839:90;65869:17;:33;;;65904:17;:24;;;65839:29;:90::i;:::-;66023:20;;66069:24;;66095:33;;;;66130:25;;;;;66023:133;;-1:-1:-1;;;66023:133:0;;-1:-1:-1;;;;;66023:20:0;;;;:45;;:133;;66069:24;;66095:33;;66023:133;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;66259:17;:25;;;66224:17;:33;;;-1:-1:-1;;;;;66172:124:0;66191:17;:24;;;-1:-1:-1;;;;;66172:124:0;;66217:5;66286:9;66172:124;;;;;;-1:-1:-1;;;;;11444:32:1;;;;11426:51;;11508:2;11493:18;;11486:34;11414:2;11399:18;;11236:290;17592:417:0;17656:4;17867:60;17892:7;-1:-1:-1;;;17867:24:0;:60::i;:::-;:134;;;;-1:-1:-1;17945:56:0;17970:7;-1:-1:-1;;;;;;17945:24:0;:56::i;:::-;17944:57;17847:154;17592:417;-1:-1:-1;;17592:417:0:o;21196:414::-;21335:71;;;-1:-1:-1;;;;;;16768:33:1;;21335:71:0;;;;16750:52:1;;;;21335:71:0;;;;;;;;;;16723:18:1;;;;21335:71:0;;;;;;;-1:-1:-1;;;;;21335:71:0;-1:-1:-1;;;21335:71:0;;;21455:45;;21289:4;;21335:71;21289:4;;;;-1:-1:-1;;;;;21455:18:0;;;21479:5;;21455:45;;21335:71;;21455:45;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21417:83;;;;21531:2;21515:6;:13;:18;21511:36;;;21542:5;21535:12;;;;;;;21511:36;21565:7;:37;;;;;21587:6;21576:26;;;;;;;;;;;;:::i;:::-;21558:44;21196:414;-1:-1:-1;;;;;;21196:414:0:o;68102:1514::-;68273:18;;68239:53;;-1:-1:-1;;;;;68239:33:0;;;68273:18;;68239:33;:53::i;:::-;68235:1374;;;68423:23;;-1:-1:-1;;;68423:23:0;;;;;29525:25:1;;;68334:15:0;;-1:-1:-1;;;;;68423:33:0;;;;:14;;;;;;29498:18:1;;68423:23:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68423:33:0;;68414:80;;;;-1:-1:-1;;;68414:80:0;;27604:2:1;68414:80:0;;;27586:21:1;;;27623:18;;;27616:30;27682:34;27662:18;;;27655:62;27734:18;;68414:80:0;27402:356:1;68414:80:0;68569:46;;-1:-1:-1;;;68569:46:0;;-1:-1:-1;;;;;10373:15:1;;;68569:46:0;;;10355:34:1;68609:4:0;10405:18:1;;;10398:43;68569:23:0;;;;;10290:18:1;;68569:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;68561:115;;;;-1:-1:-1;;;68561:115:0;;;;;;;:::i;:::-;68786:47;;-1:-1:-1;;;68786:47:0;;-1:-1:-1;;;;;68786:23:0;;;;;:47;;68810:6;;68818:5;;68825:7;;68786:47;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;68294:553;68235:1374;;;68891:19;;68857:54;;-1:-1:-1;;;;;68857:33:0;;;68891:19;;;;;68857:33;:54::i;:::-;68853:756;;;69044:34;;-1:-1:-1;;;69044:34:0;;-1:-1:-1;;;;;11444:32:1;;;69044:34:0;;;11426:51:1;11493:18;;;11486:34;;;68956:15:0;;69082:8;;69044:17;;;;;11399:18:1;;69044:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:46;;69036:103;;;;-1:-1:-1;;;69036:103:0;;25281:2:1;69036:103:0;;;25263:21:1;25320:2;25300:18;;;25293:30;25359:34;25339:18;;;25332:62;-1:-1:-1;;;25410:18:1;;;25403:42;25462:19;;69036:103:0;25079:408:1;69036:103:0;69214:47;;-1:-1:-1;;;69214:47:0;;-1:-1:-1;;;;;10373:15:1;;;69214:47:0;;;10355:34:1;69255:4:0;10405:18:1;;;10398:43;69214:24:0;;;;;10290:18:1;;69214:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;69206:116;;;;-1:-1:-1;;;69206:116:0;;;;;;;:::i;:::-;69432:62;;-1:-1:-1;;;69432:62:0;;-1:-1:-1;;;;;12967:15:1;;;69432:62:0;;;12949:34:1;13019:15;;;12999:18;;;12992:43;13051:18;;;13044:34;;;13094:18;;;13087:34;;;12929:3;13137:19;;;13130:32;-1:-1:-1;13178:19:1;;;13171:30;69432:24:0;;;;;13218:19:1;;69432:62:0;12616:627:1;68853:756:0;69529:68;;-1:-1:-1;;;69529:68:0;;29154:2:1;69529:68:0;;;29136:21:1;29193:2;29173:18;;;29166:30;29232:34;29212:18;;;29205:62;29303:28;29283:18;;;29276:56;29349:19;;69529:68:0;28952:422:1;68853:756:0;68102:1514;;;;;:::o;58270:990::-;58379:4;58398:26;58427:199;58398:228;;58639:18;58699;58736:9;:16;;;58771:9;:25;;;58815:9;:17;;;58851:9;:19;;;58889:9;:20;;;58928:9;:15;;;58962:9;:18;;;58999:9;:30;;;58670:374;;;;;;;;;;;;;;;14862:25:1;;;-1:-1:-1;;;;;14961:15:1;;;14956:2;14941:18;;14934:43;15013:15;;;;15008:2;14993:18;;14986:43;15060:2;15045:18;;15038:34;;;;15103:3;15088:19;;15081:35;;;;14914:3;15132:19;;15125:35;15191:3;15176:19;;15169:35;15235:3;15220:19;;15213:35;;;;15279:3;15264:19;;15257:35;14849:3;14834:19;;14475:823;54277:641:0;54418:15;;:53;;-1:-1:-1;;;54418:53:0;;-1:-1:-1;;;;;9875:32:1;;;54418:53:0;;;9857:51:1;54393:21:0;;54487:4;;54474:9;;54418:15;;;;:36;;9830:18:1;;54418:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:65;;;;:::i;:::-;54417:74;;;;:::i;:::-;54393:98;;54502:19;54558:4;54545:9;54525:17;;:29;;;;:::i;:::-;54524:38;;;;:::i;:::-;54502:60;-1:-1:-1;54573:23:0;54502:60;54599:25;54611:13;54599:9;:25;:::i;:::-;:39;;;;:::i;:::-;54573:65;-1:-1:-1;54657:17:0;;54653:140;;54709:15;;:56;;-1:-1:-1;;;54709:56:0;;-1:-1:-1;;;;;9875:32:1;;;54709:56:0;;;9857:51:1;54691:90:0;;54709:15;;:39;;9830:18:1;;54709:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;54767:13;54691:17;:90::i;:::-;54823:12;;54805:44;;-1:-1:-1;;;54823:12:0;;-1:-1:-1;;;;;54823:12:0;54837:11;54805:17;:44::i;:::-;54860:50;54878:14;54894:15;54860:17;:50::i;28153:231::-;28231:7;28252:17;28271:18;28293:27;28304:4;28310:9;28293:10;:27::i;:::-;28251:69;;;;28331:18;28343:5;28331:11;:18::i;:::-;-1:-1:-1;28367:9:0;28153:231;-1:-1:-1;;;28153:231:0:o;66893:1201::-;67049:4;67068:34;67105:226;67068:263;;67344:18;67404:26;67449:17;:24;;;67492:17;:33;;;67544:17;:25;;;67588:17;:27;;;67634:17;:25;;;67678:17;:28;;;67725:17;:26;;;67770:17;:26;;;67815:17;:38;;;67375:493;;;;;;;;;;;;;;;;15718:25:1;;;-1:-1:-1;;;;;15817:15:1;;;15812:2;15797:18;;15790:43;15869:15;;;;15864:2;15849:18;;15842:43;15916:2;15901:18;;15894:34;;;;15959:3;15944:19;;15937:35;;;;15770:3;15988:19;;15981:35;16047:3;16032:19;;16025:35;16091:3;16076:19;;16069:35;16135:3;16120:19;;16113:35;;;;16179:3;16164:19;;16157:35;15705:3;15690:19;;15303:895;35465:317:0;35580:6;35555:21;:31;;35547:73;;;;-1:-1:-1;;;35547:73:0;;21716:2:1;35547:73:0;;;21698:21:1;21755:2;21735:18;;;21728:30;21794:31;21774:18;;;21767:59;21843:18;;35547:73:0;21514:353:1;35547:73:0;35634:12;35652:9;-1:-1:-1;;;;;35652:14:0;35674:6;35652:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35633:52;;;35704:7;35696:78;;;;-1:-1:-1;;;35696:78:0;;20886:2:1;35696:78:0;;;20868:21:1;20925:2;20905:18;;;20898:30;20964:34;20944:18;;;20937:62;21035:28;21015:18;;;21008:56;21081:19;;35696:78:0;20684:422:1;35696:78:0;35536:246;35465:317;;:::o;26043:1308::-;26124:7;26133:12;26358:9;:16;26378:2;26358:22;26354:990;;;26654:4;26639:20;;26633:27;26704:4;26689:20;;26683:27;26762:4;26747:20;;26741:27;26397:9;26733:36;26805:25;26816:4;26733:36;26633:27;26683;26805:10;:25::i;:::-;26798:32;;;;;;;;;26354:990;26852:9;:16;26872:2;26852:22;26848:496;;;27127:4;27112:20;;27106:27;27178:4;27163:20;;27157:27;27220:23;27231:4;27106:27;27157;27220:10;:23::i;:::-;27213:30;;;;;;;;26848:496;-1:-1:-1;27292:1:0;;-1:-1:-1;27296:35:0;26848:496;26043:1308;;;;;:::o;24314:643::-;24392:20;24383:5;:29;;;;;;;;:::i;:::-;;24379:571;;;24314:643;:::o;24379:571::-;24490:29;24481:5;:38;;;;;;;;:::i;:::-;;24477:473;;;24536:34;;-1:-1:-1;;;24536:34:0;;17401:2:1;24536:34:0;;;17383:21:1;17440:2;17420:18;;;17413:30;17479:26;17459:18;;;17452:54;17523:18;;24536:34:0;17199:348:1;24477:473:0;24601:35;24592:5;:44;;;;;;;;:::i;:::-;;24588:362;;;24653:41;;-1:-1:-1;;;24653:41:0;;18103:2:1;24653:41:0;;;18085:21:1;18142:2;18122:18;;;18115:30;18181:33;18161:18;;;18154:61;18232:18;;24653:41:0;17901:355:1;24588:362:0;24725:30;24716:5;:39;;;;;;;;:::i;:::-;;24712:238;;;24772:44;;-1:-1:-1;;;24772:44:0;;21313:2:1;24772:44:0;;;21295:21:1;21352:2;21332:18;;;21325:30;21391:34;21371:18;;;21364:62;-1:-1:-1;;;21442:18:1;;;21435:32;21484:19;;24772:44:0;21111:398:1;24712:238:0;24847:30;24838:5;:39;;;;;;;;:::i;:::-;;24834:116;;;24894:44;;-1:-1:-1;;;24894:44:0;;24878:2:1;24894:44:0;;;24860:21:1;24917:2;24897:18;;;24890:30;24956:34;24936:18;;;24929:62;-1:-1:-1;;;25007:18:1;;;25000:32;25049:19;;24894:44:0;24676:398:1;29652:1632:0;29783:7;;30717:66;30704:79;;30700:163;;;-1:-1:-1;30816:1:0;;-1:-1:-1;30820:30:0;30800:51;;30700:163;30877:1;:7;;30882:2;30877:7;;:18;;;;;30888:1;:7;;30893:2;30888:7;;30877:18;30873:102;;;-1:-1:-1;30928:1:0;;-1:-1:-1;30932:30:0;30912:51;;30873:102;31089:24;;;31072:14;31089:24;;;;;;;;;16430:25:1;;;16503:4;16491:17;;16471:18;;;16464:45;;;;16525:18;;;16518:34;;;16568:18;;;16561:34;;;31089:24:0;;16402:19:1;;31089:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;31089:24:0;;-1:-1:-1;;31089:24:0;;;-1:-1:-1;;;;;;;31128:20:0;;31124:103;;31181:1;31185:29;31165:50;;;;;;;31124:103;31247:6;-1:-1:-1;31255:20:0;;-1:-1:-1;29652:1632:0;;;;;;;;:::o;28647:391::-;28761:7;;-1:-1:-1;;;;;28862:75:0;;28964:3;28960:12;;;28974:2;28956:21;29005:25;29016:4;28956:21;29025:1;28862:75;29005:10;:25::i;:::-;28998:32;;;;;;28647:391;;;;;;:::o;14:134:1:-;82:20;;111:31;82:20;111:31;:::i;:::-;14:134;;;:::o;153:718::-;195:5;248:3;241:4;233:6;229:17;225:27;215:55;;266:1;263;256:12;215:55;302:6;289:20;328:18;365:2;361;358:10;355:36;;;371:18;;:::i;:::-;446:2;440:9;414:2;500:13;;-1:-1:-1;;496:22:1;;;520:2;492:31;488:40;476:53;;;544:18;;;564:22;;;541:46;538:72;;;590:18;;:::i;:::-;630:10;626:2;619:22;665:2;657:6;650:18;711:3;704:4;699:2;691:6;687:15;683:26;680:35;677:55;;;728:1;725;718:12;677:55;792:2;785:4;777:6;773:17;766:4;758:6;754:17;741:54;839:1;832:4;827:2;819:6;815:15;811:26;804:37;859:6;850:15;;;;;;153:718;;;;:::o;876:247::-;935:6;988:2;976:9;967:7;963:23;959:32;956:52;;;1004:1;1001;994:12;956:52;1043:9;1030:23;1062:31;1087:5;1062:31;:::i;1128:251::-;1198:6;1251:2;1239:9;1230:7;1226:23;1222:32;1219:52;;;1267:1;1264;1257:12;1219:52;1299:9;1293:16;1318:31;1343:5;1318:31;:::i;1908:949::-;2047:6;2055;2063;2071;2079;2087;2095;2103;2156:3;2144:9;2135:7;2131:23;2127:33;2124:53;;;2173:1;2170;2163:12;2124:53;2212:9;2199:23;2231:31;2256:5;2231:31;:::i;:::-;2281:5;-1:-1:-1;2338:2:1;2323:18;;2310:32;2351:33;2310:32;2351:33;:::i;:::-;2403:7;-1:-1:-1;2457:2:1;2442:18;;2429:32;;-1:-1:-1;2508:2:1;2493:18;;2480:32;;-1:-1:-1;2559:3:1;2544:19;;2531:33;;-1:-1:-1;2611:3:1;2596:19;;2583:33;;-1:-1:-1;2663:3:1;2648:19;;2635:33;;-1:-1:-1;2719:3:1;2704:19;;2691:33;2747:18;2736:30;;2733:50;;;2779:1;2776;2769:12;2733:50;2802:49;2843:7;2834:6;2823:9;2819:22;2802:49;:::i;:::-;2792:59;;;1908:949;;;;;;;;;;;:::o;2862:1099::-;3018:6;3026;3034;3042;3050;3058;3066;3074;3082;3135:3;3123:9;3114:7;3110:23;3106:33;3103:53;;;3152:1;3149;3142:12;3103:53;3191:9;3178:23;3210:31;3235:5;3210:31;:::i;:::-;3260:5;-1:-1:-1;3317:2:1;3302:18;;3289:32;3330:33;3289:32;3330:33;:::i;:::-;3382:7;-1:-1:-1;3436:2:1;3421:18;;3408:32;;-1:-1:-1;3487:2:1;3472:18;;3459:32;;-1:-1:-1;3538:3:1;3523:19;;3510:33;;-1:-1:-1;3590:3:1;3575:19;;3562:33;;-1:-1:-1;3642:3:1;3627:19;;3614:33;;-1:-1:-1;3698:3:1;3683:19;;3670:33;3726:18;3715:30;;3712:50;;;3758:1;3755;3748:12;3712:50;3781:49;3822:7;3813:6;3802:9;3798:22;3781:49;:::i;:::-;3771:59;;;3882:3;3871:9;3867:19;3854:33;3896;3921:7;3896:33;:::i;:::-;3948:7;3938:17;;;2862:1099;;;;;;;;;;;:::o;3966:1168::-;4131:6;4139;4147;4155;4163;4171;4179;4187;4195;4203;4256:3;4244:9;4235:7;4231:23;4227:33;4224:53;;;4273:1;4270;4263:12;4224:53;4312:9;4299:23;4331:31;4356:5;4331:31;:::i;:::-;4381:5;-1:-1:-1;4438:2:1;4423:18;;4410:32;4451:33;4410:32;4451:33;:::i;:::-;4503:7;-1:-1:-1;4557:2:1;4542:18;;4529:32;;-1:-1:-1;4608:2:1;4593:18;;4580:32;;-1:-1:-1;4659:3:1;4644:19;;4631:33;;-1:-1:-1;4711:3:1;4696:19;;4683:33;;-1:-1:-1;4763:3:1;4748:19;;4735:33;;-1:-1:-1;4815:3:1;4800:19;;4787:33;;-1:-1:-1;4871:3:1;4856:19;;4843:33;4899:18;4888:30;;4885:50;;;4931:1;4928;4921:12;4885:50;4954:49;4995:7;4986:6;4975:9;4971:22;4954:49;:::i;:::-;4944:59;;;5055:3;5044:9;5040:19;5027:33;5069;5094:7;5069:33;:::i;:::-;5121:7;5111:17;;;3966:1168;;;;;;;;;;;;;:::o;5139:1172::-;5313:6;5321;5329;5337;5345;5353;5361;5369;5377;5385;5393:7;5447:3;5435:9;5426:7;5422:23;5418:33;5415:53;;;5464:1;5461;5454:12;5415:53;5503:9;5490:23;5522:31;5547:5;5522:31;:::i;:::-;5572:5;-1:-1:-1;5629:2:1;5614:18;;5601:32;5642:33;5601:32;5642:33;:::i;:::-;5694:7;-1:-1:-1;5748:2:1;5733:18;;5720:32;;-1:-1:-1;5799:2:1;5784:18;;5771:32;;-1:-1:-1;5850:3:1;5835:19;;5822:33;;-1:-1:-1;5902:3:1;5887:19;;5874:33;;-1:-1:-1;5954:3:1;5939:19;;5926:33;;-1:-1:-1;6006:3:1;5991:19;;5978:33;;-1:-1:-1;6058:3:1;6043:19;;6030:33;;-1:-1:-1;6114:3:1;6099:19;;6086:33;6142:18;6131:30;;6128:50;;;6174:1;6171;6164:12;6128:50;6197:49;6238:7;6229:6;6218:9;6214:22;6197:49;:::i;:::-;6187:59;;;6266:39;6300:3;6289:9;6285:19;6266:39;:::i;:::-;6255:50;;5139:1172;;;;;;;;;;;;;;:::o;6316:388::-;6384:6;6392;6445:2;6433:9;6424:7;6420:23;6416:32;6413:52;;;6461:1;6458;6451:12;6413:52;6500:9;6487:23;6519:31;6544:5;6519:31;:::i;:::-;6569:5;-1:-1:-1;6626:2:1;6611:18;;6598:32;6639:33;6598:32;6639:33;:::i;:::-;6691:7;6681:17;;;6316:388;;;;;:::o;6709:464::-;6794:6;6802;6810;6863:2;6851:9;6842:7;6838:23;6834:32;6831:52;;;6879:1;6876;6869:12;6831:52;6918:9;6905:23;6937:31;6962:5;6937:31;:::i;:::-;6987:5;-1:-1:-1;7044:2:1;7029:18;;7016:32;7057:33;7016:32;7057:33;:::i;:::-;6709:464;;7109:7;;-1:-1:-1;;;7163:2:1;7148:18;;;;7135:32;;6709:464::o;7639:277::-;7706:6;7759:2;7747:9;7738:7;7734:23;7730:32;7727:52;;;7775:1;7772;7765:12;7727:52;7807:9;7801:16;7860:5;7853:13;7846:21;7839:5;7836:32;7826:60;;7882:1;7879;7872:12;7921:320;7989:6;8042:2;8030:9;8021:7;8017:23;8013:32;8010:52;;;8058:1;8055;8048:12;8010:52;8098:9;8085:23;8131:18;8123:6;8120:30;8117:50;;;8163:1;8160;8153:12;8117:50;8186:49;8227:7;8218:6;8207:9;8203:22;8186:49;:::i;:::-;8176:59;7921:320;-1:-1:-1;;;;7921:320:1:o;8246:184::-;8316:6;8369:2;8357:9;8348:7;8344:23;8340:32;8337:52;;;8385:1;8382;8375:12;8337:52;-1:-1:-1;8408:16:1;;8246:184;-1:-1:-1;8246:184:1:o;8435:385::-;8521:6;8529;8537;8545;8598:3;8586:9;8577:7;8573:23;8569:33;8566:53;;;8615:1;8612;8605:12;8566:53;-1:-1:-1;;8638:23:1;;;8708:2;8693:18;;8680:32;;-1:-1:-1;8759:2:1;8744:18;;8731:32;;8810:2;8795:18;8782:32;;-1:-1:-1;8435:385:1;-1:-1:-1;8435:385:1:o;8825:274::-;8954:3;8992:6;8986:13;9008:53;9054:6;9049:3;9042:4;9034:6;9030:17;9008:53;:::i;:::-;9077:16;;;;;8825:274;-1:-1:-1;;8825:274:1:o;10452:391::-;-1:-1:-1;;;;;10726:15:1;;;10708:34;;10778:15;;;;10773:2;10758:18;;10751:43;10825:2;10810:18;;10803:34;;;;10658:2;10643:18;;10452:391::o;16813:381::-;16960:2;16949:9;16942:21;16923:4;16992:6;16986:13;17035:6;17030:2;17019:9;17015:18;17008:34;17051:66;17110:6;17105:2;17094:9;17090:18;17085:2;17077:6;17073:15;17051:66;:::i;:::-;17178:2;17157:15;-1:-1:-1;;17153:29:1;17138:45;;;;17185:2;17134:54;;16813:381;-1:-1:-1;;16813:381:1:o;18261:354::-;18463:2;18445:21;;;18502:2;18482:18;;;18475:30;18541:32;18536:2;18521:18;;18514:60;18606:2;18591:18;;18261:354::o;19027:420::-;19229:2;19211:21;;;19268:2;19248:18;;;19241:30;19307:34;19302:2;19287:18;;19280:62;19378:26;19373:2;19358:18;;19351:54;19437:3;19422:19;;19027:420::o;23105:340::-;23307:2;23289:21;;;23346:2;23326:18;;;23319:30;-1:-1:-1;;;23380:2:1;23365:18;;23358:46;23436:2;23421:18;;23105:340::o;23450:409::-;23652:2;23634:21;;;23691:2;23671:18;;;23664:30;23730:34;23725:2;23710:18;;23703:62;-1:-1:-1;;;23796:2:1;23781:18;;23774:43;23849:3;23834:19;;23450:409::o;25492:356::-;25694:2;25676:21;;;25713:18;;;25706:30;25772:34;25767:2;25752:18;;25745:62;25839:2;25824:18;;25492:356::o;27763:355::-;27965:2;27947:21;;;28004:2;27984:18;;;27977:30;28043:33;28038:2;28023:18;;28016:61;28109:2;28094:18;;27763:355::o;28123:400::-;28325:2;28307:21;;;28364:2;28344:18;;;28337:30;28403:34;28398:2;28383:18;;28376:62;-1:-1:-1;;;28469:2:1;28454:18;;28447:34;28513:3;28498:19;;28123:400::o;29561:128::-;29601:3;29632:1;29628:6;29625:1;29622:13;29619:39;;;29638:18;;:::i;:::-;-1:-1:-1;29674:9:1;;29561:128::o;29694:217::-;29734:1;29760;29750:132;;29804:10;29799:3;29795:20;29792:1;29785:31;29839:4;29836:1;29829:15;29867:4;29864:1;29857:15;29750:132;-1:-1:-1;29896:9:1;;29694:217::o;29916:168::-;29956:7;30022:1;30018;30014:6;30010:14;30007:1;30004:21;29999:1;29992:9;29985:17;29981:45;29978:71;;;30029:18;;:::i;:::-;-1:-1:-1;30069:9:1;;29916:168::o;30089:125::-;30129:4;30157:1;30154;30151:8;30148:34;;;30162:18;;:::i;:::-;-1:-1:-1;30199:9:1;;30089:125::o;30219:258::-;30291:1;30301:113;30315:6;30312:1;30309:13;30301:113;;;30391:11;;;30385:18;30372:11;;;30365:39;30337:2;30330:10;30301:113;;;30432:6;30429:1;30426:13;30423:48;;;30467:1;30458:6;30453:3;30449:16;30442:27;30423:48;;30219:258;;;:::o;30482:127::-;30543:10;30538:3;30534:20;30531:1;30524:31;30574:4;30571:1;30564:15;30598:4;30595:1;30588:15;30614:127;30675:10;30670:3;30666:20;30663:1;30656:31;30706:4;30703:1;30696:15;30730:4;30727:1;30720:15;30746:127;30807:10;30802:3;30798:20;30795:1;30788:31;30838:4;30835:1;30828:15;30862:4;30859:1;30852:15;30878:131;-1:-1:-1;;;;;30953:31:1;;30943:42;;30933:70;;30999:1;30996;30989:12
Swarm Source
ipfs://6e445daf296ab3f1ecf04535e7eacee47e6fdad02140113b516a5813b7717b84
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.