Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
12901942 | 1234 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
Shelf
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-07-26 */ // Verified using https://dapp.tools // hevm: flattened sources of src/borrower/shelf.sol // SPDX-License-Identifier: AGPL-3.0-only AND MIT pragma solidity >=0.5.15 >=0.6.12 >=0.6.0 <0.8.0 >=0.7.0 <0.8.0; ////// lib/tinlake-auth/src/auth.sol // Copyright (C) Centrifuge 2020, based on MakerDAO dss https://github.com/makerdao/dss /* pragma solidity >=0.5.15; */ contract Auth { mapping (address => uint256) public wards; event Rely(address indexed usr); event Deny(address indexed usr); function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); } function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); } modifier auth { require(wards[msg.sender] == 1, "not-authorized"); _; } } ////// lib/tinlake-math/src/math.sol // Copyright (C) 2018 Rain <[email protected]> /* pragma solidity >=0.5.15; */ contract Math { uint256 constant ONE = 10 ** 27; function safeAdd(uint x, uint y) public pure returns (uint z) { require((z = x + y) >= x, "safe-add-failed"); } function safeSub(uint x, uint y) public pure returns (uint z) { require((z = x - y) <= x, "safe-sub-failed"); } function safeMul(uint x, uint y) public pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, "safe-mul-failed"); } function safeDiv(uint x, uint y) public pure returns (uint z) { z = x / y; } function rmul(uint x, uint y) public pure returns (uint z) { z = safeMul(x, y) / ONE; } function rdiv(uint x, uint y) public pure returns (uint z) { require(y > 0, "division by zero"); z = safeAdd(safeMul(x, ONE), y / 2) / y; } function rdivup(uint x, uint y) internal pure returns (uint z) { require(y > 0, "division by zero"); // always rounds up z = safeAdd(safeMul(x, ONE), safeSub(y, 1)) / y; } } ////// lib/tinlake-title/src/openzeppelin-solidity/introspection/IERC165.sol /* pragma solidity ^0.7.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); } ////// lib/tinlake-title/src/openzeppelin-solidity/introspection/ERC165.sol /* pragma solidity ^0.7.0; */ /* import "./IERC165.sol"; */ /** * @dev Implementation of the {IERC165} interface. * * Contracts may inherit from this and call {_registerInterface} to declare * their support of an interface. */ abstract contract ERC165 is IERC165 { /* * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; constructor () { // Derived contracts need only register support for their own interfaces, // we register support for ERC165 itself here _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev See {IERC165-supportsInterface}. * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See {IERC165-supportsInterface}. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal virtual { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } ////// lib/tinlake-title/src/openzeppelin-solidity/math/SafeMath.sol /* pragma solidity ^0.7.0; */ /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } } ////// lib/tinlake-title/src/openzeppelin-solidity/token/ERC721/IERC721.sol /* pragma solidity ^0.7.0; */ /* import "../../introspection/IERC165.sol"; */ /** * @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; } ////// lib/tinlake-title/src/openzeppelin-solidity/token/ERC721/IERC721Enumerable.sol /* pragma solidity ^0.7.0; */ /* import "./IERC721.sol"; */ /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); } ////// lib/tinlake-title/src/openzeppelin-solidity/token/ERC721/IERC721Metadata.sol /* pragma solidity ^0.7.0; */ /* import "./IERC721.sol"; */ /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); } ////// lib/tinlake-title/src/openzeppelin-solidity/token/ERC721/IERC721Receiver.sol /* pragma solidity ^0.7.0; */ /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. */ function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4); } ////// lib/tinlake-title/src/openzeppelin-solidity/utils/Address.sol /* pragma solidity ^0.7.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; // solhint-disable-next-line no-inline-assembly 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"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (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"); // solhint-disable-next-line avoid-low-level-calls (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"); // solhint-disable-next-line avoid-low-level-calls (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"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private 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 // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } ////// lib/tinlake-title/src/openzeppelin-solidity/utils/Context.sol /* pragma solidity >=0.6.0 <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 GSN 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 payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } ////// lib/tinlake-title/src/openzeppelin-solidity/utils/EnumerableMap.sol /* pragma solidity ^0.7.0; */ /** * @dev Library for managing an enumerable variant of Solidity's * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] * type. * * Maps have the following properties: * * - Entries are added, removed, and checked for existence in constant time * (O(1)). * - Entries are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableMap for EnumerableMap.UintToAddressMap; * * // Declare a set state variable * EnumerableMap.UintToAddressMap private myMap; * } * ``` * * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are * supported. */ library EnumerableMap { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Map type with // bytes32 keys and values. // The Map implementation uses private functions, and user-facing // implementations (such as Uint256ToAddressMap) are just wrappers around // the underlying Map. // This means that we can only create new EnumerableMaps for types that fit // in bytes32. struct MapEntry { bytes32 _key; bytes32 _value; } struct Map { // Storage of map keys and values MapEntry[] _entries; // Position of the entry defined by a key in the `entries` array, plus 1 // because index 0 means a key is not in the map. mapping (bytes32 => uint256) _indexes; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) { // We read and store the key's index to prevent multiple reads from the same storage slot uint256 keyIndex = map._indexes[key]; if (keyIndex == 0) { // Equivalent to !contains(map, key) map._entries.push(MapEntry({ _key: key, _value: value })); // The entry is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value map._indexes[key] = map._entries.length; return true; } else { map._entries[keyIndex - 1]._value = value; return false; } } /** * @dev Removes a key-value pair from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function _remove(Map storage map, bytes32 key) private returns (bool) { // We read and store the key's index to prevent multiple reads from the same storage slot uint256 keyIndex = map._indexes[key]; if (keyIndex != 0) { // Equivalent to contains(map, key) // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one // in the array, and then remove the last entry (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = keyIndex - 1; uint256 lastIndex = map._entries.length - 1; // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. MapEntry storage lastEntry = map._entries[lastIndex]; // Move the last entry to the index where the entry to delete is map._entries[toDeleteIndex] = lastEntry; // Update the index for the moved entry map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved entry was stored map._entries.pop(); // Delete the index for the deleted slot delete map._indexes[key]; return true; } else { return false; } } /** * @dev Returns true if the key is in the map. O(1). */ function _contains(Map storage map, bytes32 key) private view returns (bool) { return map._indexes[key] != 0; } /** * @dev Returns the number of key-value pairs in the map. O(1). */ function _length(Map storage map) private view returns (uint256) { return map._entries.length; } /** * @dev Returns the key-value pair stored at position `index` in the map. O(1). * * Note that there are no guarantees on the ordering of entries inside the * array, and it may change when more entries are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) { require(map._entries.length > index, "EnumerableMap: index out of bounds"); MapEntry storage entry = map._entries[index]; return (entry._key, entry._value); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) { uint256 keyIndex = map._indexes[key]; if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key) return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function _get(Map storage map, bytes32 key) private view returns (bytes32) { uint256 keyIndex = map._indexes[key]; require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key) return map._entries[keyIndex - 1]._value; // All indexes are 1-based } /** * @dev Same as {_get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {_tryGet}. */ function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) { uint256 keyIndex = map._indexes[key]; require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key) return map._entries[keyIndex - 1]._value; // All indexes are 1-based } // UintToAddressMap struct UintToAddressMap { Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { return _remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { return _contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToAddressMap storage map) internal view returns (uint256) { return _length(map._inner); } /** * @dev Returns the element stored at position `index` in the set. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { (bytes32 key, bytes32 value) = _at(map._inner, index); return (uint256(key), address(uint160(uint256(value)))); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. * * _Available since v3.4._ */ function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { (bool success, bytes32 value) = _tryGet(map._inner, bytes32(key)); return (success, address(uint160(uint256(value)))); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { return address(uint160(uint256(_get(map._inner, bytes32(key))))); } /** * @dev Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) { return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage)))); } } ////// lib/tinlake-title/src/openzeppelin-solidity/utils/EnumerableSet.sol /* pragma solidity ^0.7.0; */ /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping (bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } } ////// lib/tinlake-title/src/openzeppelin-solidity/utils/Strings.sol /* pragma solidity ^0.7.0; */ /** * @dev String operations. */ library Strings { /** * @dev Converts a `uint256` to its ASCII `string` 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); uint256 index = digits - 1; temp = value; while (temp != 0) { buffer[index--] = bytes1(uint8(48 + temp % 10)); temp /= 10; } return string(buffer); } } ////// lib/tinlake-title/src/openzeppelin-solidity/token/ERC721/ERC721.sol /* pragma solidity ^0.7.0; */ /* import "../../utils/Context.sol"; */ /* import "./IERC721.sol"; */ /* import "./IERC721Metadata.sol"; */ /* import "./IERC721Enumerable.sol"; */ /* import "./IERC721Receiver.sol"; */ /* import "../../introspection/ERC165.sol"; */ /* import "../../math/SafeMath.sol"; */ /* import "../../utils/Address.sol"; */ /* import "../../utils/EnumerableSet.sol"; */ /* import "../../utils/EnumerableMap.sol"; */ /* import "../../utils/Strings.sol"; */ /** * @title ERC721 Non-Fungible Token Standard basic implementation * @dev see https://eips.ethereum.org/EIPS/eip-721 */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable { using SafeMath for uint256; using Address for address; using EnumerableSet for EnumerableSet.UintSet; using EnumerableMap for EnumerableMap.UintToAddressMap; using Strings for uint256; // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; // Mapping from holder address to their (enumerable) set of owned tokens mapping (address => EnumerableSet.UintSet) private _holderTokens; // Enumerable mapping from token ids to their owners EnumerableMap.UintToAddressMap private _tokenOwners; // Mapping from token ID to approved address mapping (uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping (address => mapping (address => bool)) private _operatorApprovals; // Token name string private _name; // Token symbol string private _symbol; // Optional mapping for token URIs mapping (uint256 => string) private _tokenURIs; // Base URI string private _baseURI; /* * bytes4(keccak256('balanceOf(address)')) == 0x70a08231 * bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5 * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde * * => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^ * 0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd */ bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd; /* * bytes4(keccak256('name()')) == 0x06fdde03 * bytes4(keccak256('symbol()')) == 0x95d89b41 * bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd * * => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f */ bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f; /* * bytes4(keccak256('totalSupply()')) == 0x18160ddd * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59 * bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7 * * => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63 */ bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor (string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; // register the supported interfaces to conform to ERC721 via ERC165 _registerInterface(_INTERFACE_ID_ERC721); _registerInterface(_INTERFACE_ID_ERC721_METADATA); _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _holderTokens[owner].length(); } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token"); } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); string memory _tokenURI = _tokenURIs[tokenId]; string memory base = baseURI(); // If there is no base URI, return the token URI. if (bytes(base).length == 0) { return _tokenURI; } // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked). if (bytes(_tokenURI).length > 0) { return string(abi.encodePacked(base, _tokenURI)); } // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI. return string(abi.encodePacked(base, tokenId.toString())); } /** * @dev Returns the base URI set via {_setBaseURI}. This will be * automatically added as a prefix in {tokenURI} to each token's URI, or * to the token ID if no specific URI is set for that token ID. */ function baseURI() public view virtual returns (string memory) { return _baseURI; } /** * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. */ function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { return _holderTokens[owner].at(index); } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds return _tokenOwners.length(); } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view virtual override returns (uint256) { (uint256 tokenId, ) = _tokenOwners.at(index); return tokenId; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require(_msgSender() == owner || ERC721.isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not owner nor approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { require(operator != _msgSender(), "ERC721: approve to caller"); _operatorApprovals[_msgSender()][operator] = approved; emit ApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom(address from, address to, uint256 tokenId) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _safeTransfer(from, to, tokenId, _data); } /** * @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. * * `_data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _tokenOwners.contains(tokenId); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ERC721.ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || ERC721.isApprovedForAll(owner, spender)); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: d* * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { _mint(to, tokenId); require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId); _holderTokens[to].add(tokenId); _tokenOwners.set(tokenId, to); emit Transfer(address(0), to, tokenId); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); // internal owner _beforeTokenTransfer(owner, address(0), tokenId); // Clear approvals _approve(address(0), tokenId); // Clear metadata (if any) if (bytes(_tokenURIs[tokenId]).length != 0) { delete _tokenURIs[tokenId]; } _holderTokens[owner].remove(tokenId); _tokenOwners.remove(tokenId); emit Transfer(owner, address(0), tokenId); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer(address from, address to, uint256 tokenId) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); // internal owner require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId); // Clear approvals from the previous owner _approve(address(0), tokenId); _holderTokens[from].remove(tokenId); _holderTokens[to].add(tokenId); _tokenOwners.set(tokenId, to); emit Transfer(from, to, tokenId); } /** * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token"); _tokenURIs[tokenId] = _tokenURI; } /** * @dev Internal function to set the base URI for all token IDs. It is * automatically added as a prefix to the value returned in {tokenURI}, * or to the token ID if {tokenURI} is empty. */ function _setBaseURI(string memory baseURI_) internal virtual { _baseURI = baseURI_; } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) private returns (bool) { if (!to.isContract()) { return true; } bytes memory returndata = to.functionCall(abi.encodeWithSelector( IERC721Receiver(to).onERC721Received.selector, _msgSender(), from, tokenId, _data ), "ERC721: transfer to non ERC721Receiver implementer"); bytes4 retval = abi.decode(returndata, (bytes4)); return (retval == _ERC721_RECEIVED); } /** * @dev Approve `to` to operate on `tokenId` * * Emits an {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); // internal owner } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` cannot be the zero address. * - `to` cannot be the zero address. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } } ////// lib/tinlake-title/src/title.sol /* pragma solidity ^0.7.0; */ /* import { ERC721 } from "./openzeppelin-solidity/token/ERC721/ERC721.sol"; */ /* import { Auth } from "tinlake-auth/auth.sol"; */ contract Title is Auth, ERC721 { // --- Data --- uint public count; string public uri; constructor (string memory name, string memory symbol) ERC721(name, symbol) { wards[msg.sender] = 1; count = 1; } // --- Title --- function issue (address usr) public auth returns (uint) { return _issue(usr); } function _issue (address usr) internal returns (uint) { _mint(usr, count); count += 1; // can't overflow, not enough gas in the world to pay for 2**256 nfts. return count-1; } function close (uint tkn) public auth { _burn(tkn); } } interface TitleLike_1 { function issue(address) external returns (uint); function close(uint) external; function ownerOf (uint) external view returns (address); } contract TitleOwned { TitleLike_1 title; constructor (address title_) { title = TitleLike_1(title_); } modifier owner (uint loan) { require(title.ownerOf(loan) == msg.sender); _; } } ////// src/borrower/shelf.sol /* pragma solidity >=0.6.12; */ /* import "tinlake-math/math.sol"; */ /* import "tinlake-auth/auth.sol"; */ /* import { TitleOwned, TitleLike } from "tinlake-title/title.sol"; */ interface NFTLike_2 { function ownerOf(uint256 tokenId) external view returns (address owner); function transferFrom(address from, address to, uint256 tokenId) external; } interface TokenLike_1 { function totalSupply() external view returns(uint); function balanceOf(address) external view returns (uint); function transferFrom(address,address,uint) external returns (bool); function transfer(address, uint) external returns (bool); function approve(address, uint) external; } interface PileLike_3 { function total() external view returns(uint); function debt(uint) external returns (uint); function accrue(uint) external; function incDebt(uint, uint) external; function decDebt(uint, uint) external; } interface NAVFeedLike_2 { function borrow(uint loan, uint currencyAmount) external; function repay(uint loan, uint currencyAmount) external; } interface ReserveLike_2 { function balance() external; } interface SubscriberLike { function borrowEvent(uint loan) external; function unlockEvent(uint loan) external; } interface AssessorLike_1 { function reBalance() external; } contract Shelf is Auth, TitleOwned, Math { // --- Data --- NAVFeedLike_2 public ceiling; PileLike_3 public pile; TokenLike_1 public currency; ReserveLike_2 public reserve; AssessorLike_1 public assessor; SubscriberLike public subscriber; uint public balance; address public lender; struct Loan { address registry; uint256 tokenId; } mapping (uint => uint) public balances; mapping (uint => Loan) public shelf; mapping (bytes32 => uint) public nftlookup; // Events event Close(uint indexed loan); event Issue(address indexed registry_, uint indexed token_); event Borrow(uint indexed loan, uint currencyAmount); event Withdraw(uint indexed loan, uint currencyAmount, address usr); event Repay(uint indexed loan, uint currencyAmount); event Recover(uint indexed loan, address usr, uint currencyAmount); event Lock(uint indexed loan); event Unlock(uint indexed loan); event Claim(uint indexed loan, address usr); event Depend(bytes32 indexed contractName, address addr); constructor(address currency_, address title_, address pile_, address ceiling_) TitleOwned(title_) { currency = TokenLike_1(currency_); pile = PileLike_3(pile_); ceiling = NAVFeedLike_2(ceiling_); wards[msg.sender] = 1; emit Rely(msg.sender); } // sets the dependency to another contract function depend(bytes32 contractName, address addr) external auth { if (contractName == "lender") { if (lender != address(0)) currency.approve(lender, uint(0)); currency.approve(addr, type(uint256).max); lender = addr; } else if (contractName == "token") { currency = TokenLike_1(addr); } else if (contractName == "title") { title = TitleLike_1(addr); } else if (contractName == "pile") { pile = PileLike_3(addr); } else if (contractName == "ceiling") { ceiling = NAVFeedLike_2(addr); } else if (contractName == "reserve") { reserve = ReserveLike_2(addr); } else if (contractName == "assessor") { assessor = AssessorLike_1(addr);} else if (contractName == "subscriber") { subscriber = SubscriberLike(addr); } else revert(); emit Depend(contractName, addr); } function token(uint loan) public view returns (address registry, uint nft) { return (shelf[loan].registry, shelf[loan].tokenId); } // issues a new loan in Tinlake - it requires the ownership of an nft // first step in the loan process - everyone could add an nft function issue(address registry_, uint token_) external returns (uint) { require(NFTLike_2(registry_).ownerOf(token_) == msg.sender, "nft-not-owned"); bytes32 nft = keccak256(abi.encodePacked(registry_, token_)); require(nftlookup[nft] == 0, "nft-in-use"); uint loan = title.issue(msg.sender); nftlookup[nft] = loan; shelf[loan].registry = registry_; shelf[loan].tokenId = token_; emit Issue(registry_, token_); return loan; } function close(uint loan) external { require(pile.debt(loan) == 0, "loan-has-outstanding-debt"); require(!nftLocked(loan), "nft-not-locked"); (address registry, uint tokenId) = token(loan); require(title.ownerOf(loan) == msg.sender || NFTLike_2(registry).ownerOf(tokenId) == msg.sender, "not-loan-or-nft-owner"); title.close(loan); bytes32 nft = keccak256(abi.encodePacked(shelf[loan].registry, shelf[loan].tokenId)); nftlookup[nft] = 0; resetLoanBalance(loan); emit Close(loan); } // used by the lender contracts to know if currency is needed or currency can be taken function balanceRequest() external view returns (bool, uint) { uint currencyBalance = currency.balanceOf(address(this)); if (balance > currencyBalance) { return (true, safeSub(balance, currencyBalance)); } else { return (false, safeSub(currencyBalance, balance)); } } // starts the borrow process of a loan // informs the system of the requested currencyAmount // interest accumulation starts with this method // the method can only be called if the nft is locked // a max ceiling needs to be defined by an oracle function borrow(uint loan, uint currencyAmount) external owner(loan) { require(nftLocked(loan), "nft-not-locked"); if(address(subscriber) != address(0)) { subscriber.borrowEvent(loan); } pile.accrue(loan); balances[loan] = safeAdd(balances[loan], currencyAmount); balance = safeAdd(balance, currencyAmount); // request currency from lender contracts reserve.balance(); // increase NAV ceiling.borrow(loan, currencyAmount); pile.incDebt(loan, currencyAmount); // reBalance lender interest bearing amount based on new NAV assessor.reBalance(); emit Borrow(loan, currencyAmount); } // withdraw transfers the currency to the borrower account function withdraw(uint loan, uint currencyAmount, address usr) external owner(loan) { require(nftLocked(loan), "nft-not-locked"); require(currencyAmount <= balances[loan], "withdraw-amount-too-high"); balances[loan] = safeSub(balances[loan], currencyAmount); balance = safeSub(balance, currencyAmount); require(currency.transfer(usr, currencyAmount), "currency-transfer-failed"); emit Withdraw(loan, currencyAmount, usr); } // repays the entire or partial debt of a loan function repay(uint loan, uint currencyAmount) external owner(loan) { require(nftLocked(loan), "nft-not-locked"); require(balances[loan] == 0, "withdraw-required-before-repay"); _repay(loan, msg.sender, currencyAmount); emit Repay(loan, currencyAmount); } // a collector can recover defaulted loans // it is not required to recover the entire loan debt function recover(uint loan, address usr, uint currencyAmount) external auth { pile.accrue(loan); uint loanDebt = pile.debt(loan); require(currency.transferFrom(usr, address(this), currencyAmount), "currency-transfer-failed"); ceiling.repay(loan, loanDebt); // sets loan debt to 0 pile.decDebt(loan, loanDebt); resetLoanBalance(loan); reserve.balance(); // reBalance lender interest bearing amount based on new NAV assessor.reBalance(); emit Recover(loan, usr, currencyAmount); } function _repay(uint loan, address usr, uint currencyAmount) internal { pile.accrue(loan); uint loanDebt = pile.debt(loan); // only repay max loan debt if (currencyAmount > loanDebt) { currencyAmount = loanDebt; } require(currency.transferFrom(usr, address(this), currencyAmount), "currency-transfer-failed"); ceiling.repay(loan, currencyAmount); pile.decDebt(loan, currencyAmount); reserve.balance(); // reBalance lender interest bearing amount based on new NAV assessor.reBalance(); } // locks an nft in the shelf // requires an issued loan function lock(uint loan) external owner(loan) { if(address(subscriber) != address(0)) { subscriber.unlockEvent(loan); } NFTLike_2(shelf[loan].registry).transferFrom(msg.sender, address(this), shelf[loan].tokenId); emit Lock(loan); } // unlocks an nft in the shelf // requires zero debt function unlock(uint loan) external owner(loan) { require(pile.debt(loan) == 0, "loan-has-outstanding-debt"); NFTLike_2(shelf[loan].registry).transferFrom(address(this), msg.sender, shelf[loan].tokenId); emit Unlock(loan); } function nftLocked(uint loan) public view returns (bool) { return NFTLike_2(shelf[loan].registry).ownerOf(shelf[loan].tokenId) == address(this); } // a loan can be claimed by a collector if the loan debt is above the loan threshold // transfers the nft to the collector function claim(uint loan, address usr) public auth { NFTLike_2(shelf[loan].registry).transferFrom(address(this), usr, shelf[loan].tokenId); emit Claim(loan, usr); } function resetLoanBalance(uint loan) internal { uint loanBalance = balances[loan]; if (loanBalance > 0) { balances[loan] = 0; balance = safeSub(balance, loanBalance); } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"currency_","type":"address"},{"internalType":"address","name":"title_","type":"address"},{"internalType":"address","name":"pile_","type":"address"},{"internalType":"address","name":"ceiling_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"loan","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currencyAmount","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"loan","type":"uint256"},{"indexed":false,"internalType":"address","name":"usr","type":"address"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"loan","type":"uint256"}],"name":"Close","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"usr","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"contractName","type":"bytes32"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"Depend","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"registry_","type":"address"},{"indexed":true,"internalType":"uint256","name":"token_","type":"uint256"}],"name":"Issue","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"loan","type":"uint256"}],"name":"Lock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"loan","type":"uint256"},{"indexed":false,"internalType":"address","name":"usr","type":"address"},{"indexed":false,"internalType":"uint256","name":"currencyAmount","type":"uint256"}],"name":"Recover","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"usr","type":"address"}],"name":"Rely","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"loan","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currencyAmount","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"loan","type":"uint256"}],"name":"Unlock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"loan","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currencyAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"usr","type":"address"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"assessor","outputs":[{"internalType":"contract AssessorLike_1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceRequest","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loan","type":"uint256"},{"internalType":"uint256","name":"currencyAmount","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ceiling","outputs":[{"internalType":"contract NAVFeedLike_2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loan","type":"uint256"},{"internalType":"address","name":"usr","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loan","type":"uint256"}],"name":"close","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currency","outputs":[{"internalType":"contract TokenLike_1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"usr","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"contractName","type":"bytes32"},{"internalType":"address","name":"addr","type":"address"}],"name":"depend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"registry_","type":"address"},{"internalType":"uint256","name":"token_","type":"uint256"}],"name":"issue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loan","type":"uint256"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loan","type":"uint256"}],"name":"nftLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"nftlookup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pile","outputs":[{"internalType":"contract PileLike_3","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"rdiv","outputs":[{"internalType":"uint256","name":"z","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"loan","type":"uint256"},{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"currencyAmount","type":"uint256"}],"name":"recover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"usr","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loan","type":"uint256"},{"internalType":"uint256","name":"currencyAmount","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserve","outputs":[{"internalType":"contract ReserveLike_2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"rmul","outputs":[{"internalType":"uint256","name":"z","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"safeAdd","outputs":[{"internalType":"uint256","name":"z","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"safeDiv","outputs":[{"internalType":"uint256","name":"z","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"safeMul","outputs":[{"internalType":"uint256","name":"z","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"safeSub","outputs":[{"internalType":"uint256","name":"z","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"shelf","outputs":[{"internalType":"address","name":"registry","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"subscriber","outputs":[{"internalType":"contract SubscriberLike","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loan","type":"uint256"}],"name":"token","outputs":[{"internalType":"address","name":"registry","type":"address"},{"internalType":"uint256","name":"nft","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loan","type":"uint256"}],"name":"unlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loan","type":"uint256"},{"internalType":"uint256","name":"currencyAmount","type":"uint256"},{"internalType":"address","name":"usr","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50604051620043ce380380620043ce8339818101604052608081101561003557600080fd5b81019080805190602001909291908051906020019092919080519060200190929190805190602001909291905050508280600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505083600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff167fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a6060405160405180910390a2505050506141c980620002056000396000f3fe608060405234801561001057600080fd5b50600436106101fb5760003560e01c8063867904b41161011a578063cd3293de116100ad578063dd4670641161007c578063dd46706414610947578063ddd5e1b214610975578063e5a6b10f146109c3578063e6cb9013146109f7578063f7f0b4d614610a43576101fb565b8063cd3293de1461084d578063ce50dc7b14610881578063d05c78da146108c3578063d8aed1451461090f576101fb565b8063b5931f7c116100e9578063b5931f7c14610757578063b69ef8a8146107a3578063bcead63e146107c1578063bf353dbb146107f5576101fb565b8063867904b4146106175780639adc339d146106795780639c52a7f1146106c7578063a293d1e81461070b576101fb565b806320e036301161019257806365fae35e1161016157806365fae35e1461052c5780636745702214610570578063753ed1bd146105bc578063843f7b89146105f0576101fb565b806320e03630146104545780634903b0d1146104885780636198e339146104ca57806362f6b10f146104f8576101fb565b80630aebeb4e116101ce5780630aebeb4e1461036e5780630e2286d31461039c5780630ecbcdab146103e85780631821d69614610420576101fb565b8063044215c614610200578063056e00b31461025f57806308e45dc1146102be5780630ad58d2f14610316575b600080fd5b61022c6004803603602081101561021657600080fd5b8101908080359060200190929190505050610a87565b604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b61028b6004803603602081101561027557600080fd5b8101908080359060200190929190505050610ae1565b604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b610314600480360360608110156102d457600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b25565b005b61036c6004803603606081101561032c57600080fd5b810190808035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061110b565b005b61039a6004803603602081101561038457600080fd5b81019080803590602001909291905050506114d7565b005b6103d2600480360360408110156103b257600080fd5b810190808035906020019092919080359060200190929190505050611a11565b6040518082815260200191505060405180910390f35b61041e600480360360408110156103fe57600080fd5b810190808035906020019092919080359060200190929190505050611ac2565b005b610428612045565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61045c61206b565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6104b46004803603602081101561049e57600080fd5b8101908080359060200190929190505050612091565b6040518082815260200191505060405180910390f35b6104f6600480360360208110156104e057600080fd5b81019080803590602001909291905050506120a9565b005b6105006123d8565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61056e6004803603602081101561054257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506123fe565b005b6105a66004803603604081101561058657600080fd5b81019080803590602001909291908035906020019092919050505061253c565b6040518082815260200191505060405180910390f35b6105c4612565565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105f861258b565b6040518083151581526020018281526020019250505060405180910390f35b6106636004803603604081101561062d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050612690565b6040518082815260200191505060405180910390f35b6106c56004803603604081101561068f57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612a34565b005b610709600480360360208110156106dd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506130a6565b005b6107416004803603604081101561072157600080fd5b8101908080359060200190929190803590602001909291905050506131e4565b6040518082815260200191505060405180910390f35b61078d6004803603604081101561076d57600080fd5b810190808035906020019092919080359060200190929190505050613267565b6040518082815260200191505060405180910390f35b6107ab61327b565b6040518082815260200191505060405180910390f35b6107c9613281565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6108376004803603602081101561080b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506132a7565b6040518082815260200191505060405180910390f35b6108556132bf565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6108ad6004803603602081101561089757600080fd5b81019080803590602001909291905050506132e5565b6040518082815260200191505060405180910390f35b6108f9600480360360408110156108d957600080fd5b8101908080359060200190929190803590602001909291905050506132fd565b6040518082815260200191505060405180910390f35b6109456004803603604081101561092557600080fd5b810190808035906020019092919080359060200190929190505050613392565b005b6109736004803603602081101561095d57600080fd5b81019080803590602001909291905050506135c4565b005b6109c16004803603604081101561098b57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506138b2565b005b6109cb613aab565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610a2d60048036036040811015610a0d57600080fd5b810190808035906020019092919080359060200190929190505050613ad1565b6040518082815260200191505060405180910390f35b610a6f60048036036020811015610a5957600080fd5b8101908080359060200190929190505050613b54565b60405180821515815260200191505060405180910390f35b600080600b600084815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600b60008581526020019081526020016000206001015491509150915091565b600b6020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010154905082565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414610bd9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e6f742d617574686f72697a656400000000000000000000000000000000000081525060200191505060405180910390fd5b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663744f4cf6846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610c4e57600080fd5b505af1158015610c62573d6000803e3d6000fd5b505050506000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631e0029c8856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015610cdd57600080fd5b505af1158015610cf1573d6000803e3d6000fd5b505050506040513d6020811015610d0757600080fd5b81019080805190602001909291905050509050600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd8430856040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b158015610dcb57600080fd5b505af1158015610ddf573d6000803e3d6000fd5b505050506040513d6020811015610df557600080fd5b8101908080519060200190929190505050610e78576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f63757272656e63792d7472616e736665722d6661696c6564000000000000000081525060200191505060405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d8aed14585836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015610ef557600080fd5b505af1158015610f09573d6000803e3d6000fd5b50505050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632047a26785836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015610f8a57600080fd5b505af1158015610f9e573d6000803e3d6000fd5b50505050610fab84613c63565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b69ef8a86040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561101557600080fd5b505af1158015611029573d6000803e3d6000fd5b50505050600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663eaf151326040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561109757600080fd5b505af11580156110ab573d6000803e3d6000fd5b50505050837fc59615076045a3968279704d2a2ff8bb378df6d05a5e1fca4a08900f4a1958f28484604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a250505050565b823373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561119657600080fd5b505afa1580156111aa573d6000803e3d6000fd5b505050506040513d60208110156111c057600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16146111f157600080fd5b6111fa84613b54565b61126c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e66742d6e6f742d6c6f636b656400000000000000000000000000000000000081525060200191505060405180910390fd5b600a6000858152602001908152602001600020548311156112f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f77697468647261772d616d6f756e742d746f6f2d68696768000000000000000081525060200191505060405180910390fd5b611312600a600086815260200190815260200160002054846131e4565b600a600086815260200190815260200160002081905550611335600854846131e4565b600881905550600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83856040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156113ce57600080fd5b505af11580156113e2573d6000803e3d6000fd5b505050506040513d60208110156113f857600080fd5b810190808051906020019092919050505061147b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f63757272656e63792d7472616e736665722d6661696c6564000000000000000081525060200191505060405180910390fd5b837f71ef96c43343734b1d843bb85d52ef329f5e9143e4d35827771e3b0dd90c5f848484604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a250505050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631e0029c8836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561154e57600080fd5b505af1158015611562573d6000803e3d6000fd5b505050506040513d602081101561157857600080fd5b8101908080519060200190929190505050146115fc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f6c6f616e2d6861732d6f75747374616e64696e672d646562740000000000000081525060200191505060405180910390fd5b61160581613b54565b15611678576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e66742d6e6f742d6c6f636b656400000000000000000000000000000000000081525060200191505060405180910390fd5b60008061168483610a87565b915091503373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e856040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561171257600080fd5b505afa158015611726573d6000803e3d6000fd5b505050506040513d602081101561173c57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16148061182557503373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156117d257600080fd5b505afa1580156117e6573d6000803e3d6000fd5b505050506040513d60208110156117fc57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16145b611897576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f6e6f742d6c6f616e2d6f722d6e66742d6f776e6572000000000000000000000081525060200191505060405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630aebeb4e846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561190c57600080fd5b505af1158015611920573d6000803e3d6000fd5b505050506000600b600085815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600b600086815260200190815260200160002060010154604051602001808373ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001925050506040516020818303038152906040528051906020012090506000600c6000838152602001908152602001600020819055506119de84613c63565b837fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf60405160405180910390a250505050565b6000808211611a88576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6469766973696f6e206279207a65726f0000000000000000000000000000000081525060200191505060405180910390fd5b81611ab2611aa2856b033b2e3c9fd0803ce80000006132fd565b60028581611aac57fe5b04613ad1565b81611ab957fe5b04905092915050565b813373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611b4d57600080fd5b505afa158015611b61573d6000803e3d6000fd5b505050506040513d6020811015611b7757600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff1614611ba857600080fd5b611bb183613b54565b611c23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e66742d6e6f742d6c6f636b656400000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611d0757600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166384d2823d846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611cee57600080fd5b505af1158015611d02573d6000803e3d6000fd5b505050505b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663744f4cf6846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611d7c57600080fd5b505af1158015611d90573d6000803e3d6000fd5b50505050611db1600a60008581526020019081526020016000205483613ad1565b600a600085815260200190815260200160002081905550611dd460085483613ad1565b600881905550600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b69ef8a86040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611e4457600080fd5b505af1158015611e58573d6000803e3d6000fd5b50505050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630ecbcdab84846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015611ed957600080fd5b505af1158015611eed573d6000803e3d6000fd5b50505050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663071ffb3c84846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015611f6e57600080fd5b505af1158015611f82573d6000803e3d6000fd5b50505050600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663eaf151326040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611ff057600080fd5b505af1158015612004573d6000803e3d6000fd5b50505050827f044ec4d36b0d76019c4b5aec2a216dbca5ad6c6d671940c8fbbcd23cfe4e804b836040518082815260200191505060405180910390a2505050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600a6020528060005260406000206000915090505481565b803373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561213457600080fd5b505afa158015612148573d6000803e3d6000fd5b505050506040513d602081101561215e57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff161461218f57600080fd5b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631e0029c8846040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561220657600080fd5b505af115801561221a573d6000803e3d6000fd5b505050506040513d602081101561223057600080fd5b8101908080519060200190929190505050146122b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f6c6f616e2d6861732d6f75747374616e64696e672d646562740000000000000081525060200191505060405180910390fd5b600b600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3033600b6000878152602001908152602001600020600101546040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b15801561238f57600080fd5b505af11580156123a3573d6000803e3d6000fd5b50505050817f832a253ad4e9e88f705006a24d9957b8aa1de307a0f9d0a6ad5fd0b0ac81050560405160405180910390a25050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054146124b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e6f742d617574686f72697a656400000000000000000000000000000000000081525060200191505060405180910390fd5b60016000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508073ffffffffffffffffffffffffffffffffffffffff167fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a6060405160405180910390a250565b60006b033b2e3c9fd0803ce800000061255584846132fd565b8161255c57fe5b04905092915050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561261957600080fd5b505afa15801561262d573d6000803e3d6000fd5b505050506040513d602081101561264357600080fd5b8101908080519060200190929190505050905080600854111561267857600161266e600854836131e4565b925092505061268c565b6000612686826008546131e4565b92509250505b9091565b60003373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16636352211e846040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156126fa57600080fd5b505afa15801561270e573d6000803e3d6000fd5b505050506040513d602081101561272457600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16146127be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f6e66742d6e6f742d6f776e65640000000000000000000000000000000000000081525060200191505060405180910390fd5b60008383604051602001808373ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001925050506040516020818303038152906040528051906020012090506000600c60008381526020019081526020016000205414612893576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600a8152602001807f6e66742d696e2d7573650000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166371e928af336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561292057600080fd5b505af1158015612934573d6000803e3d6000fd5b505050506040513d602081101561294a57600080fd5b8101908080519060200190929190505050905080600c60008481526020019081526020016000208190555084600b600083815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555083600b600083815260200190815260200160002060010181905550838573ffffffffffffffffffffffffffffffffffffffff167fc65a3f767206d2fdcede0b094a4840e01c0dd0be1888b5ba800346eaa0123c1660405160405180910390a3809250505092915050565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414612ae8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e6f742d617574686f72697a656400000000000000000000000000000000000081525060200191505060405180910390fd5b7f6c656e6465720000000000000000000000000000000000000000000000000000821415612d4657600073ffffffffffffffffffffffffffffffffffffffff16600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612c3557600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b3600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660006040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b158015612c1c57600080fd5b505af1158015612c30573d6000803e3d6000fd5b505050505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b3827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b158015612ce857600080fd5b505af1158015612cfc573d6000803e3d6000fd5b5050505080600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613054565b7f746f6b656e000000000000000000000000000000000000000000000000000000821415612db45780600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613053565b7f7469746c65000000000000000000000000000000000000000000000000000000821415612e225780600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613052565b7f70696c6500000000000000000000000000000000000000000000000000000000821415612e905780600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613051565b7f6365696c696e6700000000000000000000000000000000000000000000000000821415612efe5780600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613050565b7f7265736572766500000000000000000000000000000000000000000000000000821415612f6c5780600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061304f565b7f6173736573736f72000000000000000000000000000000000000000000000000821415612fda5780600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061304e565b7f73756273637269626572000000000000000000000000000000000000000000008214156130485780600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061304d565b600080fd5b5b5b5b5b5b5b5b817f6b1c5500aa423d5848c47aefec3615dc13387acaa5bcd947bd971e7c53483cef82604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a25050565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541461315a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e6f742d617574686f72697a656400000000000000000000000000000000000081525060200191505060405180910390fd5b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508073ffffffffffffffffffffffffffffffffffffffff167f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b60405160405180910390a250565b6000828284039150811115613261576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f736166652d7375622d6661696c6564000000000000000000000000000000000081525060200191505060405180910390fd5b92915050565b600081838161327257fe5b04905092915050565b60085481565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006020528060005260406000206000915090505481565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600c6020528060005260406000206000915090505481565b60008082148061331a575082828385029250828161331757fe5b04145b61338c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f736166652d6d756c2d6661696c6564000000000000000000000000000000000081525060200191505060405180910390fd5b92915050565b813373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561341d57600080fd5b505afa158015613431573d6000803e3d6000fd5b505050506040513d602081101561344757600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff161461347857600080fd5b61348183613b54565b6134f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e66742d6e6f742d6c6f636b656400000000000000000000000000000000000081525060200191505060405180910390fd5b6000600a6000858152602001908152602001600020541461357c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f77697468647261772d72657175697265642d6265666f72652d7265706179000081525060200191505060405180910390fd5b613587833384613cb4565b827f552544cb36551120f07c66c5cd4b2987725a0c72198587f2ce796099bb66c58c836040518082815260200191505060405180910390a2505050565b803373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561364f57600080fd5b505afa158015613663573d6000803e3d6000fd5b505050506040513d602081101561367957600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16146136aa57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461378e57600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639df17b19836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561377557600080fd5b505af1158015613789573d6000803e3d6000fd5b505050505b600b600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330600b6000878152602001908152602001600020600101546040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b15801561386957600080fd5b505af115801561387d573d6000803e3d6000fd5b50505050817f57424d5909ad92dd80fbaa1967a047a5975a0e9bb94726d561734e667cdf422760405160405180910390a25050565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414613966576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e6f742d617574686f72697a656400000000000000000000000000000000000081525060200191505060405180910390fd5b600b600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3083600b6000878152602001908152602001600020600101546040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b158015613a4157600080fd5b505af1158015613a55573d6000803e3d6000fd5b50505050817f35538759d80c1fd7bb450a0d05601db5a99fa8b5d073a07c847a9fd61029b10782604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a25050565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000828284019150811015613b4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f736166652d6164642d6661696c6564000000000000000000000000000000000081525060200191505060405180910390fd5b92915050565b60003073ffffffffffffffffffffffffffffffffffffffff16600b600084815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e600b6000868152602001908152602001600020600101546040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015613c0a57600080fd5b505afa158015613c1e573d6000803e3d6000fd5b505050506040513d6020811015613c3457600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16149050919050565b6000600a60008381526020019081526020016000205490506000811115613cb0576000600a600084815260200190815260200160002081905550613ca9600854826131e4565b6008819055505b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663744f4cf6846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613d2957600080fd5b505af1158015613d3d573d6000803e3d6000fd5b505050506000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631e0029c8856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015613db857600080fd5b505af1158015613dcc573d6000803e3d6000fd5b505050506040513d6020811015613de257600080fd5b8101908080519060200190929190505050905080821115613e01578091505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd8430856040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b158015613eb257600080fd5b505af1158015613ec6573d6000803e3d6000fd5b505050506040513d6020811015613edc57600080fd5b8101908080519060200190929190505050613f5f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f63757272656e63792d7472616e736665722d6661696c6564000000000000000081525060200191505060405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d8aed14585846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015613fdc57600080fd5b505af1158015613ff0573d6000803e3d6000fd5b50505050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632047a26785846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b15801561407157600080fd5b505af1158015614085573d6000803e3d6000fd5b50505050600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b69ef8a86040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156140f357600080fd5b505af1158015614107573d6000803e3d6000fd5b50505050600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663eaf151326040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561417557600080fd5b505af1158015614189573d6000803e3d6000fd5b505050505050505056fea2646970667358221220d876a0e1106c45505e0a3bb4489836a0d1b285b62e57a3d17ed69dfceeceacc864736f6c634300070600330000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000004ac844d4b76a1e17a1ea0ced8582eaa49253e8070000000000000000000000009e39e0130558cd9a01c1e3c7b2c3803bacb59616000000000000000000000000468eb2408c6f24662a291892550952eb0d70b707
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101fb5760003560e01c8063867904b41161011a578063cd3293de116100ad578063dd4670641161007c578063dd46706414610947578063ddd5e1b214610975578063e5a6b10f146109c3578063e6cb9013146109f7578063f7f0b4d614610a43576101fb565b8063cd3293de1461084d578063ce50dc7b14610881578063d05c78da146108c3578063d8aed1451461090f576101fb565b8063b5931f7c116100e9578063b5931f7c14610757578063b69ef8a8146107a3578063bcead63e146107c1578063bf353dbb146107f5576101fb565b8063867904b4146106175780639adc339d146106795780639c52a7f1146106c7578063a293d1e81461070b576101fb565b806320e036301161019257806365fae35e1161016157806365fae35e1461052c5780636745702214610570578063753ed1bd146105bc578063843f7b89146105f0576101fb565b806320e03630146104545780634903b0d1146104885780636198e339146104ca57806362f6b10f146104f8576101fb565b80630aebeb4e116101ce5780630aebeb4e1461036e5780630e2286d31461039c5780630ecbcdab146103e85780631821d69614610420576101fb565b8063044215c614610200578063056e00b31461025f57806308e45dc1146102be5780630ad58d2f14610316575b600080fd5b61022c6004803603602081101561021657600080fd5b8101908080359060200190929190505050610a87565b604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b61028b6004803603602081101561027557600080fd5b8101908080359060200190929190505050610ae1565b604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b610314600480360360608110156102d457600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b25565b005b61036c6004803603606081101561032c57600080fd5b810190808035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061110b565b005b61039a6004803603602081101561038457600080fd5b81019080803590602001909291905050506114d7565b005b6103d2600480360360408110156103b257600080fd5b810190808035906020019092919080359060200190929190505050611a11565b6040518082815260200191505060405180910390f35b61041e600480360360408110156103fe57600080fd5b810190808035906020019092919080359060200190929190505050611ac2565b005b610428612045565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61045c61206b565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6104b46004803603602081101561049e57600080fd5b8101908080359060200190929190505050612091565b6040518082815260200191505060405180910390f35b6104f6600480360360208110156104e057600080fd5b81019080803590602001909291905050506120a9565b005b6105006123d8565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61056e6004803603602081101561054257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506123fe565b005b6105a66004803603604081101561058657600080fd5b81019080803590602001909291908035906020019092919050505061253c565b6040518082815260200191505060405180910390f35b6105c4612565565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105f861258b565b6040518083151581526020018281526020019250505060405180910390f35b6106636004803603604081101561062d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050612690565b6040518082815260200191505060405180910390f35b6106c56004803603604081101561068f57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612a34565b005b610709600480360360208110156106dd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506130a6565b005b6107416004803603604081101561072157600080fd5b8101908080359060200190929190803590602001909291905050506131e4565b6040518082815260200191505060405180910390f35b61078d6004803603604081101561076d57600080fd5b810190808035906020019092919080359060200190929190505050613267565b6040518082815260200191505060405180910390f35b6107ab61327b565b6040518082815260200191505060405180910390f35b6107c9613281565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6108376004803603602081101561080b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506132a7565b6040518082815260200191505060405180910390f35b6108556132bf565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6108ad6004803603602081101561089757600080fd5b81019080803590602001909291905050506132e5565b6040518082815260200191505060405180910390f35b6108f9600480360360408110156108d957600080fd5b8101908080359060200190929190803590602001909291905050506132fd565b6040518082815260200191505060405180910390f35b6109456004803603604081101561092557600080fd5b810190808035906020019092919080359060200190929190505050613392565b005b6109736004803603602081101561095d57600080fd5b81019080803590602001909291905050506135c4565b005b6109c16004803603604081101561098b57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506138b2565b005b6109cb613aab565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610a2d60048036036040811015610a0d57600080fd5b810190808035906020019092919080359060200190929190505050613ad1565b6040518082815260200191505060405180910390f35b610a6f60048036036020811015610a5957600080fd5b8101908080359060200190929190505050613b54565b60405180821515815260200191505060405180910390f35b600080600b600084815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600b60008581526020019081526020016000206001015491509150915091565b600b6020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010154905082565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414610bd9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e6f742d617574686f72697a656400000000000000000000000000000000000081525060200191505060405180910390fd5b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663744f4cf6846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610c4e57600080fd5b505af1158015610c62573d6000803e3d6000fd5b505050506000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631e0029c8856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015610cdd57600080fd5b505af1158015610cf1573d6000803e3d6000fd5b505050506040513d6020811015610d0757600080fd5b81019080805190602001909291905050509050600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd8430856040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b158015610dcb57600080fd5b505af1158015610ddf573d6000803e3d6000fd5b505050506040513d6020811015610df557600080fd5b8101908080519060200190929190505050610e78576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f63757272656e63792d7472616e736665722d6661696c6564000000000000000081525060200191505060405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d8aed14585836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015610ef557600080fd5b505af1158015610f09573d6000803e3d6000fd5b50505050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632047a26785836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015610f8a57600080fd5b505af1158015610f9e573d6000803e3d6000fd5b50505050610fab84613c63565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b69ef8a86040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561101557600080fd5b505af1158015611029573d6000803e3d6000fd5b50505050600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663eaf151326040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561109757600080fd5b505af11580156110ab573d6000803e3d6000fd5b50505050837fc59615076045a3968279704d2a2ff8bb378df6d05a5e1fca4a08900f4a1958f28484604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a250505050565b823373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561119657600080fd5b505afa1580156111aa573d6000803e3d6000fd5b505050506040513d60208110156111c057600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16146111f157600080fd5b6111fa84613b54565b61126c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e66742d6e6f742d6c6f636b656400000000000000000000000000000000000081525060200191505060405180910390fd5b600a6000858152602001908152602001600020548311156112f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f77697468647261772d616d6f756e742d746f6f2d68696768000000000000000081525060200191505060405180910390fd5b611312600a600086815260200190815260200160002054846131e4565b600a600086815260200190815260200160002081905550611335600854846131e4565b600881905550600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83856040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156113ce57600080fd5b505af11580156113e2573d6000803e3d6000fd5b505050506040513d60208110156113f857600080fd5b810190808051906020019092919050505061147b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f63757272656e63792d7472616e736665722d6661696c6564000000000000000081525060200191505060405180910390fd5b837f71ef96c43343734b1d843bb85d52ef329f5e9143e4d35827771e3b0dd90c5f848484604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a250505050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631e0029c8836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561154e57600080fd5b505af1158015611562573d6000803e3d6000fd5b505050506040513d602081101561157857600080fd5b8101908080519060200190929190505050146115fc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f6c6f616e2d6861732d6f75747374616e64696e672d646562740000000000000081525060200191505060405180910390fd5b61160581613b54565b15611678576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e66742d6e6f742d6c6f636b656400000000000000000000000000000000000081525060200191505060405180910390fd5b60008061168483610a87565b915091503373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e856040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561171257600080fd5b505afa158015611726573d6000803e3d6000fd5b505050506040513d602081101561173c57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16148061182557503373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156117d257600080fd5b505afa1580156117e6573d6000803e3d6000fd5b505050506040513d60208110156117fc57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16145b611897576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f6e6f742d6c6f616e2d6f722d6e66742d6f776e6572000000000000000000000081525060200191505060405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630aebeb4e846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561190c57600080fd5b505af1158015611920573d6000803e3d6000fd5b505050506000600b600085815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600b600086815260200190815260200160002060010154604051602001808373ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001925050506040516020818303038152906040528051906020012090506000600c6000838152602001908152602001600020819055506119de84613c63565b837fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf60405160405180910390a250505050565b6000808211611a88576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6469766973696f6e206279207a65726f0000000000000000000000000000000081525060200191505060405180910390fd5b81611ab2611aa2856b033b2e3c9fd0803ce80000006132fd565b60028581611aac57fe5b04613ad1565b81611ab957fe5b04905092915050565b813373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611b4d57600080fd5b505afa158015611b61573d6000803e3d6000fd5b505050506040513d6020811015611b7757600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff1614611ba857600080fd5b611bb183613b54565b611c23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e66742d6e6f742d6c6f636b656400000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611d0757600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166384d2823d846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611cee57600080fd5b505af1158015611d02573d6000803e3d6000fd5b505050505b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663744f4cf6846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611d7c57600080fd5b505af1158015611d90573d6000803e3d6000fd5b50505050611db1600a60008581526020019081526020016000205483613ad1565b600a600085815260200190815260200160002081905550611dd460085483613ad1565b600881905550600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b69ef8a86040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611e4457600080fd5b505af1158015611e58573d6000803e3d6000fd5b50505050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630ecbcdab84846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015611ed957600080fd5b505af1158015611eed573d6000803e3d6000fd5b50505050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663071ffb3c84846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015611f6e57600080fd5b505af1158015611f82573d6000803e3d6000fd5b50505050600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663eaf151326040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611ff057600080fd5b505af1158015612004573d6000803e3d6000fd5b50505050827f044ec4d36b0d76019c4b5aec2a216dbca5ad6c6d671940c8fbbcd23cfe4e804b836040518082815260200191505060405180910390a2505050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600a6020528060005260406000206000915090505481565b803373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561213457600080fd5b505afa158015612148573d6000803e3d6000fd5b505050506040513d602081101561215e57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff161461218f57600080fd5b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631e0029c8846040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561220657600080fd5b505af115801561221a573d6000803e3d6000fd5b505050506040513d602081101561223057600080fd5b8101908080519060200190929190505050146122b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f6c6f616e2d6861732d6f75747374616e64696e672d646562740000000000000081525060200191505060405180910390fd5b600b600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3033600b6000878152602001908152602001600020600101546040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b15801561238f57600080fd5b505af11580156123a3573d6000803e3d6000fd5b50505050817f832a253ad4e9e88f705006a24d9957b8aa1de307a0f9d0a6ad5fd0b0ac81050560405160405180910390a25050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054146124b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e6f742d617574686f72697a656400000000000000000000000000000000000081525060200191505060405180910390fd5b60016000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508073ffffffffffffffffffffffffffffffffffffffff167fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a6060405160405180910390a250565b60006b033b2e3c9fd0803ce800000061255584846132fd565b8161255c57fe5b04905092915050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561261957600080fd5b505afa15801561262d573d6000803e3d6000fd5b505050506040513d602081101561264357600080fd5b8101908080519060200190929190505050905080600854111561267857600161266e600854836131e4565b925092505061268c565b6000612686826008546131e4565b92509250505b9091565b60003373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16636352211e846040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156126fa57600080fd5b505afa15801561270e573d6000803e3d6000fd5b505050506040513d602081101561272457600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16146127be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f6e66742d6e6f742d6f776e65640000000000000000000000000000000000000081525060200191505060405180910390fd5b60008383604051602001808373ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001925050506040516020818303038152906040528051906020012090506000600c60008381526020019081526020016000205414612893576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600a8152602001807f6e66742d696e2d7573650000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166371e928af336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561292057600080fd5b505af1158015612934573d6000803e3d6000fd5b505050506040513d602081101561294a57600080fd5b8101908080519060200190929190505050905080600c60008481526020019081526020016000208190555084600b600083815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555083600b600083815260200190815260200160002060010181905550838573ffffffffffffffffffffffffffffffffffffffff167fc65a3f767206d2fdcede0b094a4840e01c0dd0be1888b5ba800346eaa0123c1660405160405180910390a3809250505092915050565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414612ae8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e6f742d617574686f72697a656400000000000000000000000000000000000081525060200191505060405180910390fd5b7f6c656e6465720000000000000000000000000000000000000000000000000000821415612d4657600073ffffffffffffffffffffffffffffffffffffffff16600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612c3557600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b3600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660006040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b158015612c1c57600080fd5b505af1158015612c30573d6000803e3d6000fd5b505050505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b3827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b158015612ce857600080fd5b505af1158015612cfc573d6000803e3d6000fd5b5050505080600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613054565b7f746f6b656e000000000000000000000000000000000000000000000000000000821415612db45780600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613053565b7f7469746c65000000000000000000000000000000000000000000000000000000821415612e225780600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613052565b7f70696c6500000000000000000000000000000000000000000000000000000000821415612e905780600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613051565b7f6365696c696e6700000000000000000000000000000000000000000000000000821415612efe5780600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613050565b7f7265736572766500000000000000000000000000000000000000000000000000821415612f6c5780600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061304f565b7f6173736573736f72000000000000000000000000000000000000000000000000821415612fda5780600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061304e565b7f73756273637269626572000000000000000000000000000000000000000000008214156130485780600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061304d565b600080fd5b5b5b5b5b5b5b5b817f6b1c5500aa423d5848c47aefec3615dc13387acaa5bcd947bd971e7c53483cef82604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a25050565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541461315a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e6f742d617574686f72697a656400000000000000000000000000000000000081525060200191505060405180910390fd5b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508073ffffffffffffffffffffffffffffffffffffffff167f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b60405160405180910390a250565b6000828284039150811115613261576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f736166652d7375622d6661696c6564000000000000000000000000000000000081525060200191505060405180910390fd5b92915050565b600081838161327257fe5b04905092915050565b60085481565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006020528060005260406000206000915090505481565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600c6020528060005260406000206000915090505481565b60008082148061331a575082828385029250828161331757fe5b04145b61338c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f736166652d6d756c2d6661696c6564000000000000000000000000000000000081525060200191505060405180910390fd5b92915050565b813373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561341d57600080fd5b505afa158015613431573d6000803e3d6000fd5b505050506040513d602081101561344757600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff161461347857600080fd5b61348183613b54565b6134f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e66742d6e6f742d6c6f636b656400000000000000000000000000000000000081525060200191505060405180910390fd5b6000600a6000858152602001908152602001600020541461357c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f77697468647261772d72657175697265642d6265666f72652d7265706179000081525060200191505060405180910390fd5b613587833384613cb4565b827f552544cb36551120f07c66c5cd4b2987725a0c72198587f2ce796099bb66c58c836040518082815260200191505060405180910390a2505050565b803373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561364f57600080fd5b505afa158015613663573d6000803e3d6000fd5b505050506040513d602081101561367957600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16146136aa57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461378e57600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639df17b19836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561377557600080fd5b505af1158015613789573d6000803e3d6000fd5b505050505b600b600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330600b6000878152602001908152602001600020600101546040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b15801561386957600080fd5b505af115801561387d573d6000803e3d6000fd5b50505050817f57424d5909ad92dd80fbaa1967a047a5975a0e9bb94726d561734e667cdf422760405160405180910390a25050565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414613966576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f6e6f742d617574686f72697a656400000000000000000000000000000000000081525060200191505060405180910390fd5b600b600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3083600b6000878152602001908152602001600020600101546040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b158015613a4157600080fd5b505af1158015613a55573d6000803e3d6000fd5b50505050817f35538759d80c1fd7bb450a0d05601db5a99fa8b5d073a07c847a9fd61029b10782604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a25050565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000828284019150811015613b4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f736166652d6164642d6661696c6564000000000000000000000000000000000081525060200191505060405180910390fd5b92915050565b60003073ffffffffffffffffffffffffffffffffffffffff16600b600084815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e600b6000868152602001908152602001600020600101546040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015613c0a57600080fd5b505afa158015613c1e573d6000803e3d6000fd5b505050506040513d6020811015613c3457600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16149050919050565b6000600a60008381526020019081526020016000205490506000811115613cb0576000600a600084815260200190815260200160002081905550613ca9600854826131e4565b6008819055505b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663744f4cf6846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613d2957600080fd5b505af1158015613d3d573d6000803e3d6000fd5b505050506000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631e0029c8856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015613db857600080fd5b505af1158015613dcc573d6000803e3d6000fd5b505050506040513d6020811015613de257600080fd5b8101908080519060200190929190505050905080821115613e01578091505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd8430856040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b158015613eb257600080fd5b505af1158015613ec6573d6000803e3d6000fd5b505050506040513d6020811015613edc57600080fd5b8101908080519060200190929190505050613f5f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f63757272656e63792d7472616e736665722d6661696c6564000000000000000081525060200191505060405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d8aed14585846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015613fdc57600080fd5b505af1158015613ff0573d6000803e3d6000fd5b50505050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632047a26785846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b15801561407157600080fd5b505af1158015614085573d6000803e3d6000fd5b50505050600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b69ef8a86040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156140f357600080fd5b505af1158015614107573d6000803e3d6000fd5b50505050600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663eaf151326040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561417557600080fd5b505af1158015614189573d6000803e3d6000fd5b505050505050505056fea2646970667358221220d876a0e1106c45505e0a3bb4489836a0d1b285b62e57a3d17ed69dfceeceacc864736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000004ac844d4b76a1e17a1ea0ced8582eaa49253e8070000000000000000000000009e39e0130558cd9a01c1e3c7b2c3803bacb59616000000000000000000000000468eb2408c6f24662a291892550952eb0d70b707
-----Decoded View---------------
Arg [0] : currency_ (address): 0x6B175474E89094C44Da98b954EedeAC495271d0F
Arg [1] : title_ (address): 0x4AC844d4B76A1E17a1EA0CED8582eAa49253e807
Arg [2] : pile_ (address): 0x9E39e0130558cd9A01C1e3c7b2c3803baCb59616
Arg [3] : ceiling_ (address): 0x468eb2408c6F24662a291892550952eb0d70b707
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Arg [1] : 0000000000000000000000004ac844d4b76a1e17a1ea0ced8582eaa49253e807
Arg [2] : 0000000000000000000000009e39e0130558cd9a01c1e3c7b2c3803bacb59616
Arg [3] : 000000000000000000000000468eb2408c6f24662a291892550952eb0d70b707
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.