Source Code
Latest 25 from a total of 308 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Create Post | 119735616 | 640 days ago | IN | 0 ETH | 0.0000190867 | ||||
| Create Post | 119665843 | 642 days ago | IN | 0 ETH | 0.000002601574 | ||||
| Create Post | 119628899 | 642 days ago | IN | 0 ETH | 0.000002176427 | ||||
| Create Post | 119487018 | 646 days ago | IN | 0 ETH | 0.000020256134 | ||||
| Create Post | 119486664 | 646 days ago | IN | 0 ETH | 0.000019972386 | ||||
| Create Post | 119479769 | 646 days ago | IN | 0 ETH | 0.000020158466 | ||||
| Create Post | 119451444 | 646 days ago | IN | 0 ETH | 0.000019128224 | ||||
| Create Post | 119451276 | 647 days ago | IN | 0 ETH | 0.000019755171 | ||||
| Create Post | 119436602 | 647 days ago | IN | 0 ETH | 0.000019135238 | ||||
| Create Post | 119402659 | 648 days ago | IN | 0 ETH | 0.00002057853 | ||||
| Create Post | 119394424 | 648 days ago | IN | 0 ETH | 0.000018862991 | ||||
| Create Post | 119364494 | 649 days ago | IN | 0 ETH | 0.000018750858 | ||||
| Create Post | 119361205 | 649 days ago | IN | 0 ETH | 0.000020026927 | ||||
| Create Post | 119360172 | 649 days ago | IN | 0 ETH | 0.000020144571 | ||||
| Create Post | 119360025 | 649 days ago | IN | 0 ETH | 0.00002054147 | ||||
| Create Post | 119359834 | 649 days ago | IN | 0 ETH | 0.000020128546 | ||||
| Create Post | 119356591 | 649 days ago | IN | 0 ETH | 0.000020103302 | ||||
| Create Post | 119356374 | 649 days ago | IN | 0 ETH | 0.000019912204 | ||||
| Create Post | 119356160 | 649 days ago | IN | 0 ETH | 0.000020347715 | ||||
| Create Post | 119356079 | 649 days ago | IN | 0 ETH | 0.000020211917 | ||||
| Create Post | 119348249 | 649 days ago | IN | 0 ETH | 0.000020227117 | ||||
| Create Post | 119336407 | 649 days ago | IN | 0 ETH | 0.000018880558 | ||||
| Create Post | 119336129 | 649 days ago | IN | 0 ETH | 0.000020092006 | ||||
| Create Post | 119336025 | 649 days ago | IN | 0 ETH | 0.000020238007 | ||||
| Create Post | 119335946 | 649 days ago | IN | 0 ETH | 0.000019784874 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
LSP8PinSave
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
No with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
import "@lukso/lsp-smart-contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol";
pragma solidity 0.8.20;
contract LSP8PinSave is LSP8IdentifiableDigitalAsset {
bool internal locked;
address public feeSetter;
uint public mintingFee;
modifier noReentrant() {
require(!locked, "No re-entrancy");
locked = true;
_;
locked = false;
}
struct Post {
string cid;
address author;
uint256 id;
bytes32 tokenId;
}
Post latestPost;
uint256 private postsCounter;
mapping(uint256 => Post) public postByTokenId;
constructor(
string memory name_,
string memory symbol_,
address newOwner_
) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_) {
feeSetter = newOwner_;
}
function setFeeSetter(address _feeSetter) external {
require(msg.sender == feeSetter, 'FORBIDDEN');
feeSetter = _feeSetter;
}
function changeFee(uint newFee) external {
require(msg.sender == feeSetter, 'FORBIDDEN');
mintingFee = newFee;
}
function getContractBalance() public view returns (uint) {
return address(this).balance;
}
function withdrawFees() external {
require(msg.sender == feeSetter, "Only admin can withdraw fees");
uint amount = address(this).balance;
(bool success, ) = payable(feeSetter).call{value: amount}("");
require(success, "Failed to send fees");
}
function createPost(address receiver, string memory _cid, bytes32 tokenId) payable public noReentrant {
require(msg.value >= mintingFee, "Insufficient fee");
latestPost.cid = _cid;
latestPost.author = msg.sender;
latestPost.id = ++postsCounter;
latestPost.tokenId = tokenId;
postByTokenId[postsCounter] = latestPost;
_mint(receiver, tokenId , true, "");
}
function createBatchPosts(
address to,
string[] memory _cid,
bytes32[] memory tokenId
) public {
uint len = tokenId.length;
for (uint256 i; i != len;) {
createPost(to, _cid[i], tokenId[i]);
unchecked{++i;}
}
}
function getPostOwner(uint id) external view returns(address){
return tokenOwnerOf(postByTokenId[id].tokenId);
}
function getPostCid(uint id) external view returns(string memory){
return postByTokenId[id].cid;
}
function getPostAuthor(uint id) public view returns(address){
return postByTokenId[id].author;
}
receive() external payable {
// Code to handle receiving Ether
}
}// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; // ERC165 INTERFACE IDs bytes4 constant _INTERFACEID_ERC725X = 0x7545acac; bytes4 constant _INTERFACEID_ERC725Y = 0x629aa694; // ERC725X OPERATION TYPES uint256 constant OPERATION_0_CALL = 0; uint256 constant OPERATION_1_CREATE = 1; uint256 constant OPERATION_2_CREATE2 = 2; uint256 constant OPERATION_3_STATICCALL = 3; uint256 constant OPERATION_4_DELEGATECALL = 4;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title OwnableUnset
* @dev modified version of OpenZeppelin implementation, where:
* - _setOwner(address) function is internal, so this function can be used in constructor
* of contracts implementation (instead of using transferOwnership(address)
* - the contract does not inherit from Context contract
*/
abstract contract OwnableUnset {
address private _owner;
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(
newOwner != address(0),
"Ownable: new owner is the zero address"
);
_setOwner(newOwner);
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == msg.sender, "Ownable: caller is not the owner");
}
/**
* @dev Changes the owner if `newOwner` and oldOwner are different
* This pattern is useful in inheritance.
*/
function _setOwner(address newOwner) internal virtual {
if (newOwner != owner()) {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
// modules
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {OwnableUnset} from "./custom/OwnableUnset.sol";
import {ERC725YCore} from "./ERC725YCore.sol";
/**
* @title Deployable implementation with `constructor` of ERC725Y, a generic data key/value store.
* @author Fabian Vogelsteller <[email protected]>
* @dev ERC725Y provides the ability to set arbitrary data key/value pairs that can be changed over time.
* It is intended to standardise certain data key/value pairs to allow automated read and writes from/to the contract storage.
*/
contract ERC725Y is ERC725YCore {
/**
* @notice Deploying an ERC725Y smart contract and setting address `initialOwner` as the contract owner.
* @dev Deploy a new ERC725Y contract with the provided `initialOwner` as the contract {owner}.
* @param initialOwner the owner of the contract.
*
* @custom:requirements
* - `initialOwner` CANNOT be the zero address.
*/
constructor(address initialOwner) payable {
require(
initialOwner != address(0),
"Ownable: new owner is the zero address"
);
OwnableUnset._setOwner(initialOwner);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
// interfaces
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IERC725Y} from "./interfaces/IERC725Y.sol";
// modules
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {OwnableUnset} from "./custom/OwnableUnset.sol";
// constants
import {_INTERFACEID_ERC725Y} from "./constants.sol";
import "./errors.sol";
/**
* @title Core implementation of ERC725Y sub-standard, a general data key/value store.
* @author Fabian Vogelsteller <[email protected]>
* @dev ERC725Y provides the ability to set arbitrary data key/value pairs that can be changed over time.
* It is intended to standardise certain data key/value pairs to allow automated read and writes from/to the contract storage.
*/
abstract contract ERC725YCore is OwnableUnset, ERC165, IERC725Y {
/**
* @dev Map `bytes32` data keys to their `bytes` data values.
*/
mapping(bytes32 => bytes) internal _store;
/**
* @inheritdoc IERC725Y
*/
function getData(
bytes32 dataKey
) public view virtual override returns (bytes memory dataValue) {
dataValue = _getData(dataKey);
}
/**
* @inheritdoc IERC725Y
*/
function getDataBatch(
bytes32[] memory dataKeys
) public view virtual override returns (bytes[] memory dataValues) {
dataValues = new bytes[](dataKeys.length);
for (uint256 i = 0; i < dataKeys.length; ) {
dataValues[i] = _getData(dataKeys[i]);
// Increment the iterator in unchecked block to save gas
unchecked {
++i;
}
}
return dataValues;
}
/**
* @inheritdoc IERC725Y
* @custom:requirements
* - SHOULD only be callable by the {owner}.
*
* @custom:warning
* **Note for developers:** despite the fact that this function is set as `payable`, if the function is not intended to receive value
* (= native tokens), **an additional check should be implemented to ensure that `msg.value` sent was equal to 0**.
*
* @custom:events {DataChanged} event.
*/
function setData(
bytes32 dataKey,
bytes memory dataValue
) public payable virtual override onlyOwner {
if (msg.value != 0) revert ERC725Y_MsgValueDisallowed();
_setData(dataKey, dataValue);
}
/**
* @inheritdoc IERC725Y
* @custom:requirements
* - SHOULD only be callable by the {owner} of the contract.
*
* @custom:warning
* **Note for developers:** despite the fact that this function is set as `payable`, if the function is not intended to receive value
* (= native tokens), **an additional check should be implemented to ensure that `msg.value` sent was equal to 0**.
*
* @custom:events {DataChanged} event **for each data key/value pair set**.
*/
function setDataBatch(
bytes32[] memory dataKeys,
bytes[] memory dataValues
) public payable virtual override onlyOwner {
/// @dev do not allow to send value by default when setting data in ERC725Y
if (msg.value != 0) revert ERC725Y_MsgValueDisallowed();
if (dataKeys.length != dataValues.length) {
revert ERC725Y_DataKeysValuesLengthMismatch();
}
if (dataKeys.length == 0) {
revert ERC725Y_DataKeysValuesEmptyArray();
}
for (uint256 i = 0; i < dataKeys.length; ) {
_setData(dataKeys[i], dataValues[i]);
// Increment the iterator in unchecked block to save gas
unchecked {
++i;
}
}
}
/**
* @dev Read the value stored under a specific `dataKey` inside the underlying ERC725Y storage,
* represented as a mapping of `bytes32` data keys mapped to their `bytes` data values.
*
* ```solidity
* mapping(bytes32 => bytes) _store
* ```
*
* @param dataKey A bytes32 data key to read the associated `bytes` value from the store.
* @return dataValue The `bytes` value associated with the given `dataKey` in the ERC725Y storage.
*/
function _getData(
bytes32 dataKey
) internal view virtual returns (bytes memory dataValue) {
return _store[dataKey];
}
/**
* @dev Write a `dataValue` to the underlying ERC725Y storage, represented as a mapping of
* `bytes32` data keys mapped to their `bytes` data values.
*
* ```solidity
* mapping(bytes32 => bytes) _store
* ```
*
* @param dataKey A bytes32 data key to write the associated `bytes` value to the store.
* @param dataValue The `bytes` value to associate with the given `dataKey` in the ERC725Y storage.
*
* @custom:events {DataChanged} event emitted after a successful `setData` call.
*/
function _setData(
bytes32 dataKey,
bytes memory dataValue
) internal virtual {
_store[dataKey] = dataValue;
emit DataChanged(dataKey, dataValue);
}
/**
* @inheritdoc ERC165
*/
function supportsInterface(
bytes4 interfaceId
) public view virtual override(IERC165, ERC165) returns (bool) {
return
interfaceId == _INTERFACEID_ERC725Y ||
super.supportsInterface(interfaceId);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/**
* @dev Reverts when trying to send more native tokens `value` than available in current `balance`.
* @param balance The balance of native tokens of the ERC725X smart contract.
* @param value The amount of native tokens sent via `ERC725X.execute(...)`/`ERC725X.executeBatch(...)` that is greater than the contract's `balance`.
*/
error ERC725X_InsufficientBalance(uint256 balance, uint256 value);
/**
* @dev Reverts when the `operationTypeProvided` is none of the default operation types available.
* (CALL = 0; CREATE = 1; CREATE2 = 2; STATICCALL = 3; DELEGATECALL = 4)
* @param operationTypeProvided The unrecognised operation type number provided to `ERC725X.execute(...)`/`ERC725X.executeBatch(...)`.
*/
error ERC725X_UnknownOperationType(uint256 operationTypeProvided);
/**
* @dev Reverts when trying to send native tokens (`value` / `values[]` parameter of {execute} or {executeBatch} functions) while making a `staticcall` (`operationType == 3`).
* Sending native tokens via `staticcall` is not allowed because it is a state changing operation.
*/
error ERC725X_MsgValueDisallowedInStaticCall();
/**
* @dev Reverts when trying to send native tokens (`value` / `values[]` parameter of {execute} or {executeBatch} functions) while making a `delegatecall` (`operationType == 4`).
* Sending native tokens via `staticcall` is not allowed because `msg.value` is persisting.
*/
error ERC725X_MsgValueDisallowedInDelegateCall();
/**
* @dev Reverts when passing a `to` address that is not `address(0)` (= address zero) while deploying a contract via {execute} or {executeBatch} functions.
* This error can occur using either operation type 1 (`CREATE`) or 2 (`CREATE2`).
*/
error ERC725X_CreateOperationsRequireEmptyRecipientAddress();
/**
* @dev Reverts when contract deployment failed via {execute} or {executeBatch} functions,
* This error can occur using either operation type 1 (`CREATE`) or 2 (`CREATE2`).
*/
error ERC725X_ContractDeploymentFailed();
/**
* @dev Reverts when no contract bytecode was provided as parameter when trying to deploy a contract via {execute} or {executeBatch}.
* This error can occur using either operation type 1 (`CREATE`) or 2 (`CREATE2`).
*/
error ERC725X_NoContractBytecodeProvided();
/**
* @dev Reverts when there is not the same number of elements in the `operationTypes`, `targets` addresses, `values`, and `datas`
* array parameters provided when calling the {executeBatch} function.
*/
error ERC725X_ExecuteParametersLengthMismatch();
/**
* @dev Reverts when one of the array parameter provided to the {executeBatch} function is an empty array.
*/
error ERC725X_ExecuteParametersEmptyArray();
/**
* @dev Reverts when there is not the same number of elements in the `datakeys` and `dataValues`
* array parameters provided when calling the {setDataBatch} function.
*/
error ERC725Y_DataKeysValuesLengthMismatch();
/**
* @dev Reverts when one of the array parameter provided to {setDataBatch} function is an empty array.
*/
error ERC725Y_DataKeysValuesEmptyArray();
/**
* @dev Reverts when sending value to the {setData} or {setDataBatch} function.
*/
error ERC725Y_MsgValueDisallowed();// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
// interfaces
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @title The interface for ERC725Y sub-standard, a generic data key/value store.
* @dev ERC725Y provides the ability to set arbitrary data key/value pairs that can be changed over time.
* It is intended to standardise certain data key/value pairs to allow automated read and writes from/to the contract storage.
*/
interface IERC725Y is IERC165 {
/**
* @notice The following data key/value pair has been changed in the ERC725Y storage: Data key: `dataKey`, data value: `dataValue`.
* @dev Emitted when data at a specific `dataKey` was changed to a new value `dataValue`.
* @param dataKey The data key for which a bytes value is set.
* @param dataValue The value to set for the given data key.
*/
event DataChanged(bytes32 indexed dataKey, bytes dataValue);
/**
* @notice Reading the ERC725Y storage for data key `dataKey` returned the following value: `dataValue`.
* @dev Get in the ERC725Y storage the bytes data stored at a specific data key `dataKey`.
* @param dataKey The data key for which to retrieve the value.
* @return dataValue The bytes value stored under the specified data key.
*/
function getData(
bytes32 dataKey
) external view returns (bytes memory dataValue);
/**
* @notice Reading the ERC725Y storage for data keys `dataKeys` returned the following values: `dataValues`.
* @dev Get in the ERC725Y storage the bytes data stored at multiple data keys `dataKeys`.
* @param dataKeys The array of keys which values to retrieve
* @return dataValues The array of data stored at multiple keys
*/
function getDataBatch(
bytes32[] memory dataKeys
) external view returns (bytes[] memory dataValues);
/**
* @notice Setting the following data key value pair in the ERC725Y storage. Data key: `dataKey`, data value: `dataValue`.
*
* @dev Sets a single bytes value `dataValue` in the ERC725Y storage for a specific data key `dataKey`.
* The function is marked as payable to enable flexibility on child contracts. For instance to implement
* a fee mechanism for setting specific data.
*
* @param dataKey The data key for which to set a new value.
* @param dataValue The new bytes value to set.
*/
function setData(bytes32 dataKey, bytes memory dataValue) external payable;
/**
* @notice Setting the following data key value pairs in the ERC725Y storage. Data keys: `dataKeys`, data values: `dataValues`.
*
* @dev Batch data setting function that behaves the same as {setData} but allowing to set multiple data key/value pairs in the ERC725Y storage in the same transaction.
*
* @param dataKeys An array of data keys to set bytes values for.
* @param dataValues An array of bytes values to set for each `dataKeys`.
*/
function setDataBatch(
bytes32[] memory dataKeys,
bytes[] memory dataValues
) external payable;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.4;
// --- ERC165 interface ids
// bytes4(keccack256("LSP17Extendable"))
bytes4 constant _INTERFACEID_LSP17_EXTENDABLE = 0xa918fa6b;
// bytes4(keccack256("LSP17Extension"))
bytes4 constant _INTERFACEID_LSP17_EXTENSION = 0xcee78b40;
// --- ERC725Y Data Keys
// Extension Handler Prefix
// bytes10(keccak256('LSP17Extension'))
bytes10 constant _LSP17_EXTENSION_PREFIX = 0xcee78b4094da86011096;// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /** * @dev reverts when there is no extension for the function selector being called with */ error NoExtensionFoundForFunctionSelector(bytes4 functionSelector); /** * @dev reverts when the contract is called with a function selector not valid (less than 4 bytes of data) */ error InvalidFunctionSelector(bytes data); /** * @dev reverts when the bytes retrieved from the LSP17 data key is not a valid address (not 20 bytes) */ error InvalidExtensionAddress(bytes storedData);
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.4;
// modules
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {
ERC165Checker
} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
// constants
import {_INTERFACEID_LSP17_EXTENDABLE} from "./LSP17Constants.sol";
// errors
import "./LSP17Errors.sol";
/**
* @title Module to add more functionalities to a contract using extensions.
*
* @dev Implementation of the `fallback(...)` logic according to LSP17 - Contract Extension standard.
* This module can be inherited to extend the functionality of the parent contract when
* calling a function that doesn't exist on the parent contract via forwarding the call
* to an extension mapped to the function selector being called, set originally by the parent contract
*/
abstract contract LSP17Extendable is ERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(
bytes4 interfaceId
) public view virtual override returns (bool) {
return
interfaceId == _INTERFACEID_LSP17_EXTENDABLE ||
super.supportsInterface(interfaceId);
}
/**
* @dev Returns whether the interfaceId being checked is supported in the extension of the
* {supportsInterface} selector.
*
* To be used by extendable contracts wishing to extend the ERC165 interfaceIds originally
* supported by reading whether the interfaceId queried is supported in the `supportsInterface`
* extension if the extension is set, if not it returns false.
*/
function _supportsInterfaceInERC165Extension(
bytes4 interfaceId
) internal view virtual returns (bool) {
address erc165Extension = _getExtension(
ERC165.supportsInterface.selector
);
if (erc165Extension == address(0)) return false;
return
ERC165Checker.supportsERC165InterfaceUnchecked(
erc165Extension,
interfaceId
);
}
/**
* @dev Returns the extension mapped to a specific function selector
* If no extension was found, return the address(0)
* To be overrided.
* Up to the implementor contract to return an extension based on a function selector
*/
function _getExtension(
bytes4 functionSelector
) internal view virtual returns (address);
/**
* @dev Forwards the call to an extension mapped to a function selector.
*
* Calls {_getExtension} to get the address of the extension mapped to the function selector being
* called on the account. If there is no extension, the address(0) will be returned.
*
* Reverts if there is no extension for the function being called.
*
* If there is an extension for the function selector being called, it calls the extension with the
* CALL opcode, passing the {msg.data} appended with the 20 bytes of the {msg.sender} and
* 32 bytes of the {msg.value}
*
* Because the function uses assembly {return()/revert()} to terminate the call, it cannot be
* called before other codes in fallback().
*
* Otherwise, the codes after _fallbackLSP17Extendable() may never be reached.
*/
function _fallbackLSP17Extendable(
bytes calldata callData
) internal virtual returns (bytes memory) {
// If there is a function selector
address extension = _getExtension(msg.sig);
// if no extension was found, revert
if (extension == address(0))
revert NoExtensionFoundForFunctionSelector(msg.sig);
(bool success, bytes memory result) = extension.call(
abi.encodePacked(callData, msg.sender, msg.value)
);
if (success) {
return result;
} else {
// `mload(result)` -> offset in memory where `result.length` is located
// `add(result, 32)` -> offset in memory where `result` data starts
// solhint-disable no-inline-assembly
/// @solidity memory-safe-assembly
assembly {
let resultdata_size := mload(result)
revert(add(result, 32), resultdata_size)
}
}
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.4;
/**
* @title Interface of the LSP1 - Universal Receiver standard, an entry function for a contract to receive arbitrary information.
* @dev LSP1UniversalReceiver allows to receive arbitrary messages and to be informed when assets are sent or received.
*/
interface ILSP1UniversalReceiver {
/**
* @dev Emitted when the {universalReceiver} function was called with a specific `typeId` and some `receivedData`
s
* @notice Address `from` called the `universalReceiver(...)` function while sending `value` LYX. Notification type (typeId): `typeId` - Data received: `receivedData`.
*
* @param from The address of the EOA or smart contract that called the {universalReceiver(...)} function.
* @param value The amount sent to the {universalReceiver(...)} function.
* @param typeId A `bytes32` unique identifier (= _"hook"_)that describe the type of notification, information or transaction received by the contract. Can be related to a specific standard or a hook.
* @param receivedData Any arbitrary data that was sent to the {universalReceiver(...)} function.
* @param returnedValue The value returned by the {universalReceiver(...)} function.
*/
event UniversalReceiver(
address indexed from,
uint256 indexed value,
bytes32 indexed typeId,
bytes receivedData,
bytes returnedValue
);
/**
* @dev Generic function that can be used to notify the contract about specific incoming transactions or events like asset transfers, vault transfers, etc. Allows for custom on-chain and off-chain reactions based on the `typeId` and `data`.
* @notice Reacted on received notification with `typeId` & `data`.
*
* @param typeId The hash of a specific standard or a hook.
* @param data The arbitrary data received with the call.
*
* @custom:events {UniversalReceiver} event.
*/
function universalReceiver(
bytes32 typeId,
bytes calldata data
) external payable returns (bytes memory);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.4;
// --- ERC165 interface ids
bytes4 constant _INTERFACEID_LSP1 = 0x6bb56a14;
// --- ERC725Y Data Keys
// bytes10(keccak256('LSP1UniversalReceiverDelegate'))
bytes10 constant _LSP1_UNIVERSAL_RECEIVER_DELEGATE_PREFIX = 0x0cfc51aec37c55a4d0b1;
// keccak256('LSP1UniversalReceiverDelegate')
bytes32 constant _LSP1_UNIVERSAL_RECEIVER_DELEGATE_KEY = 0x0cfc51aec37c55a4d0b1a65c6255c4bf2fbdf6277f3cc0730c45b828b6db8b47;// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
// interfaces
import {
IERC725Y
} from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol";
// libraries
import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol";
/**
* @title LSP2 Utility library.
* @author Jean Cavallera <CJ42>, Yamen Merhi <YamenMerhi>, Daniel Afteni <B00ste>
* @dev LSP2Utils is a library of utility functions that can be used to encode data key of different key type
* defined on the LSP2 standard.
* Based on LSP2 ERC725Y JSON Schema standard.
*/
library LSP2Utils {
using BytesLib for bytes;
/**
* @dev Generates a data key of keyType Singleton by hashing the string `keyName`. As:
*
* ```
* keccak256("keyName")
* ```
*
* @param keyName The string to hash to generate a Singleton data key.
*
* @return The generated `bytes32` data key of key type Singleton.
*/
function generateSingletonKey(
string memory keyName
) internal pure returns (bytes32) {
return keccak256(bytes(keyName));
}
/**
* @dev Generates a data key of keyType Array by hashing `arrayKeyName`. As:
*
* ```
* keccak256("arrayKeyName[]")
* ```
*
* @param arrayKeyName The string that will be used to generate a data key of key type Array.
*
* @return The generated `bytes32` data key of key type Array.
*
* @custom:requirements
* - The `keyName` must include at the end of the string the square brackets `"[]"`.
*/
function generateArrayKey(
string memory arrayKeyName
) internal pure returns (bytes32) {
bytes memory dataKey = bytes(arrayKeyName);
require(dataKey.length >= 2, "MUST be longer than 2 characters");
require(
dataKey[dataKey.length - 2] == 0x5b && // "[" in utf8 encoded
dataKey[dataKey.length - 1] == 0x5d, // "]" in utf8
"Missing empty square brackets '[]' at the end of the key name"
);
return keccak256(dataKey);
}
/**
* @dev Generates an Array data key at a specific `index` by concatenating together the first 16 bytes of `arrayKey`
* with the 16 bytes of `index`. As:
*
* ```
* arrayKey[index]
* ```
*
* @param arrayKey The Array data key from which to generate the Array data key at a specific `index`.
* @param index The index number in the `arrayKey`.
*
* @return The generated `bytes32` data key of key type Array at a specific `index`.
*/
function generateArrayElementKeyAtIndex(
bytes32 arrayKey,
uint128 index
) internal pure returns (bytes32) {
bytes memory elementInArray = bytes.concat(
bytes16(arrayKey),
bytes16(index)
);
return bytes32(elementInArray);
}
/**
* @dev Generates a data key of key type Mapping that map `firstWord` to `lastWord`. This is done by hashing two strings words `firstWord` and `lastWord`. As:
*
* ```
* bytes10(firstWordHash):0000:bytes20(lastWordHash)
* ```
*
* @param firstWord The word to retrieve the first 10 bytes of its hash.
* @param lastWord The word to retrieve the first 10 bytes of its hash.
*
* @return The generated `bytes32` data key of key type Mapping that map `firstWord` to a specific `lastWord`.
*/
function generateMappingKey(
string memory firstWord,
string memory lastWord
) internal pure returns (bytes32) {
bytes32 firstWordHash = keccak256(bytes(firstWord));
bytes32 lastWordHash = keccak256(bytes(lastWord));
bytes memory temporaryBytes = bytes.concat(
bytes10(firstWordHash),
bytes2(0),
bytes20(lastWordHash)
);
return bytes32(temporaryBytes);
}
/**
* @dev Generates a data key of key type Mapping that map `firstWord` to an address `addr`.
* This is done by hashing the string word `firstWord` and concatenating its first 10 bytes with `addr`. As:
*
* ```
* bytes10(firstWordHash):0000:<address>
* ```
*
* @param firstWord The word to retrieve the first 10 bytes of its hash.
* @param addr An address to map `firstWord` to.
*
* @return The generated `bytes32` data key of key type Mapping that map `firstWord` to a specific address `addr`.
*/
function generateMappingKey(
string memory firstWord,
address addr
) internal pure returns (bytes32) {
bytes32 firstWordHash = keccak256(bytes(firstWord));
bytes memory temporaryBytes = bytes.concat(
bytes10(firstWordHash),
bytes2(0),
bytes20(addr)
);
return bytes32(temporaryBytes);
}
/**
* @dev Generate a data key of key type Mapping that map a 10 bytes `keyPrefix` to a `bytes20Value`. As:
*
* ```
* keyPrefix:bytes20Value
* ```
*
* @param keyPrefix The first part of the data key of key type Mapping.
* @param bytes20Value The second part of the data key of key type Mapping.
*
* @return The generated `bytes32` data key of key type Mapping that map a `keyPrefix` to a specific `bytes20Value`.
*/
function generateMappingKey(
bytes10 keyPrefix,
bytes20 bytes20Value
) internal pure returns (bytes32) {
bytes memory generatedKey = bytes.concat(
keyPrefix,
bytes2(0),
bytes20Value
);
return bytes32(generatedKey);
}
/**
* @dev Generate a data key of key type MappingWithGrouping by using two strings `firstWord`
* mapped to a `secondWord` mapped itself to a specific address `addr`. As:
*
* ```
* bytes6(keccak256("firstWord")):bytes4(keccak256("secondWord")):0000:<address>
* ```
*
* @param firstWord The word to retrieve the first 6 bytes of its hash.
* @param secondWord The word to retrieve the first 4 bytes of its hash.
* @param addr The address that makes the last part of the MappingWithGrouping.
*
* @return The generated `bytes32` data key of key type MappingWithGrouping that map a `firstWord` to a `secondWord` to a specific address `addr`.
*/
function generateMappingWithGroupingKey(
string memory firstWord,
string memory secondWord,
address addr
) internal pure returns (bytes32) {
bytes32 firstWordHash = keccak256(bytes(firstWord));
bytes32 secondWordHash = keccak256(bytes(secondWord));
bytes memory temporaryBytes = bytes.concat(
bytes6(firstWordHash),
bytes4(secondWordHash),
bytes2(0),
bytes20(addr)
);
return bytes32(temporaryBytes);
}
/**
* @dev Generate a data key of key type MappingWithGrouping that map a `keyPrefix` to an other `mapPrefix` to a specific `subMapKey`. As:
*
* ```
* keyPrefix:mapPrefix:0000:subMapKey
* ```
*
* @param keyPrefix The first part (6 bytes) of the data key of keyType MappingWithGrouping.
* @param mapPrefix The second part (4 bytes) of the data key of keyType MappingWithGrouping.
* @param subMapKey The last part (bytes20) of the data key of keyType MappingWithGrouping.
*
* @return The generated `bytes32` data key of key type MappingWithGrouping that map a `keyPrefix` to a `mapPrefix` to a specific `subMapKey`.
*/
function generateMappingWithGroupingKey(
bytes6 keyPrefix,
bytes4 mapPrefix,
bytes20 subMapKey
) internal pure returns (bytes32) {
bytes memory generatedKey = bytes.concat(
keyPrefix,
mapPrefix,
bytes2(0),
subMapKey
);
return bytes32(generatedKey);
}
/**
* @dev Generate a data key of key type MappingWithGrouping that map a 10 bytes `keyPrefix` to a specific `bytes20Value`. As:
*
* @param keyPrefix The first part of the data key of keyType MappingWithGrouping.
* @param bytes20Value The last of the data key of keyType MappingWithGrouping.
*
* @return The generated `bytes32` data key of key type MappingWithGrouping that map a `keyPrefix`
* (containing the first and second mapped word) to a specific `bytes20Value`.
*/
function generateMappingWithGroupingKey(
bytes10 keyPrefix,
bytes20 bytes20Value
) internal pure returns (bytes32) {
bytes memory generatedKey = bytes.concat(
keyPrefix,
bytes2(0),
bytes20Value
);
return bytes32(generatedKey);
}
/**
* @dev Generate a JSONURL value content.
* @param hashFunction The function used to hash the JSON file.
* @param json Bytes value of the JSON file.
* @param url The URL where the JSON file is hosted.
*/
function generateJSONURLValue(
string memory hashFunction,
string memory json,
string memory url
) internal pure returns (bytes memory) {
bytes32 hashFunctionDigest = keccak256(bytes(hashFunction));
bytes32 jsonDigest = keccak256(bytes(json));
return abi.encodePacked(bytes4(hashFunctionDigest), jsonDigest, url);
}
/**
* @dev Generate a ASSETURL value content.
*
* @param hashFunction The function used to hash the JSON file.
* @param assetBytes Bytes value of the JSON file.
* @param url The URL where the JSON file is hosted.
*
* @return The encoded value as an `ASSETURL`.
*/
function generateASSETURLValue(
string memory hashFunction,
string memory assetBytes,
string memory url
) internal pure returns (bytes memory) {
bytes32 hashFunctionDigest = keccak256(bytes(hashFunction));
bytes32 jsonDigest = keccak256(bytes(assetBytes));
return abi.encodePacked(bytes4(hashFunctionDigest), jsonDigest, url);
}
/**
* @dev Verify if `data` is an abi-encoded array.
*
* @param data The bytes value to verify.
*
* @return `true` if the `data` represents an abi-encoded array, `false` otherwise.
*/
function isEncodedArray(bytes memory data) internal pure returns (bool) {
uint256 nbOfBytes = data.length;
// there must be at least 32 x length bytes after offset
uint256 offset = uint256(bytes32(data));
if (nbOfBytes < offset + 32) return false;
uint256 arrayLength = data.toUint256(offset);
// 32 bytes word (= offset)
// + 32 bytes word (= array length)
// + remaining bytes that make each element of the array
if (nbOfBytes < (offset + 32 + (arrayLength * 32))) return false;
return true;
}
/**
* @dev Verify if `data` is an abi-encoded array of addresses (`address[]`) encoded according to the ABI specs.
*
* @param data The bytes value to verify.
*
* @return `true` if the `data` represents an abi-encoded array of addresses, `false` otherwise.
*/
function isEncodedArrayOfAddresses(
bytes memory data
) internal pure returns (bool) {
if (!isEncodedArray(data)) return false;
uint256 offset = uint256(bytes32(data));
uint256 arrayLength = data.toUint256(offset);
uint256 pointer = offset + 32;
for (uint256 ii = 0; ii < arrayLength; ) {
bytes32 key = data.toBytes32(pointer);
// check that the leading bytes are zero bytes "00"
// NB: address type is padded on the left (unlike bytes20 type that is padded on the right)
if (bytes12(key) != bytes12(0)) return false;
// increment the pointer
pointer += 32;
unchecked {
++ii;
}
}
return true;
}
/**
* @dev Verify if `data` is an abi-array of `bytes4` values (`bytes4[]`) encoded according to the ABI specs.
*
* @param data The bytes value to verify.
*
* @return `true` if the `data` represents an abi-encoded array of `bytes4`, `false` otherwise.
*/
function isBytes4EncodedArray(
bytes memory data
) internal pure returns (bool) {
if (!isEncodedArray(data)) return false;
uint256 offset = uint256(bytes32(data));
uint256 arrayLength = data.toUint256(offset);
uint256 pointer = offset + 32;
for (uint256 ii = 0; ii < arrayLength; ) {
bytes32 key = data.toBytes32(pointer);
// check that the trailing bytes are zero bytes "00"
if (uint224(uint256(key)) != 0) return false;
// increment the pointer
pointer += 32;
unchecked {
++ii;
}
}
return true;
}
/**
* @dev Verify if `data` is a valid array of value encoded as a `CompactBytesArray` according to the LSP2 `CompactBytesArray` valueType specification.
*
* @param compactBytesArray The bytes value to verify.
*
* @return `true` if the `data` is correctly encoded CompactBytesArray, `false` otherwise.
*/
function isCompactBytesArray(
bytes memory compactBytesArray
) internal pure returns (bool) {
/**
* Pointer will always land on these values:
*
* ↓↓↓↓
* 0003 a00000
* 0005 fff83a0011
* 0020 aa0000000000000000000000000000000000000000000000000000000000cafe
* 0012 bb000000000000000000000000000000beef
* 0019 cc00000000000000000000000000000000000000000000deed
* ↑↑↑↑
*
* The pointer can only land on the length of the following bytes value.
*/
uint256 pointer = 0;
/**
* Check each length byte and make sure that when you reach the last length byte.
* Make sure that the last length describes exactly the last bytes value and you do not get out of bounds.
*/
while (pointer < compactBytesArray.length) {
if (pointer + 1 >= compactBytesArray.length) return false;
uint256 elementLength = uint16(
bytes2(
abi.encodePacked(
compactBytesArray[pointer],
compactBytesArray[pointer + 1]
)
)
);
pointer += elementLength + 2;
}
if (pointer == compactBytesArray.length) return true;
return false;
}
/**
* @dev Validates if the bytes `arrayLength` are exactly 16 bytes long, and are of the exact size of an LSP2 Array length value
*
* @param arrayLength Plain bytes that should be validated.
*
* @return `true` if the value is 16 bytes long, `false` otherwise.
*/
function isValidLSP2ArrayLengthValue(
bytes memory arrayLength
) internal pure returns (bool) {
if (arrayLength.length == 16) {
return true;
}
return false;
}
/**
* @dev Generates Data Key/Value pairs for removing the last element from an LSP2 Array and a mapping Data Key.
*
* @param arrayKey The Data Key of Key Type Array.
* @param newArrayLength The new Array Length for the `arrayKey`.
* @param removedElementIndexKey The Data Key of Key Type Array Index for the removed element.
* @param removedElementMapKey The Data Key of a mapping to be removed.
*/
function removeLastElementFromArrayAndMap(
bytes32 arrayKey,
uint128 newArrayLength,
bytes32 removedElementIndexKey,
bytes32 removedElementMapKey
)
internal
pure
returns (bytes32[] memory dataKeys, bytes[] memory dataValues)
{
dataKeys = new bytes32[](3);
dataValues = new bytes[](3);
// store the number of received assets decremented by 1
dataKeys[0] = arrayKey;
dataValues[0] = abi.encodePacked(newArrayLength);
// remove the data value for the map key of the element
dataKeys[1] = removedElementMapKey;
dataValues[1] = "";
// remove the data value for the map key of the element
dataKeys[2] = removedElementIndexKey;
dataValues[2] = "";
}
/**
* @dev Generates Data Key/Value pairs for removing an element from an LSP2 Array and a mapping Data Key.
*
* @custom:info The function assumes that the Data Value stored under the mapping Data Key is of length 20 where the last 16 bytes are the index of the element in the array.
*
* @param erc725YContract The ERC725Y contract.
* @param arrayKey The Data Key of Key Type Array.
* @param newArrayLength The new Array Length for the `arrayKey`.
* @param removedElementIndexKey The Data Key of Key Type Array Index for the removed element.
* @param removedElementIndex the index of the removed element.
* @param removedElementMapKey The Data Key of a mapping to be removed.
*/
function removeElementFromArrayAndMap(
IERC725Y erc725YContract,
bytes32 arrayKey,
uint128 newArrayLength,
bytes32 removedElementIndexKey,
uint128 removedElementIndex,
bytes32 removedElementMapKey
)
internal
view
returns (bytes32[] memory dataKeys, bytes[] memory dataValues)
{
dataKeys = new bytes32[](5);
dataValues = new bytes[](5);
// store the number of received assets decremented by 1
dataKeys[0] = arrayKey;
dataValues[0] = abi.encodePacked(newArrayLength);
// remove the data value for the map key of the element
dataKeys[1] = removedElementMapKey;
dataValues[1] = "";
// Generate the key of the last element in the array
bytes32 lastElementIndexKey = LSP2Utils.generateArrayElementKeyAtIndex(
arrayKey,
newArrayLength
);
// Get the data value from the key of the last element in the array
bytes20 lastElementIndexValue = bytes20(
erc725YContract.getData(lastElementIndexKey)
);
// Set data value of the last element instead of the element from the array that will be removed
dataKeys[2] = removedElementIndexKey;
dataValues[2] = bytes.concat(lastElementIndexValue);
// Remove the data value for the swapped array element
dataKeys[3] = lastElementIndexKey;
dataValues[3] = "";
// Generate mapping key for the swapped array element
bytes32 lastElementMapKey = LSP2Utils.generateMappingKey(
bytes10(removedElementMapKey),
lastElementIndexValue
);
// Generate the mapping value for the swapped array element
bytes memory lastElementMapValue = abi.encodePacked(
bytes4(erc725YContract.getData(lastElementMapKey)),
removedElementIndex
);
// Update the map value of the swapped array element to the new index
dataKeys[4] = lastElementMapKey;
dataValues[4] = lastElementMapValue;
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.4;
// --- ERC725Y entries
// bytes10(keccak256('SupportedStandards')) + bytes2(0) + bytes20(keccak256('LSP4DigitalAsset'))
bytes32 constant _LSP4_SUPPORTED_STANDARDS_KEY = 0xeafec4d89fa9619884b60000a4d96624a38f7ac2d8d9a604ecf07c12c77e480c;
// bytes4(keccak256('LSP4DigitalAsset'))
bytes constant _LSP4_SUPPORTED_STANDARDS_VALUE = hex"a4d96624";
// keccak256('LSP4TokenName')
bytes32 constant _LSP4_TOKEN_NAME_KEY = 0xdeba1e292f8ba88238e10ab3c7f88bd4be4fac56cad5194b6ecceaf653468af1;
// keccak256('LSP4TokenSymbol')
bytes32 constant _LSP4_TOKEN_SYMBOL_KEY = 0x2f0a68ab07768e01943a599e73362a0e17a63a72e94dd2e384d2c1d4db932756;
// keccak256('LSP4Creators[]')
bytes32 constant _LSP4_CREATORS_ARRAY_KEY = 0x114bd03b3a46d48759680d81ebb2b414fda7d030a7105a851867accf1c2352e7;
// bytes10(keccak256('LSP4CreatorsMap')) + bytes2(0)
bytes12 constant _LSP4_CREATORS_MAP_KEY_PREFIX = 0x6de85eaf5d982b4e5da00000;
// keccak256('LSP4Metadata')
bytes32 constant _LSP4_METADATA_KEY = 0x9afb95cacc9f95858ec44aa8c3b685511002e30ae54415823f406128b85b238e;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
// modules
import {ERC725Y} from "@erc725/smart-contracts/contracts/ERC725Y.sol";
// libraries
import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol";
// constants
import "./LSP4Constants.sol";
// errors
import {
LSP4TokenNameNotEditable,
LSP4TokenSymbolNotEditable
} from "./LSP4Errors.sol";
/**
* @title Implementation of a LSP4DigitalAssetMetadata contract that stores the **Token-Metadata** (`LSP4TokenName` and `LSP4TokenSymbol`) in its ERC725Y data store.
* @author Matthew Stevens
* @dev Standard Implementation of the LSP4 standard.
*/
abstract contract LSP4DigitalAssetMetadata is ERC725Y {
/**
* @notice Deploying a digital asset `name_` with the `symbol_` symbol.
*
* @param name_ The name of the token
* @param symbol_ The symbol of the token
* @param initialOwner_ The owner of the token contract
*/
constructor(
string memory name_,
string memory symbol_,
address initialOwner_
) ERC725Y(initialOwner_) {
// set data key SupportedStandards:LSP4DigitalAsset
super._setData(
_LSP4_SUPPORTED_STANDARDS_KEY,
_LSP4_SUPPORTED_STANDARDS_VALUE
);
super._setData(_LSP4_TOKEN_NAME_KEY, bytes(name_));
super._setData(_LSP4_TOKEN_SYMBOL_KEY, bytes(symbol_));
}
/**
* @dev The ERC725Y data keys `LSP4TokenName` and `LSP4TokenSymbol` cannot be changed
* via this function once the digital asset contract has been deployed.
*
* @dev Save gas by emitting the {DataChanged} event with only the first 256 bytes of dataValue
*/
function _setData(
bytes32 dataKey,
bytes memory dataValue
) internal virtual override {
if (dataKey == _LSP4_TOKEN_NAME_KEY) {
revert LSP4TokenNameNotEditable();
} else if (dataKey == _LSP4_TOKEN_SYMBOL_KEY) {
revert LSP4TokenSymbolNotEditable();
} else {
_store[dataKey] = dataValue;
emit DataChanged(
dataKey,
dataValue.length <= 256
? dataValue
: BytesLib.slice(dataValue, 0, 256)
);
}
}
}// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.4; /** * @dev Reverts when trying to edit the data key `LSP4TokenName` after the digital asset contract has been deployed. * The `LSP4TokenName` data key is located inside the ERC725Y Data key-value store of the digital asset contract. * It can be set only once inside the constructor/initializer when the digital asset contract is being deployed. */ error LSP4TokenNameNotEditable(); /** * @dev Reverts when trying to edit the data key `LSP4TokenSymbol` after the digital asset contract has been deployed. * The `LSP4TokenSymbol` data key is located inside the ERC725Y Data key-value store of the digital asset contract. * It can be set only once inside the constructor/initializer when the digital asset contract is being deployed. */ error LSP4TokenSymbolNotEditable();
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
// interfaces
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {
IERC725Y
} from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol";
/**
* @title Interface of the LSP8 - Identifiable Digital Asset standard, a non-fungible digital asset.
*/
interface ILSP8IdentifiableDigitalAsset is IERC165, IERC725Y {
// --- Events
/**
* @dev Emitted when `tokenId` token is transferred from the `from` to the `to` address.
* @param operator The address of operator that sent the `tokenId`
* @param from The previous owner of the `tokenId`
* @param to The new owner of `tokenId`
* @param tokenId The tokenId that was transferred
* @param allowNonLSP1Recipient If the token transfer enforces the `to` recipient address to be a contract that implements the LSP1 standard or not.
* @param data Any additional data the caller included by the caller during the transfer, and sent in the hooks to the `from` and `to` addresses.
*/
event Transfer(
address operator,
address indexed from,
address indexed to,
bytes32 indexed tokenId,
bool allowNonLSP1Recipient,
bytes data
);
/**
* @dev Emitted when `tokenOwner` enables `operator` to transfer or burn the `tokenId`.
* @param operator The address authorized as an operator.
* @param tokenOwner The owner of the `tokenId`.
* @param tokenId The tokenId `operator` address has access on behalf of `tokenOwner`.
* @param operatorNotificationData The data to notify the operator about via LSP1.
*/
event AuthorizedOperator(
address indexed operator,
address indexed tokenOwner,
bytes32 indexed tokenId,
bytes operatorNotificationData
);
/**
* @dev Emitted when `tokenOwner` disables `operator` to transfer or burn `tokenId` on its behalf.
* @param operator The address revoked from the operator array ({getOperatorsOf}).
* @param tokenOwner The owner of the `tokenId`.
* @param tokenId The tokenId `operator` is revoked from operating on.
* @param operatorNotificationData The data to notify the operator about via LSP1.
*/
event RevokedOperator(
address indexed operator,
address indexed tokenOwner,
bytes32 indexed tokenId,
bytes operatorNotificationData
);
// --- Token queries
/**
* @dev Returns the number of existing tokens that have been minted in this contract.
* @return The number of existing tokens.
*/
function totalSupply() external view returns (uint256);
// --- Token owner queries
/**
* @dev Get the number of token IDs owned by `tokenOwner`.
* @param tokenOwner The address to query *
* @return The total number of token IDs that `tokenOwner` owns.
*/
function balanceOf(address tokenOwner) external view returns (uint256);
/**
* @dev Returns the list of `tokenIds` for the `tokenOwner` address.
*
* @param tokenId tokenOwner The address to query owned tokens
* @return The owner address of the given `tokenId`.
*
* @custom:requirements `tokenId` must exist.
* @custom:info if the `tokenId` is not owned by any address, the returned address will be `address(0)`
*/
function tokenOwnerOf(bytes32 tokenId) external view returns (address);
/**
* @dev Returns the list of token IDs that the `tokenOwner` address owns.
* @param tokenOwner The address that we want to get the list of token IDs for.
* @return An array of `bytes32[] tokenIds` owned by `tokenOwner`.
*/
function tokenIdsOf(
address tokenOwner
) external view returns (bytes32[] memory);
// --- Operator functionality
/**
* @dev Allow an `operator` address to transfer or burn a specific `tokenId` on behalf of its token owner. See {isOperatorFor}.
*
* @param operator The address to authorize as an operator.
* @param tokenId The token ID operator has access to.
* @param operatorNotificationData The data to notify the operator about via LSP1.
*
* @custom:requirements
* - `tokenId` must exist.
* - caller MUST be the {tokenOwnerOf} `tokenId`.
* - the owner of a `tokenId` cannot grant itself as an `operator` (`operator` cannot be the calling address).
* - `operator` cannot be the zero address.
*
* @custom:events {AuthorizedOperator} event.
*/
function authorizeOperator(
address operator,
bytes32 tokenId,
bytes memory operatorNotificationData
) external;
/**
* @dev Remove access of `operator` for a given `tokenId`, disallowing it to transfer `tokenId` on behalf of its owner.
* See also {isOperatorFor}.
*
* @param operator The address to revoke as an operator.
* @param tokenId The tokenId `operator` is revoked from operating on.
* @param operatorNotificationData The data to notify the operator about via LSP1.
*
* @custom:requirements
* - `tokenId` must exist.
* - caller must be the {tokenOwnerOf} `tokenId`.
* - the owner of a `tokenId` cannot grant revoke itself as an `operator` (`operator` cannot be the calling address).
* - `operator` cannot be the zero address.
*
* @custom:events {RevokedOperator} event with address of the operator being revoked for the caller (token owner)..
*/
function revokeOperator(
address operator,
bytes32 tokenId,
bytes memory operatorNotificationData
) external;
/**
* @dev Returns whether `operator` address is an operator for a given `tokenId`.
*
* @param operator The address to query operator status for.
* @param tokenId The token ID to check if `operator` is allowed to operate on.
*
* @return `true` if `operator` is an operator for `tokenId`, `false` otherwise.
*
* @custom:requirements
* - `tokenId` must exist.
* - caller must be the current {tokenOwnerOf} `tokenId`.
*
* @custom:info The tokenOwner is its own operator.
*/
function isOperatorFor(
address operator,
bytes32 tokenId
) external view returns (bool);
/**
* @dev Returns all `operator` addresses that are allowed to transfer or burn a specific `tokenId` on behalf of its owner.
*
* @param tokenId The token ID to get the operators for.
* @return An array of operators allowed to transfer or burn a specific `tokenId`.
*
* Requirements
* - `tokenId` must exist.
*/
function getOperatorsOf(
bytes32 tokenId
) external view returns (address[] memory);
// --- Transfer functionality
/**
* @dev Transfer a given `tokenId` token from the `from` address to the `to` address.
*
* If operators are set for a specific `tokenId`, all the operators are revoked after the tokenId have been transferred.
*
* The `allowNonLSP1Recipient` parameter MUST be set to `true` when transferring tokens to Externally Owned Accounts (EOAs)
* or contracts that do not implement the LSP1 standard.
*
* @param from The address that owns the given `tokenId`.
* @param to The address that will receive the `tokenId`.
* @param tokenId The token ID to transfer.
* @param allowNonLSP1Recipient When set to `true`, the `to` address CAN be any addres.
* When set to `false`, the `to` address MUST be a contract that supports the LSP1 UniversalReceiver standard.
* @param data Any additional data the caller wants included in the emitted event, and sent in the hooks of the `from` and `to` addresses.
*
* @custom:requirements
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` and `to` cannot be the same address (`from` cannot send the `tokenId` to itself).
* - `from` must own the given `tokenId`.
* - If the caller is not `from`, it must be an operator for the `tokenId`.
*
* @custom:events
* - {Transfer} event when the `tokenId` is successfully transferred.
*
* @custom:hint The `allowNonLSP1Recipient` parameter **MUST be set to `true`** to transfer tokens to Externally Owned Accounts (EOAs)
* or contracts that do not implement the LSP1 Universal Receiver Standard. Otherwise the function will revert making the transfer fail.
*
* @custom:info if the `to` address is a contract that implements LSP1, it will always be notified via its `universalReceiver(...)` function, regardless if `allowNonLSP1Recipient` is set to `true` or `false`.
*
* @custom:warning Be aware that when either the sender or the recipient can have logic that revert in their `universalReceiver(...)` function when being notified.
* This even if the `allowNonLSP1Recipient` was set to `true`.
*/
function transfer(
address from,
address to,
bytes32 tokenId,
bool allowNonLSP1Recipient,
bytes memory data
) external;
/**
* @dev Transfers multiple tokens at once based on the arrays of `from`, `to` and `tokenId`.
* If any transfer fails, the whole call will revert.
*
* @param from An array of sending addresses.
* @param to An array of recipient addresses.
* @param tokenId An array of token IDs to transfer.
* @param allowNonLSP1Recipient When set to `true`, `to` may be any address.
* When set to `false`, `to` must be a contract that supports the LSP1 standard and not revert.
* @param data Any additional data the caller wants included in the emitted event, and sent in the hooks to the `from` and `to` addresses.
*
*
* @custom:requirements
* - The arrays of `from`, `to` and `tokenId` must have the same length.
* - no values in the `from` array can be the zero address.
* - no values in the `to` array can be the zero address.
* - `from` and `to` cannot be the same address at the same index on each arrays.
* - each `tokenId` must be owned by `from`.
* - If the caller is not `from`, it must be an operator of each `tokenId`.
*
* @custom:events
* - {Transfer} events on each successful token transfer.
*/
function transferBatch(
address[] memory from,
address[] memory to,
bytes32[] memory tokenId,
bool[] memory allowNonLSP1Recipient,
bytes[] memory data
) external;
}// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.4;
// --- ERC165 interface ids
bytes4 constant _INTERFACEID_LSP8 = 0x1ae9ba1f;
// --- ERC725Y Data Keys
// bytes10(keccak256('LSP8MetadataAddress')) + bytes2(0)
bytes12 constant _LSP8_METADATA_ADDRESS_KEY_PREFIX = 0x73dcc7c3c4096cdc7f8a0000;
// bytes10(keccak256('LSP8MetadataJSON')) + bytes2(0)
bytes12 constant _LSP8_METADATA_JSON_KEY_PREFIX = 0x9a26b4060ae7f7d5e3cd0000;
// --- Token Hooks
// keccak256('LSP8Tokens_SenderNotification')
bytes32 constant _TYPEID_LSP8_TOKENSSENDER = 0xb23eae7e6d1564b295b4c3e3be402d9a2f0776c57bdf365903496f6fa481ab00;
// keccak256('LSP8Tokens_RecipientNotification')
bytes32 constant _TYPEID_LSP8_TOKENSRECIPIENT = 0x0b084a55ebf70fd3c06fd755269dac2212c4d3f0f4d09079780bfa50c1b2984d;
// keccak256('LSP8Tokens_OperatorNotification')
bytes32 constant _TYPEID_LSP8_TOKENOPERATOR = 0x8a1c15a8799f71b547e08e2bcb2e85257e81b0a07eee2ce6712549eef1f00970;// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.4;
// --- Errors
/**
* @dev reverts when `tokenId` has not been minted.
*/
error LSP8NonExistentTokenId(bytes32 tokenId);
/**
* @dev reverts when `caller` is not the `tokenOwner` of the `tokenId`.
*/
error LSP8NotTokenOwner(address tokenOwner, bytes32 tokenId, address caller);
/**
* @dev reverts when `caller` is not an allowed operator for `tokenId`.
*/
error LSP8NotTokenOperator(bytes32 tokenId, address caller);
/**
* @dev reverts when `operator` is already authorized for the `tokenId`.
*/
error LSP8OperatorAlreadyAuthorized(address operator, bytes32 tokenId);
/**
* @dev reverts when trying to set the zero address as an operator.
*/
error LSP8CannotUseAddressZeroAsOperator();
/**
* @dev reverts when trying to send token to the zero address.
*/
error LSP8CannotSendToAddressZero();
/**
* @dev reverts when specifying the same address for `from` and `to` in a token transfer.
*/
error LSP8CannotSendToSelf();
/**
* @dev reverts when `operator` is not an operator for the `tokenId`.
*/
error LSP8NonExistingOperator(address operator, bytes32 tokenId);
/**
* @dev reverts when `tokenId` has already been minted.
*/
error LSP8TokenIdAlreadyMinted(bytes32 tokenId);
/**
* @dev reverts when the parameters used for `transferBatch` have different lengths.
*/
error LSP8InvalidTransferBatch();
/**
* @dev reverts if the `tokenReceiver` does not implement LSP1
* when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`.
*/
error LSP8NotifyTokenReceiverContractMissingLSP1Interface(
address tokenReceiver
);
/**
* @dev reverts if the `tokenReceiver` is an EOA
* when minting or transferring tokens with `bool allowNonLSP1Recipient` set as `false`.
*/
error LSP8NotifyTokenReceiverIsEOA(address tokenReceiver);
/**
* @dev reverts when trying to authorize or revoke the token's owner as an operator.
*/
error LSP8TokenOwnerCannotBeOperator();// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.4;
// interfaces
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
// modules
import {ERC725YCore} from "@erc725/smart-contracts/contracts/ERC725YCore.sol";
import {
LSP8IdentifiableDigitalAssetCore
} from "./LSP8IdentifiableDigitalAssetCore.sol";
import {
LSP4DigitalAssetMetadata
} from "../LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol";
import {LSP17Extendable} from "../LSP17ContractExtension/LSP17Extendable.sol";
// libraries
import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol";
// constants
import {_INTERFACEID_LSP8} from "./LSP8Constants.sol";
import "../LSP17ContractExtension/LSP17Constants.sol";
// errors
import {
NoExtensionFoundForFunctionSelector,
InvalidFunctionSelector,
InvalidExtensionAddress
} from "../LSP17ContractExtension/LSP17Errors.sol";
/**
* @title Implementation of a LSP8 Identifiable Digital Asset, a contract that represents a non-fungible token.
* @author Matthew Stevens
*
* @dev Standard implementation contract of the LSP8 standard.
*
* Minting and transferring are done by providing a unique `tokenId`.
* This implementation is agnostic to the way tokens are created.
* A supply mechanism has to be added in a derived contract using {_mint}
* For a generic mechanism, see {LSP7Mintable}.
*/
abstract contract LSP8IdentifiableDigitalAsset is
LSP4DigitalAssetMetadata,
LSP8IdentifiableDigitalAssetCore,
LSP17Extendable
{
/**
* @notice Sets the token-Metadata
* @param name_ The name of the token
* @param symbol_ The symbol of the token
* @param newOwner_ The owner of the the token-Metadata
*/
constructor(
string memory name_,
string memory symbol_,
address newOwner_
) LSP4DigitalAssetMetadata(name_, symbol_, newOwner_) {}
// fallback function
// solhint-disable no-complex-fallback
/**
* @notice The `fallback` function was called with the following amount of native tokens: `msg.value`; and the following calldata: `callData`.
*
* @dev Achieves the goal of [LSP-17-ContractExtension] standard by extending the contract to handle calls of functions that do not exist natively,
* forwarding the function call to the extension address mapped to the function being called.
*
* This function is executed when:
* - Sending data of length less than 4 bytes to the contract.
* - The first 4 bytes of the calldata do not match any publicly callable functions from the contract ABI.
* - Receiving native tokens
*
* 1. If the data is equal or longer than 4 bytes, the [ERC-725Y] storage is queried with the following data key: [_LSP17_EXTENSION_PREFIX] + `bytes4(msg.sig)` (Check [LSP-2-ERC725YJSONSchema] for encoding the data key)
*
* - If there is no address stored under the following data key, revert with {NoExtensionFoundForFunctionSelector(bytes4)}. The data key relative to `bytes4(0)` is an exception, where no reverts occurs if there is no extension address stored under. This exception is made to allow users to send random data (graffiti) to the account and to be able to react on it.
*
* - If there is an address, forward the `msg.data` to the extension using the CALL opcode, appending 52 bytes (20 bytes of `msg.sender` and 32 bytes of `msg.value`). Return what the calls returns, or revert if the call failed.
*
* 2. If the data sent to this function is of length less than 4 bytes (not a function selector), revert.
*/
fallback(
bytes calldata callData
) external payable virtual returns (bytes memory) {
if (msg.data.length < 4) {
revert InvalidFunctionSelector(callData);
}
return _fallbackLSP17Extendable(callData);
}
/**
* @dev Forwards the call with the received value to an extension mapped to a function selector.
*
* Calls {_getExtension} to get the address of the extension mapped to the function selector being
* called on the account. If there is no extension, the address(0) will be returned.
*
* Reverts if there is no extension for the function being called.
*
* If there is an extension for the function selector being called, it calls the extension with the
* CALL opcode, passing the {msg.data} appended with the 20 bytes of the {msg.sender} and
* 32 bytes of the {msg.value}
*
* Because the function uses assembly {return()/revert()} to terminate the call, it cannot be
* called before other codes in fallback().
*
* Otherwise, the codes after _fallbackLSP17Extendable() may never be reached.
*/
function _fallbackLSP17Extendable(
bytes calldata callData
) internal virtual override returns (bytes memory) {
// If there is a function selector
address extension = _getExtension(msg.sig);
// if no extension was found, revert
if (extension == address(0))
revert NoExtensionFoundForFunctionSelector(msg.sig);
(bool success, bytes memory result) = extension.call{value: msg.value}(
abi.encodePacked(callData, msg.sender, msg.value)
);
if (success) {
return result;
} else {
// `mload(result)` -> offset in memory where `result.length` is located
// `add(result, 32)` -> offset in memory where `result` data starts
// solhint-disable no-inline-assembly
/// @solidity memory-safe-assembly
assembly {
let resultdata_size := mload(result)
revert(add(result, 32), resultdata_size)
}
}
}
/**
* @dev Returns the extension address stored under the following data key:
* - {_LSP17_EXTENSION_PREFIX} + `<bytes4>` (Check [LSP2-ERC725YJSONSchema] for encoding the data key).
* - If no extension is stored, returns the address(0).
*/
function _getExtension(
bytes4 functionSelector
) internal view virtual override returns (address) {
// Generate the data key relevant for the functionSelector being called
bytes32 mappedExtensionDataKey = LSP2Utils.generateMappingKey(
_LSP17_EXTENSION_PREFIX,
functionSelector
);
// Check if there is an extension stored under the generated data key
bytes memory extensionAddress = ERC725YCore._getData(
mappedExtensionDataKey
);
if (extensionAddress.length != 20 && extensionAddress.length != 0)
revert InvalidExtensionAddress(extensionAddress);
return address(bytes20(extensionAddress));
}
/**
* @inheritdoc IERC165
*/
function supportsInterface(
bytes4 interfaceId
)
public
view
virtual
override(IERC165, ERC725YCore, LSP17Extendable)
returns (bool)
{
return
interfaceId == _INTERFACEID_LSP8 ||
super.supportsInterface(interfaceId) ||
LSP17Extendable._supportsInterfaceInERC165Extension(interfaceId);
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.4;
// interfaces
import {
ILSP1UniversalReceiver
} from "../LSP1UniversalReceiver/ILSP1UniversalReceiver.sol";
import {
ILSP8IdentifiableDigitalAsset
} from "./ILSP8IdentifiableDigitalAsset.sol";
// libraries
import {
EnumerableSet
} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {
ERC165Checker
} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
// errors
import "./LSP8Errors.sol";
// constants
import {_INTERFACEID_LSP1} from "../LSP1UniversalReceiver/LSP1Constants.sol";
import {
_TYPEID_LSP8_TOKENOPERATOR,
_TYPEID_LSP8_TOKENSSENDER,
_TYPEID_LSP8_TOKENSRECIPIENT
} from "./LSP8Constants.sol";
/**
* @title LSP8IdentifiableDigitalAsset contract
* @author Matthew Stevens
* @dev Core Implementation of a LSP8 compliant contract.
*/
abstract contract LSP8IdentifiableDigitalAssetCore is
ILSP8IdentifiableDigitalAsset
{
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableSet for EnumerableSet.Bytes32Set;
// --- Storage
uint256 internal _existingTokens;
// Mapping from `tokenId` to `tokenOwner`
mapping(bytes32 => address) internal _tokenOwners;
// Mapping `tokenOwner` to owned tokenIds
mapping(address => EnumerableSet.Bytes32Set) internal _ownedTokens;
// Mapping a `tokenId` to its authorized operator addresses.
mapping(bytes32 => EnumerableSet.AddressSet) internal _operators;
mapping(address => EnumerableSet.Bytes32Set) internal _tokenIdsForOperator;
// --- Token queries
/**
* @inheritdoc ILSP8IdentifiableDigitalAsset
*/
function totalSupply() public view virtual returns (uint256) {
return _existingTokens;
}
// --- Token owner queries
/**
* @inheritdoc ILSP8IdentifiableDigitalAsset
*/
function balanceOf(
address tokenOwner
) public view virtual returns (uint256) {
return _ownedTokens[tokenOwner].length();
}
/**
* @inheritdoc ILSP8IdentifiableDigitalAsset
*/
function tokenOwnerOf(
bytes32 tokenId
) public view virtual returns (address) {
address tokenOwner = _tokenOwners[tokenId];
if (tokenOwner == address(0)) {
revert LSP8NonExistentTokenId(tokenId);
}
return tokenOwner;
}
/**
* @inheritdoc ILSP8IdentifiableDigitalAsset
*/
function tokenIdsOf(
address tokenOwner
) public view virtual returns (bytes32[] memory) {
return _ownedTokens[tokenOwner].values();
}
// --- Operator functionality
/**
* @inheritdoc ILSP8IdentifiableDigitalAsset
*/
function authorizeOperator(
address operator,
bytes32 tokenId,
bytes memory operatorNotificationData
) public virtual {
address tokenOwner = tokenOwnerOf(tokenId);
if (tokenOwner != msg.sender) {
revert LSP8NotTokenOwner(tokenOwner, tokenId, msg.sender);
}
if (operator == address(0)) {
revert LSP8CannotUseAddressZeroAsOperator();
}
if (tokenOwner == operator) {
revert LSP8TokenOwnerCannotBeOperator();
}
bool isAdded = _operators[tokenId].add(operator);
if (!isAdded) revert LSP8OperatorAlreadyAuthorized(operator, tokenId);
emit AuthorizedOperator(
operator,
tokenOwner,
tokenId,
operatorNotificationData
);
bytes memory lsp1Data = abi.encode(
msg.sender,
tokenId,
operatorNotificationData
);
_notifyTokenOperator(operator, lsp1Data);
}
/**
* @inheritdoc ILSP8IdentifiableDigitalAsset
*/
function revokeOperator(
address operator,
bytes32 tokenId,
bytes memory operatorNotificationData
) public virtual {
address tokenOwner = tokenOwnerOf(tokenId);
if (tokenOwner != msg.sender) {
revert LSP8NotTokenOwner(tokenOwner, tokenId, msg.sender);
}
if (operator == address(0)) {
revert LSP8CannotUseAddressZeroAsOperator();
}
if (tokenOwner == operator) {
revert LSP8TokenOwnerCannotBeOperator();
}
_revokeOperator(
operator,
tokenOwner,
tokenId,
operatorNotificationData
);
bytes memory lsp1Data = abi.encode(
msg.sender,
tokenId,
operatorNotificationData
);
_notifyTokenOperator(operator, lsp1Data);
}
/**
* @inheritdoc ILSP8IdentifiableDigitalAsset
*/
function isOperatorFor(
address operator,
bytes32 tokenId
) public view virtual returns (bool) {
_existsOrError(tokenId);
return _isOperatorOrOwner(operator, tokenId);
}
/**
* @inheritdoc ILSP8IdentifiableDigitalAsset
*/
function getOperatorsOf(
bytes32 tokenId
) public view virtual returns (address[] memory) {
_existsOrError(tokenId);
return _operators[tokenId].values();
}
/**
* @dev verifies if the `caller` is operator or owner for the `tokenId`
* @return true if `caller` is either operator or owner
*/
function _isOperatorOrOwner(
address caller,
bytes32 tokenId
) internal view virtual returns (bool) {
address tokenOwner = tokenOwnerOf(tokenId);
return (caller == tokenOwner || _operators[tokenId].contains(caller));
}
// --- Transfer functionality
/**
* @inheritdoc ILSP8IdentifiableDigitalAsset
*/
function transfer(
address from,
address to,
bytes32 tokenId,
bool allowNonLSP1Recipient,
bytes memory data
) public virtual {
address operator = msg.sender;
if (!_isOperatorOrOwner(operator, tokenId)) {
revert LSP8NotTokenOperator(tokenId, operator);
}
_transfer(from, to, tokenId, allowNonLSP1Recipient, data);
}
/**
* @inheritdoc ILSP8IdentifiableDigitalAsset
*/
function transferBatch(
address[] memory from,
address[] memory to,
bytes32[] memory tokenId,
bool[] memory allowNonLSP1Recipient,
bytes[] memory data
) public virtual {
uint256 fromLength = from.length;
if (
fromLength != to.length ||
fromLength != tokenId.length ||
fromLength != allowNonLSP1Recipient.length ||
fromLength != data.length
) {
revert LSP8InvalidTransferBatch();
}
for (uint256 i = 0; i < fromLength; ) {
transfer(
from[i],
to[i],
tokenId[i],
allowNonLSP1Recipient[i],
data[i]
);
unchecked {
++i;
}
}
}
/**
* @dev removes `operator` from the list of operators for the `tokenId`
*/
function _revokeOperator(
address operator,
address tokenOwner,
bytes32 tokenId,
bytes memory operatorNotificationData
) internal virtual {
bool isRemoved = _operators[tokenId].remove(operator);
if (!isRemoved) revert LSP8NonExistingOperator(operator, tokenId);
emit RevokedOperator(
operator,
tokenOwner,
tokenId,
operatorNotificationData
);
}
/**
* @dev revoke all the current operators for a specific `tokenId` token which belongs to `tokenOwner`.
*
* @param tokenOwner The address that is the owner of the `tokenId`.
* @param tokenId The token to remove the associated operators for.
*/
function _clearOperators(
address tokenOwner,
bytes32 tokenId
) internal virtual {
// here is a good example of why having multiple operators will be expensive.. we
// need to clear them on token transfer
//
// NOTE: this may cause a tx to fail if there is too many operators to clear, in which case
// the tokenOwner needs to call `revokeOperator` until there is less operators to clear and
// the desired `transfer` or `burn` call can succeed.
EnumerableSet.AddressSet storage operatorsForTokenId = _operators[
tokenId
];
uint256 operatorListLength = operatorsForTokenId.length();
for (uint256 i = 0; i < operatorListLength; ) {
// we are emptying the list, always remove from index 0
address operator = operatorsForTokenId.at(0);
_revokeOperator(operator, tokenOwner, tokenId, "");
unchecked {
++i;
}
}
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens start existing when they are minted ({_mint}), and stop existing when they are burned ({_burn}).
*/
function _exists(bytes32 tokenId) internal view virtual returns (bool) {
return _tokenOwners[tokenId] != address(0);
}
/**
* @dev When `tokenId` does not exist then revert with an error.
*/
function _existsOrError(bytes32 tokenId) internal view virtual {
if (!_exists(tokenId)) {
revert LSP8NonExistentTokenId(tokenId);
}
}
/**
* @dev Create `tokenId` by minting it and transfers it to `to`.
*
* @custom:requirements
* - `tokenId` must not exist and not have been already minted.
* - `to` cannot be the zero address.
*
* @param to The address that will receive the minted `tokenId`.
* @param tokenId The token ID to create (= mint).
* @param allowNonLSP1Recipient When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard.
* @param data Any additional data the caller wants included in the emitted event, and sent in the hook of the `to` address.
*
* @custom:events {Transfer} event with `address(0)` as `from` address.
*/
function _mint(
address to,
bytes32 tokenId,
bool allowNonLSP1Recipient,
bytes memory data
) internal virtual {
if (to == address(0)) {
revert LSP8CannotSendToAddressZero();
}
if (_exists(tokenId)) {
revert LSP8TokenIdAlreadyMinted(tokenId);
}
address operator = msg.sender;
_beforeTokenTransfer(address(0), to, tokenId);
// token being minted
_existingTokens += 1;
_ownedTokens[to].add(tokenId);
_tokenOwners[tokenId] = to;
emit Transfer(
operator,
address(0),
to,
tokenId,
allowNonLSP1Recipient,
data
);
bytes memory lsp1Data = abi.encode(address(0), to, tokenId, data);
_notifyTokenReceiver(to, allowNonLSP1Recipient, lsp1Data);
}
/**
* @dev Burn a specific `tokenId`, removing the `tokenId` from the {tokenIdsOf} the caller and decreasing its {balanceOf} by -1.
* This will also clear all the operators allowed to transfer the `tokenId`.
*
* The owner of the `tokenId` will be notified about the `tokenId` being transferred through its LSP1 {universalReceiver}
* function, if it is a contract that supports the LSP1 interface. Its {universalReceiver} function will receive
* all the parameters in the calldata packed encoded.
*
* Any logic in the {_beforeTokenTransfer} function will run before burning `tokenId` and updating the balances.
*
* @param tokenId The token to burn.
* @param data Any additional data the caller wants included in the emitted event, and sent in the LSP1 hook on the token owner's address.
*
* @custom:hint In dApps, you can know which addresses are burning tokens by listening for the `Transfer` event and filter with the zero address as `to`.
*
* @custom:requirements
* - `tokenId` must exist.
*
* @custom:events {Transfer} event with `address(0)` as the `to` address.
*/
function _burn(bytes32 tokenId, bytes memory data) internal virtual {
address tokenOwner = tokenOwnerOf(tokenId);
address operator = msg.sender;
_beforeTokenTransfer(tokenOwner, address(0), tokenId);
// token being burned
_existingTokens -= 1;
_clearOperators(tokenOwner, tokenId);
_ownedTokens[tokenOwner].remove(tokenId);
delete _tokenOwners[tokenId];
emit Transfer(operator, tokenOwner, address(0), tokenId, false, data);
bytes memory lsp1Data = abi.encode(
tokenOwner,
address(0),
tokenId,
data
);
_notifyTokenSender(tokenOwner, lsp1Data);
}
/**
* @dev Change the owner of the `tokenId` from `from` to `to`.
*
* Both the sender and recipient will be notified of the `tokenId` being transferred through their LSP1 {universalReceiver}
* function, if they are contracts that support the LSP1 interface. Their `universalReceiver` function will receive
* all the parameters in the calldata packed encoded.
*
* Any logic in the {_beforeTokenTransfer} function will run before changing the owner of `tokenId`.
*
* @param from The sender address.
* @param to The recipient address.
* @param tokenId The token to transfer.
* @param allowNonLSP1Recipient When set to `true`, `to` may be any address. When set to `false`, `to` must be a contract that supports the LSP1 standard.
* @param data Additional data the caller wants included in the emitted event, and sent in the hooks to `from` and `to` addresses.
*
* @custom:requirements
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* @custom:events {Transfer} event.
*
* @custom:danger This internal function does not check if the sender is authorized or not to operate on the `tokenId`.
*/
function _transfer(
address from,
address to,
bytes32 tokenId,
bool allowNonLSP1Recipient,
bytes memory data
) internal virtual {
if (from == to) {
revert LSP8CannotSendToSelf();
}
address tokenOwner = tokenOwnerOf(tokenId);
if (tokenOwner != from) {
revert LSP8NotTokenOwner(tokenOwner, tokenId, from);
}
if (to == address(0)) {
revert LSP8CannotSendToAddressZero();
}
address operator = msg.sender;
_beforeTokenTransfer(from, to, tokenId);
_clearOperators(from, tokenId);
_ownedTokens[from].remove(tokenId);
_ownedTokens[to].add(tokenId);
_tokenOwners[tokenId] = to;
emit Transfer(operator, from, to, tokenId, allowNonLSP1Recipient, data);
bytes memory lsp1Data = abi.encode(from, to, tokenId, data);
_notifyTokenSender(from, lsp1Data);
_notifyTokenReceiver(to, allowNonLSP1Recipient, lsp1Data);
}
/**
* @dev Hook that is called before any token transfer, including minting and burning.
* * Allows to run custom logic before updating balances and notifiying sender/recipient by overriding this function.
*
* @param from The sender address
* @param to The recipient address
* @param tokenId The tokenId to transfer
*/
function _beforeTokenTransfer(
address from,
address to,
bytes32 tokenId
) internal virtual {}
/**
* @dev Attempt to notify the operator `operator` about the `tokenId` tokens being authorized.
* This is done by calling its {universalReceiver} function with the `_TYPEID_LSP8_TOKENOPERATOR` as typeId, if `operator` is a contract that supports the LSP1 interface.
* If `operator` is an EOA or a contract that does not support the LSP1 interface, nothing will happen and no notification will be sent.
* @param operator The address to call the {universalReceiver} function on.
* @param lsp1Data the data to be sent to the `operator` address in the `universalReceiver` call.
*/
function _notifyTokenOperator(
address operator,
bytes memory lsp1Data
) internal virtual {
if (
ERC165Checker.supportsERC165InterfaceUnchecked(
operator,
_INTERFACEID_LSP1
)
) {
operator.call(
abi.encodeWithSelector(
ILSP1UniversalReceiver.universalReceiver.selector,
_TYPEID_LSP8_TOKENOPERATOR,
lsp1Data
)
);
}
}
/**
* @dev An attempt is made to notify the token sender about the `tokenId` changing owners using
* LSP1 interface.
*/
function _notifyTokenSender(
address from,
bytes memory lsp1Data
) internal virtual {
if (
ERC165Checker.supportsERC165InterfaceUnchecked(
from,
_INTERFACEID_LSP1
)
) {
ILSP1UniversalReceiver(from).universalReceiver(
_TYPEID_LSP8_TOKENSSENDER,
lsp1Data
);
}
}
/**
* @dev An attempt is made to notify the token receiver about the `tokenId` changing owners
* using LSP1 interface. When allowNonLSP1Recipient is FALSE the token receiver MUST support LSP1.
*
* The receiver may revert when the token being sent is not wanted.
*/
function _notifyTokenReceiver(
address to,
bool allowNonLSP1Recipient,
bytes memory lsp1Data
) internal virtual {
if (
ERC165Checker.supportsERC165InterfaceUnchecked(
to,
_INTERFACEID_LSP1
)
) {
ILSP1UniversalReceiver(to).universalReceiver(
_TYPEID_LSP8_TOKENSRECIPIENT,
lsp1Data
);
} else if (!allowNonLSP1Recipient) {
if (to.code.length > 0) {
revert LSP8NotifyTokenReceiverContractMissingLSP1Interface(to);
} else {
revert LSP8NotifyTokenReceiverIsEOA(to);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface.
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
!supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
}
/**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*/
function getSupportedInterfaces(
address account,
bytes4[] memory interfaceIds
) internal view returns (bool[] memory) {
// an array of booleans corresponding to interfaceIds and whether they're supported or not
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
// query support of ERC165 itself
if (supportsERC165(account)) {
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
*
* Batch-querying can lead to gas savings by skipping repeated checks for
* {IERC165} support.
*
* See {IERC165-supportsInterface}.
*/
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
// query support of ERC165 itself
if (!supportsERC165(account)) {
return false;
}
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
return false;
}
}
// all interfaces supported
return true;
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
*
* Some precompiled contracts will falsely indicate support for a given interface, so caution
* should be exercised when using this function.
*
* Interface identification is specified in ERC-165.
*/
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @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.
*
* ```solidity
* 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.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
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 is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @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._positions[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 cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 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 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[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._positions[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) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// 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);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// 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))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// 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 in 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));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
{
"evmVersion": "paris",
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"address","name":"newOwner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ERC725Y_DataKeysValuesEmptyArray","type":"error"},{"inputs":[],"name":"ERC725Y_DataKeysValuesLengthMismatch","type":"error"},{"inputs":[],"name":"ERC725Y_MsgValueDisallowed","type":"error"},{"inputs":[{"internalType":"bytes","name":"storedData","type":"bytes"}],"name":"InvalidExtensionAddress","type":"error"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"InvalidFunctionSelector","type":"error"},{"inputs":[],"name":"LSP4TokenNameNotEditable","type":"error"},{"inputs":[],"name":"LSP4TokenSymbolNotEditable","type":"error"},{"inputs":[],"name":"LSP8CannotSendToAddressZero","type":"error"},{"inputs":[],"name":"LSP8CannotSendToSelf","type":"error"},{"inputs":[],"name":"LSP8CannotUseAddressZeroAsOperator","type":"error"},{"inputs":[],"name":"LSP8InvalidTransferBatch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"LSP8NonExistentTokenId","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"LSP8NonExistingOperator","type":"error"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"internalType":"address","name":"caller","type":"address"}],"name":"LSP8NotTokenOperator","type":"error"},{"inputs":[{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"internalType":"address","name":"caller","type":"address"}],"name":"LSP8NotTokenOwner","type":"error"},{"inputs":[{"internalType":"address","name":"tokenReceiver","type":"address"}],"name":"LSP8NotifyTokenReceiverContractMissingLSP1Interface","type":"error"},{"inputs":[{"internalType":"address","name":"tokenReceiver","type":"address"}],"name":"LSP8NotifyTokenReceiverIsEOA","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"LSP8OperatorAlreadyAuthorized","type":"error"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"LSP8TokenIdAlreadyMinted","type":"error"},{"inputs":[],"name":"LSP8TokenOwnerCannotBeOperator","type":"error"},{"inputs":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"}],"name":"NoExtensionFoundForFunctionSelector","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOwner","type":"address"},{"indexed":true,"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"operatorNotificationData","type":"bytes"}],"name":"AuthorizedOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"dataKey","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"dataValue","type":"bytes"}],"name":"DataChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOwner","type":"address"},{"indexed":true,"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"operatorNotificationData","type":"bytes"}],"name":"RevokedOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"allowNonLSP1Recipient","type":"bool"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"Transfer","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"internalType":"bytes","name":"operatorNotificationData","type":"bytes"}],"name":"authorizeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOwner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"changeFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"string[]","name":"_cid","type":"string[]"},{"internalType":"bytes32[]","name":"tokenId","type":"bytes32[]"}],"name":"createBatchPosts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"string","name":"_cid","type":"string"},{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"createPost","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"feeSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataKey","type":"bytes32"}],"name":"getData","outputs":[{"internalType":"bytes","name":"dataValue","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"dataKeys","type":"bytes32[]"}],"name":"getDataBatch","outputs":[{"internalType":"bytes[]","name":"dataValues","type":"bytes[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"getOperatorsOf","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getPostAuthor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getPostCid","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getPostOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"isOperatorFor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"postByTokenId","outputs":[{"internalType":"string","name":"cid","type":"string"},{"internalType":"address","name":"author","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"internalType":"bytes","name":"operatorNotificationData","type":"bytes"}],"name":"revokeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataKey","type":"bytes32"},{"internalType":"bytes","name":"dataValue","type":"bytes"}],"name":"setData","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"dataKeys","type":"bytes32[]"},{"internalType":"bytes[]","name":"dataValues","type":"bytes[]"}],"name":"setDataBatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeSetter","type":"address"}],"name":"setFeeSetter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOwner","type":"address"}],"name":"tokenIdsOf","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tokenId","type":"bytes32"}],"name":"tokenOwnerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes32","name":"tokenId","type":"bytes32"},{"internalType":"bool","name":"allowNonLSP1Recipient","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"from","type":"address[]"},{"internalType":"address[]","name":"to","type":"address[]"},{"internalType":"bytes32[]","name":"tokenId","type":"bytes32[]"},{"internalType":"bool[]","name":"allowNonLSP1Recipient","type":"bool[]"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"transferBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b5060405162005da038038062005da0833981810160405281019062000037919062000570565b82828282828280600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000b0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620000a79062000691565b60405180910390fd5b620000c181620001e660201b60201c565b506200012c7feafec4d89fa9619884b60000a4d96624a38f7ac2d8d9a604ecf07c12c77e480c60001b6040518060400160405280600481526020017fa4d9662400000000000000000000000000000000000000000000000000000000815250620002ee60201b60201c565b620001617fdeba1e292f8ba88238e10ab3c7f88bd4be4fac56cad5194b6ecceaf653468af160001b84620002ee60201b60201c565b620001967f2f0a68ab07768e01943a599e73362a0e17a63a72e94dd2e384d2c1d4db93275660001b83620002ee60201b60201c565b50505050505080600760016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505062000a5b565b620001f66200034f60201b60201c565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614620002eb5760008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3505b50565b80600160008481526020019081526020016000209081620003109190620008fe565b50817fece574603820d07bc9b91f2a932baadf4628aabcb8afba49776529c14a6104b28260405162000343919062000a37565b60405180910390a25050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620003e18262000396565b810181811067ffffffffffffffff82111715620004035762000402620003a7565b5b80604052505050565b60006200041862000378565b9050620004268282620003d6565b919050565b600067ffffffffffffffff821115620004495762000448620003a7565b5b620004548262000396565b9050602081019050919050565b60005b838110156200048157808201518184015260208101905062000464565b60008484015250505050565b6000620004a46200049e846200042b565b6200040c565b905082815260208101848484011115620004c357620004c262000391565b5b620004d084828562000461565b509392505050565b600082601f830112620004f057620004ef6200038c565b5b8151620005028482602086016200048d565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600062000538826200050b565b9050919050565b6200054a816200052b565b81146200055657600080fd5b50565b6000815190506200056a816200053f565b92915050565b6000806000606084860312156200058c576200058b62000382565b5b600084015167ffffffffffffffff811115620005ad57620005ac62000387565b5b620005bb86828701620004d8565b935050602084015167ffffffffffffffff811115620005df57620005de62000387565b5b620005ed86828701620004d8565b9250506040620006008682870162000559565b9150509250925092565b600082825260208201905092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000620006796026836200060a565b915062000686826200061b565b604082019050919050565b60006020820190508181036000830152620006ac816200066a565b9050919050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200070657607f821691505b6020821081036200071c576200071b620006be565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620007867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000747565b62000792868362000747565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620007df620007d9620007d384620007aa565b620007b4565b620007aa565b9050919050565b6000819050919050565b620007fb83620007be565b620008136200080a82620007e6565b84845462000754565b825550505050565b600090565b6200082a6200081b565b62000837818484620007f0565b505050565b5b818110156200085f576200085360008262000820565b6001810190506200083d565b5050565b601f821115620008ae57620008788162000722565b620008838462000737565b8101602085101562000893578190505b620008ab620008a28562000737565b8301826200083c565b50505b505050565b600082821c905092915050565b6000620008d360001984600802620008b3565b1980831691505092915050565b6000620008ee8383620008c0565b9150826002028217905092915050565b6200090982620006b3565b67ffffffffffffffff811115620009255762000924620003a7565b5b620009318254620006ed565b6200093e82828562000863565b600060209050601f83116001811462000976576000841562000961578287015190505b6200096d8582620008e0565b865550620009dd565b601f198416620009868662000722565b60005b82811015620009b05784890151825560018201915060208501945060208101905062000989565b86831015620009d05784890151620009cc601f891682620008c0565b8355505b6001600288020188555050505b505050505050565b600082825260208201905092915050565b600062000a0382620006b3565b62000a0f8185620009e5565b935062000a2181856020860162000461565b62000a2c8162000396565b840191505092915050565b6000602082019050818103600083015262000a538184620009f6565b905092915050565b6153358062000a6b6000396000f3fe6080604052600436106101d15760003560e01c8063715018a6116100f75780639790242111610095578063b92223c311610064578063b92223c314610715578063dedff9c614610731578063f1b97e041461076e578063f2fde38b14610797576101d8565b80639790242114610656578063a3b261f214610672578063a56581df146106af578063b19805af146106ec576101d8565b806386a10ddd116100d157806386a10ddd146105ae57806387cf3ef4146105d75780638da5cb5b1461060257806395b9945b1461062d576101d8565b8063715018a6146105525780637e87632c146105695780637f23690c14610592576101d8565b8063476343ee1161016f5780635a64ad951161013e5780635a64ad95146104965780636a1db1bf146104c15780636f9fb98a146104ea57806370a0823114610515576101d8565b8063476343ee146103dc57806349a6078d146103f3578063511b69521461043057806354f6127f14610459576101d8565b806318160ddd116101ab57806318160ddd146102fa578063217b2270146103255780632a3654a41461036257806345c146711461039f576101d8565b806301ffc9a714610240578063085f441f1461027d57806316ebbe04146102ba576101d8565b366101d857005b60003660606004600036905010156102295782826040517fe5099ee3000000000000000000000000000000000000000000000000000000008152600401610220929190613176565b60405180910390fd5b61023383836107c0565b9050915050805190602001f35b34801561024c57600080fd5b5061026760048036038101906102629190613206565b61093d565b604051610274919061324e565b60405180910390f35b34801561028957600080fd5b506102a4600480360381019061029f919061329f565b6109ae565b6040516102b1919061330d565b60405180910390f35b3480156102c657600080fd5b506102e160048036038101906102dc919061329f565b6109d6565b6040516102f194939291906133cf565b60405180910390f35b34801561030657600080fd5b5061030f610aae565b60405161031c919061341b565b60405180910390f35b34801561033157600080fd5b5061034c60048036038101906103479190613462565b610ab8565b604051610359919061330d565b60405180910390f35b34801561036e57600080fd5b50610389600480360381019061038491906134bb565b610b6b565b604051610396919061324e565b60405180910390f35b3480156103ab57600080fd5b506103c660048036038101906103c1919061329f565b610b88565b6040516103d3919061330d565b60405180910390f35b3480156103e857600080fd5b506103f1610bc8565b005b3480156103ff57600080fd5b5061041a60048036038101906104159190613462565b610d2f565b60405161042791906135b9565b60405180910390f35b34801561043c57600080fd5b506104576004803603810190610452919061372d565b610d5c565b005b34801561046557600080fd5b50610480600480360381019061047b9190613462565b610dc3565b60405161048d9190613808565b60405180910390f35b3480156104a257600080fd5b506104ab610dd5565b6040516104b8919061341b565b60405180910390f35b3480156104cd57600080fd5b506104e860048036038101906104e3919061329f565b610ddb565b005b3480156104f657600080fd5b506104ff610e75565b60405161050c919061341b565b60405180910390f35b34801561052157600080fd5b5061053c6004803603810190610537919061382a565b610e7d565b604051610549919061341b565b60405180910390f35b34801561055e57600080fd5b50610567610ecd565b005b34801561057557600080fd5b50610590600480360381019061058b9190613b86565b610ee1565b005b6105ac60048036038101906105a79190613c8d565b610ff5565b005b3480156105ba57600080fd5b506105d560048036038101906105d09190613ce9565b611045565b005b3480156105e357600080fd5b506105ec61129d565b6040516105f9919061330d565b60405180910390f35b34801561060e57600080fd5b506106176112c3565b604051610624919061330d565b60405180910390f35b34801561063957600080fd5b50610654600480360381019061064f9190613eda565b6112ec565b005b610670600480360381019061066b9190613f65565b61134d565b005b34801561067e57600080fd5b506106996004803603810190610694919061382a565b61145f565b6040516106a6919061409b565b60405180910390f35b3480156106bb57600080fd5b506106d660048036038101906106d1919061329f565b6114af565b6040516106e391906140bd565b60405180910390f35b3480156106f857600080fd5b50610713600480360381019061070e919061382a565b611557565b005b61072f600480360381019061072a91906140df565b61162b565b005b34801561073d57600080fd5b506107586004803603810190610753919061414e565b611840565b60405161076591906142a3565b60405180910390f35b34801561077a57600080fd5b5061079560048036038101906107909190613ce9565b6118f1565b005b3480156107a357600080fd5b506107be60048036038101906107b9919061382a565b611a82565b005b606060006107f16000357fffffffff0000000000000000000000000000000000000000000000000000000016611b05565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610888576000357fffffffff00000000000000000000000000000000000000000000000000000000166040517fbb370b2b00000000000000000000000000000000000000000000000000000000815260040161087f91906142d4565b60405180910390fd5b6000808273ffffffffffffffffffffffffffffffffffffffff1634878733346040516020016108ba9493929190614388565b6040516020818303038152906040526040516108d691906143f4565b60006040518083038185875af1925050503d8060008114610913576040519150601f19603f3d011682016040523d82523d6000602084013e610918565b606091505b5091509150811561092e57809350505050610937565b80518060208301fd5b92915050565b6000631ae9ba1f60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610997575061099682611bb9565b5b806109a757506109a682611c1a565b5b9050919050565b60006109cf600e600084815260200190815260200160002060030154610ab8565b9050919050565b600e6020528060005260406000206000915090508060000180546109f99061443a565b80601f0160208091040260200160405190810160405280929190818152602001828054610a259061443a565b8015610a725780601f10610a4757610100808354040283529160200191610a72565b820191906000526020600020905b815481529060010190602001808311610a5557829003601f168201915b5050505050908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020154908060030154905084565b6000600254905090565b6000806003600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610b6257826040517fae8f9a36000000000000000000000000000000000000000000000000000000008152600401610b59919061446b565b60405180910390fd5b80915050919050565b6000610b7682611c80565b610b808383611ccd565b905092915050565b6000600e600083815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b600760019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c58576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c4f906144d2565b60405180910390fd5b60004790506000600760019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1682604051610ca590614518565b60006040518083038185875af1925050503d8060008114610ce2576040519150601f19603f3d011682016040523d82523d6000602084013e610ce7565b606091505b5050905080610d2b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d2290614579565b60405180910390fd5b5050565b6060610d3a82611c80565b610d5560056000848152602001908152602001600020611d3f565b9050919050565b6000339050610d6b8185611ccd565b610dae5783816040517f1294d2a9000000000000000000000000000000000000000000000000000000008152600401610da5929190614599565b60405180910390fd5b610dbb8686868686611d60565b505050505050565b6060610dce8261206f565b9050919050565b60085481565b600760019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610e6b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e629061460e565b60405180910390fd5b8060088190555050565b600047905090565b6000610ec6600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612114565b9050919050565b610ed5612129565b610edf60006121a0565b565b600085519050845181141580610ef8575083518114155b80610f04575082518114155b80610f10575081518114155b15610f47576040517f93a8311900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610fec57610fe1878281518110610f6857610f6761462e565b5b6020026020010151878381518110610f8357610f8261462e565b5b6020026020010151878481518110610f9e57610f9d61462e565b5b6020026020010151878581518110610fb957610fb861462e565b5b6020026020010151878681518110610fd457610fd361462e565b5b6020026020010151610d5c565b806001019050610f4a565b50505050505050565b610ffd612129565b60003414611037576040517ff36ba73700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611041828261229f565b5050565b600061105083610ab8565b90503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146110c6578083336040517f5b271ea20000000000000000000000000000000000000000000000000000000081526004016110bd9392919061465d565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361112c576040517f9577b8b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611191576040517f89fdad6200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006111b885600560008781526020019081526020016000206123d390919063ffffffff16565b9050806111fe5784846040517fa7626b680000000000000000000000000000000000000000000000000000000081526004016111f5929190614694565b60405180910390fd5b838273ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167e52e433f2d4225671bc164dd1cdc9a76044356091f27ad234798bd0cbf083498660405161125b9190613808565b60405180910390a4600033858560405160200161127a939291906146bd565b60405160208183030381529060405290506112958682612403565b505050505050565b600760019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008151905060005b8181146113465761133b858583815181106113135761131261462e565b5b602002602001015185848151811061132e5761132d61462e565b5b602002602001015161162b565b8060010190506112f5565b5050505050565b611355612129565b6000341461138f576040517ff36ba73700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80518251146113ca576040517f3bcc897900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000825103611405576040517f97da5f9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b825181101561145a5761144f8382815181106114275761142661462e565b5b60200260200101518383815181106114425761144161462e565b5b602002602001015161229f565b806001019050611408565b505050565b60606114a8600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612522565b9050919050565b6060600e600083815260200190815260200160002060000180546114d29061443a565b80601f01602080910402602001604051908101604052809291908181526020018280546114fe9061443a565b801561154b5780601f106115205761010080835404028352916020019161154b565b820191906000526020600020905b81548152906001019060200180831161152e57829003601f168201915b50505050509050919050565b600760019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146115e7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115de9061460e565b60405180910390fd5b80600760016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600760009054906101000a900460ff161561167b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161167290614747565b60405180910390fd5b6001600760006101000a81548160ff0219169083151502179055506008543410156116db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116d2906147b3565b60405180910390fd5b81600960000190816116ed919061497f565b5033600960010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600d6000815461174190614a80565b919050819055600960020181905550806009600301819055506009600e6000600d548152602001908152602001600020600082018160000190816117859190614ade565b506001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060028201548160020155600382015481600301559050506118208382600160405180602001604052806000815250612543565b6000600760006101000a81548160ff021916908315150217905550505050565b6060815167ffffffffffffffff81111561185d5761185c613611565b5b60405190808252806020026020018201604052801561189057816020015b606081526020019060019003908161187b5790505b50905060005b82518110156118eb576118c28382815181106118b5576118b461462e565b5b602002602001015161206f565b8282815181106118d5576118d461462e565b5b6020026020010181905250806001019050611896565b50919050565b60006118fc83610ab8565b90503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611972578083336040517f5b271ea20000000000000000000000000000000000000000000000000000000081526004016119699392919061465d565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036119d8576040517f9577b8b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611a3d576040517f89fdad6200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a498482858561276b565b6000338484604051602001611a60939291906146bd565b6040516020818303038152906040529050611a7b8582612403565b5050505050565b611a8a612129565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611af9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611af090614c38565b60405180910390fd5b611b02816121a0565b50565b600080611b3e69cee78b4094da8601109660b01b847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916612845565b90506000611b4b8261206f565b90506014815114158015611b6157506000815114155b15611ba357806040517f42bfe79f000000000000000000000000000000000000000000000000000000008152600401611b9a9190613808565b60405180910390fd5b80611bad90614ca9565b60601c92505050919050565b600063a918fa6b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611c135750611c1282612885565b5b9050919050565b600080611c2d6301ffc9a760e01b611b05565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611c6d576000915050611c7b565b611c7781846128e6565b9150505b919050565b611c8981612985565b611cca57806040517fae8f9a36000000000000000000000000000000000000000000000000000000008152600401611cc1919061446b565b60405180910390fd5b50565b600080611cd983610ab8565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480611d365750611d3584600560008681526020019081526020016000206129f190919063ffffffff16565b5b91505092915050565b60606000611d4f83600001612a21565b905060608190508092505050919050565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611dc5576040517f5d67d6c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611dd084610ab8565b90508573ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611e46578084876040517f5b271ea2000000000000000000000000000000000000000000000000000000008152600401611e3d9392919061465d565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611eac576040517f24ecef4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000339050611ebc878787612a7d565b611ec68786612a82565b611f1785600460008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612af790919063ffffffff16565b50611f6985600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612b0e90919063ffffffff16565b50856003600087815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550848673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf84888860405161201e93929190614d10565b60405180910390a460008787878660405160200161203f9493929190614d4e565b604051602081830303815290604052905061205a8882612b25565b612065878683612be7565b5050505050505050565b606060016000838152602001908152602001600020805461208f9061443a565b80601f01602080910402602001604051908101604052809291908181526020018280546120bb9061443a565b80156121085780601f106120dd57610100808354040283529160200191612108565b820191906000526020600020905b8154815290600101906020018083116120eb57829003601f168201915b50505050509050919050565b600061212282600001612d4e565b9050919050565b3373ffffffffffffffffffffffffffffffffffffffff166121486112c3565b73ffffffffffffffffffffffffffffffffffffffff161461219e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161219590614de6565b60405180910390fd5b565b6121a86112c3565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461229c5760008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3505b50565b7fdeba1e292f8ba88238e10ab3c7f88bd4be4fac56cad5194b6ecceaf653468af160001b82036122fb576040517f85c169bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2f0a68ab07768e01943a599e73362a0e17a63a72e94dd2e384d2c1d4db93275660001b8203612357576040517f76755b3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600084815260200190815260200160002090816123779190614e61565b50817fece574603820d07bc9b91f2a932baadf4628aabcb8afba49776529c14a6104b2610100835111156123b8576123b3836000610100612d5f565b6123ba565b825b6040516123c79190613808565b60405180910390a25050565b60006123fb836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612e7d565b905092915050565b61241482636bb56a1460e01b6128e6565b1561251e578173ffffffffffffffffffffffffffffffffffffffff16636bb56a1460e01b7f8a1c15a8799f71b547e08e2bcb2e85257e81b0a07eee2ce6712549eef1f0097060001b8360405160240161246e929190614f33565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516124d891906143f4565b6000604051808303816000865af19150503d8060008114612515576040519150601f19603f3d011682016040523d82523d6000602084013e61251a565b606091505b5050505b5050565b6060600061253283600001612a21565b905060608190508092505050919050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036125a9576040517f24ecef4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125b283612985565b156125f457826040517f34c7b5110000000000000000000000000000000000000000000000000000000081526004016125eb919061446b565b60405180910390fd5b600033905061260560008686612a7d565b6001600260008282546126189190614f63565b9250508190555061267084600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612b0e90919063ffffffff16565b50846003600086815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838573ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf84878760405161272693929190614d10565b60405180910390a46000808686856040516020016127479493929190614d4e565b6040516020818303038152906040529050612763868583612be7565b505050505050565b60006127928560056000868152602001908152602001600020612eed90919063ffffffff16565b9050806127d85784836040517f4aa31a8c0000000000000000000000000000000000000000000000000000000081526004016127cf929190614694565b60405180910390fd5b828473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f501bc920d7f604417e315bcf29247652b2327fa1076b27b7f132bd8927cb15ea856040516128369190613808565b60405180910390a45050505050565b60008083600060f01b8460405160200161286193929190615052565b60405160208183030381529060405290508061287c906150a4565b91505092915050565b600063629aa69460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806128df57506128de82612f1d565b5b9050919050565b600080826040516024016128fa91906142d4565b6040516020818303038152906040526301ffc9a760e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000806000602060008551602087018a617530fa92503d9150600051905082801561296d575060208210155b80156129795750600081115b94505050505092915050565b60008073ffffffffffffffffffffffffffffffffffffffff166003600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614159050919050565b6000612a19836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612f87565b905092915050565b606081600001805480602002602001604051908101604052809291908181526020018280548015612a7157602002820191906000526020600020905b815481526020019060010190808311612a5d575b50505050509050919050565b505050565b60006005600083815260200190815260200160002090506000612aa482612faa565b905060005b81811015612af0576000612ac7600085612fbf90919063ffffffff16565b9050612ae48187876040518060200160405280600081525061276b565b81600101915050612aa9565b5050505050565b6000612b068360000183612fd9565b905092915050565b6000612b1d8360000183612e7d565b905092915050565b612b3682636bb56a1460e01b6128e6565b15612be3578173ffffffffffffffffffffffffffffffffffffffff16636bb56a147fb23eae7e6d1564b295b4c3e3be402d9a2f0776c57bdf365903496f6fa481ab0060001b836040518363ffffffff1660e01b8152600401612b99929190614f33565b6000604051808303816000875af1158015612bb8573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190612be1919061517b565b505b5050565b612bf883636bb56a1460e01b6128e6565b15612ca9578273ffffffffffffffffffffffffffffffffffffffff16636bb56a147f0b084a55ebf70fd3c06fd755269dac2212c4d3f0f4d09079780bfa50c1b2984d60001b836040518363ffffffff1660e01b8152600401612c5b929190614f33565b6000604051808303816000875af1158015612c7a573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190612ca3919061517b565b50612d49565b81612d485760008373ffffffffffffffffffffffffffffffffffffffff163b1115612d0b57826040517f4349776d000000000000000000000000000000000000000000000000000000008152600401612d02919061330d565b60405180910390fd5b826040517f03173137000000000000000000000000000000000000000000000000000000008152600401612d3f919061330d565b60405180910390fd5b5b505050565b600081600001805490509050919050565b606081601f83612d6f9190614f63565b1015612db0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612da790615210565b60405180910390fd5b8183612dbc9190614f63565b84511015612dff576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612df69061527c565b60405180910390fd5b6060821560008114612e205760405191506000825260208201604052612e71565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015612e5e5780518352602083019250602081019050612e41565b50868552601f19601f8301166040525050505b50809150509392505050565b6000612e898383612f87565b612ee2578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050612ee7565b600090505b92915050565b6000612f15836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612fd9565b905092915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b600080836001016000848152602001908152602001600020541415905092915050565b6000612fb882600001612d4e565b9050919050565b6000612fce83600001836130ed565b60001c905092915050565b600080836001016000848152602001908152602001600020549050600081146130e157600060018261300b919061529c565b9050600060018660000180549050613023919061529c565b90508082146130925760008660000182815481106130445761304361462e565b5b90600052602060002001549050808760000184815481106130685761306761462e565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b856000018054806130a6576130a56152d0565b5b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506130e7565b60009150505b92915050565b60008260000182815481106131055761310461462e565b5b9060005260206000200154905092915050565b600082825260208201905092915050565b82818337600083830152505050565b6000601f19601f8301169050919050565b60006131558385613118565b9350613162838584613129565b61316b83613138565b840190509392505050565b60006020820190508181036000830152613191818486613149565b90509392505050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6131e3816131ae565b81146131ee57600080fd5b50565b600081359050613200816131da565b92915050565b60006020828403121561321c5761321b6131a4565b5b600061322a848285016131f1565b91505092915050565b60008115159050919050565b61324881613233565b82525050565b6000602082019050613263600083018461323f565b92915050565b6000819050919050565b61327c81613269565b811461328757600080fd5b50565b60008135905061329981613273565b92915050565b6000602082840312156132b5576132b46131a4565b5b60006132c38482850161328a565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006132f7826132cc565b9050919050565b613307816132ec565b82525050565b600060208201905061332260008301846132fe565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613362578082015181840152602081019050613347565b60008484015250505050565b600061337982613328565b6133838185613333565b9350613393818560208601613344565b61339c81613138565b840191505092915050565b6133b081613269565b82525050565b6000819050919050565b6133c9816133b6565b82525050565b600060808201905081810360008301526133e9818761336e565b90506133f860208301866132fe565b61340560408301856133a7565b61341260608301846133c0565b95945050505050565b600060208201905061343060008301846133a7565b92915050565b61343f816133b6565b811461344a57600080fd5b50565b60008135905061345c81613436565b92915050565b600060208284031215613478576134776131a4565b5b60006134868482850161344d565b91505092915050565b613498816132ec565b81146134a357600080fd5b50565b6000813590506134b58161348f565b92915050565b600080604083850312156134d2576134d16131a4565b5b60006134e0858286016134a6565b92505060206134f18582860161344d565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b613530816132ec565b82525050565b60006135428383613527565b60208301905092915050565b6000602082019050919050565b6000613566826134fb565b6135708185613506565b935061357b83613517565b8060005b838110156135ac5781516135938882613536565b975061359e8361354e565b92505060018101905061357f565b5085935050505092915050565b600060208201905081810360008301526135d3818461355b565b905092915050565b6135e481613233565b81146135ef57600080fd5b50565b600081359050613601816135db565b92915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61364982613138565b810181811067ffffffffffffffff8211171561366857613667613611565b5b80604052505050565b600061367b61319a565b90506136878282613640565b919050565b600067ffffffffffffffff8211156136a7576136a6613611565b5b6136b082613138565b9050602081019050919050565b60006136d06136cb8461368c565b613671565b9050828152602081018484840111156136ec576136eb61360c565b5b6136f7848285613129565b509392505050565b600082601f83011261371457613713613607565b5b81356137248482602086016136bd565b91505092915050565b600080600080600060a08688031215613749576137486131a4565b5b6000613757888289016134a6565b9550506020613768888289016134a6565b94505060406137798882890161344d565b935050606061378a888289016135f2565b925050608086013567ffffffffffffffff8111156137ab576137aa6131a9565b5b6137b7888289016136ff565b9150509295509295909350565b600081519050919050565b60006137da826137c4565b6137e48185613118565b93506137f4818560208601613344565b6137fd81613138565b840191505092915050565b6000602082019050818103600083015261382281846137cf565b905092915050565b6000602082840312156138405761383f6131a4565b5b600061384e848285016134a6565b91505092915050565b600067ffffffffffffffff82111561387257613871613611565b5b602082029050602081019050919050565b600080fd5b600061389b61389684613857565b613671565b905080838252602082019050602084028301858111156138be576138bd613883565b5b835b818110156138e757806138d388826134a6565b8452602084019350506020810190506138c0565b5050509392505050565b600082601f83011261390657613905613607565b5b8135613916848260208601613888565b91505092915050565b600067ffffffffffffffff82111561393a57613939613611565b5b602082029050602081019050919050565b600061395e6139598461391f565b613671565b9050808382526020820190506020840283018581111561398157613980613883565b5b835b818110156139aa5780613996888261344d565b845260208401935050602081019050613983565b5050509392505050565b600082601f8301126139c9576139c8613607565b5b81356139d984826020860161394b565b91505092915050565b600067ffffffffffffffff8211156139fd576139fc613611565b5b602082029050602081019050919050565b6000613a21613a1c846139e2565b613671565b90508083825260208201905060208402830185811115613a4457613a43613883565b5b835b81811015613a6d5780613a5988826135f2565b845260208401935050602081019050613a46565b5050509392505050565b600082601f830112613a8c57613a8b613607565b5b8135613a9c848260208601613a0e565b91505092915050565b600067ffffffffffffffff821115613ac057613abf613611565b5b602082029050602081019050919050565b6000613ae4613adf84613aa5565b613671565b90508083825260208201905060208402830185811115613b0757613b06613883565b5b835b81811015613b4e57803567ffffffffffffffff811115613b2c57613b2b613607565b5b808601613b3989826136ff565b85526020850194505050602081019050613b09565b5050509392505050565b600082601f830112613b6d57613b6c613607565b5b8135613b7d848260208601613ad1565b91505092915050565b600080600080600060a08688031215613ba257613ba16131a4565b5b600086013567ffffffffffffffff811115613bc057613bbf6131a9565b5b613bcc888289016138f1565b955050602086013567ffffffffffffffff811115613bed57613bec6131a9565b5b613bf9888289016138f1565b945050604086013567ffffffffffffffff811115613c1a57613c196131a9565b5b613c26888289016139b4565b935050606086013567ffffffffffffffff811115613c4757613c466131a9565b5b613c5388828901613a77565b925050608086013567ffffffffffffffff811115613c7457613c736131a9565b5b613c8088828901613b58565b9150509295509295909350565b60008060408385031215613ca457613ca36131a4565b5b6000613cb28582860161344d565b925050602083013567ffffffffffffffff811115613cd357613cd26131a9565b5b613cdf858286016136ff565b9150509250929050565b600080600060608486031215613d0257613d016131a4565b5b6000613d10868287016134a6565b9350506020613d218682870161344d565b925050604084013567ffffffffffffffff811115613d4257613d416131a9565b5b613d4e868287016136ff565b9150509250925092565b600067ffffffffffffffff821115613d7357613d72613611565b5b602082029050602081019050919050565b600067ffffffffffffffff821115613d9f57613d9e613611565b5b613da882613138565b9050602081019050919050565b6000613dc8613dc384613d84565b613671565b905082815260208101848484011115613de457613de361360c565b5b613def848285613129565b509392505050565b600082601f830112613e0c57613e0b613607565b5b8135613e1c848260208601613db5565b91505092915050565b6000613e38613e3384613d58565b613671565b90508083825260208201905060208402830185811115613e5b57613e5a613883565b5b835b81811015613ea257803567ffffffffffffffff811115613e8057613e7f613607565b5b808601613e8d8982613df7565b85526020850194505050602081019050613e5d565b5050509392505050565b600082601f830112613ec157613ec0613607565b5b8135613ed1848260208601613e25565b91505092915050565b600080600060608486031215613ef357613ef26131a4565b5b6000613f01868287016134a6565b935050602084013567ffffffffffffffff811115613f2257613f216131a9565b5b613f2e86828701613eac565b925050604084013567ffffffffffffffff811115613f4f57613f4e6131a9565b5b613f5b868287016139b4565b9150509250925092565b60008060408385031215613f7c57613f7b6131a4565b5b600083013567ffffffffffffffff811115613f9a57613f996131a9565b5b613fa6858286016139b4565b925050602083013567ffffffffffffffff811115613fc757613fc66131a9565b5b613fd385828601613b58565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b614012816133b6565b82525050565b60006140248383614009565b60208301905092915050565b6000602082019050919050565b600061404882613fdd565b6140528185613fe8565b935061405d83613ff9565b8060005b8381101561408e5781516140758882614018565b975061408083614030565b925050600181019050614061565b5085935050505092915050565b600060208201905081810360008301526140b5818461403d565b905092915050565b600060208201905081810360008301526140d7818461336e565b905092915050565b6000806000606084860312156140f8576140f76131a4565b5b6000614106868287016134a6565b935050602084013567ffffffffffffffff811115614127576141266131a9565b5b61413386828701613df7565b92505060406141448682870161344d565b9150509250925092565b600060208284031215614164576141636131a4565b5b600082013567ffffffffffffffff811115614182576141816131a9565b5b61418e848285016139b4565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600082825260208201905092915050565b60006141df826137c4565b6141e981856141c3565b93506141f9818560208601613344565b61420281613138565b840191505092915050565b600061421983836141d4565b905092915050565b6000602082019050919050565b600061423982614197565b61424381856141a2565b935083602082028501614255856141b3565b8060005b858110156142915784840389528151614272858261420d565b945061427d83614221565b925060208a01995050600181019050614259565b50829750879550505050505092915050565b600060208201905081810360008301526142bd818461422e565b905092915050565b6142ce816131ae565b82525050565b60006020820190506142e960008301846142c5565b92915050565b600081905092915050565b600061430683856142ef565b9350614313838584613129565b82840190509392505050565b60008160601b9050919050565b60006143378261431f565b9050919050565b60006143498261432c565b9050919050565b61436161435c826132ec565b61433e565b82525050565b6000819050919050565b61438261437d82613269565b614367565b82525050565b60006143958286886142fa565b91506143a18285614350565b6014820191506143b18284614371565b60208201915081905095945050505050565b60006143ce826137c4565b6143d881856142ef565b93506143e8818560208601613344565b80840191505092915050565b600061440082846143c3565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061445257607f821691505b6020821081036144655761446461440b565b5b50919050565b600060208201905061448060008301846133c0565b92915050565b7f4f6e6c792061646d696e2063616e207769746864726177206665657300000000600082015250565b60006144bc601c83613333565b91506144c782614486565b602082019050919050565b600060208201905081810360008301526144eb816144af565b9050919050565b50565b60006145026000836142ef565b915061450d826144f2565b600082019050919050565b6000614523826144f5565b9150819050919050565b7f4661696c656420746f2073656e64206665657300000000000000000000000000600082015250565b6000614563601383613333565b915061456e8261452d565b602082019050919050565b6000602082019050818103600083015261459281614556565b9050919050565b60006040820190506145ae60008301856133c0565b6145bb60208301846132fe565b9392505050565b7f464f5242494444454e0000000000000000000000000000000000000000000000600082015250565b60006145f8600983613333565b9150614603826145c2565b602082019050919050565b60006020820190508181036000830152614627816145eb565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060608201905061467260008301866132fe565b61467f60208301856133c0565b61468c60408301846132fe565b949350505050565b60006040820190506146a960008301856132fe565b6146b660208301846133c0565b9392505050565b60006060820190506146d260008301866132fe565b6146df60208301856133c0565b81810360408301526146f181846137cf565b9050949350505050565b7f4e6f2072652d656e7472616e6379000000000000000000000000000000000000600082015250565b6000614731600e83613333565b915061473c826146fb565b602082019050919050565b6000602082019050818103600083015261476081614724565b9050919050565b7f496e73756666696369656e742066656500000000000000000000000000000000600082015250565b600061479d601083613333565b91506147a882614767565b602082019050919050565b600060208201905081810360008301526147cc81614790565b9050919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026148357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826147f8565b61483f86836147f8565b95508019841693508086168417925050509392505050565b6000819050919050565b600061487c61487761487284613269565b614857565b613269565b9050919050565b6000819050919050565b61489683614861565b6148aa6148a282614883565b848454614805565b825550505050565b600090565b6148bf6148b2565b6148ca81848461488d565b505050565b5b818110156148ee576148e36000826148b7565b6001810190506148d0565b5050565b601f82111561493357614904816147d3565b61490d846147e8565b8101602085101561491c578190505b614930614928856147e8565b8301826148cf565b50505b505050565b600082821c905092915050565b600061495660001984600802614938565b1980831691505092915050565b600061496f8383614945565b9150826002028217905092915050565b61498882613328565b67ffffffffffffffff8111156149a1576149a0613611565b5b6149ab825461443a565b6149b68282856148f2565b600060209050601f8311600181146149e957600084156149d7578287015190505b6149e18582614963565b865550614a49565b601f1984166149f7866147d3565b60005b82811015614a1f578489015182556001820191506020850194506020810190506149fa565b86831015614a3c5784890151614a38601f891682614945565b8355505b6001600288020188555050505b505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614a8b82613269565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614abd57614abc614a51565b5b600182019050919050565b600081549050614ad78161443a565b9050919050565b818103614aec575050614bc4565b614af582614ac8565b67ffffffffffffffff811115614b0e57614b0d613611565b5b614b18825461443a565b614b238282856148f2565b6000601f831160018114614b525760008415614b40578287015490505b614b4a8582614963565b865550614bbd565b601f198416614b60876147d3565b9650614b6b866147d3565b60005b82811015614b9357848901548255600182019150600185019450602081019050614b6e565b86831015614bb05784890154614bac601f891682614945565b8355505b6001600288020188555050505b5050505050505b565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000614c22602683613333565b9150614c2d82614bc6565b604082019050919050565b60006020820190508181036000830152614c5181614c15565b9050919050565b6000819050602082019050919050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b6000614ca08251614c68565b80915050919050565b6000614cb4826137c4565b82614cbe84614c58565b9050614cc981614c94565b92506014821015614d0957614d047fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026147f8565b831692505b5050919050565b6000606082019050614d2560008301866132fe565b614d32602083018561323f565b8181036040830152614d4481846137cf565b9050949350505050565b6000608082019050614d6360008301876132fe565b614d7060208301866132fe565b614d7d60408301856133c0565b8181036060830152614d8f81846137cf565b905095945050505050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000614dd0602083613333565b9150614ddb82614d9a565b602082019050919050565b60006020820190508181036000830152614dff81614dc3565b9050919050565b60008190508160005260206000209050919050565b601f821115614e5c57614e2d81614e06565b614e36846147e8565b81016020851015614e45578190505b614e59614e51856147e8565b8301826148cf565b50505b505050565b614e6a826137c4565b67ffffffffffffffff811115614e8357614e82613611565b5b614e8d825461443a565b614e98828285614e1b565b600060209050601f831160018114614ecb5760008415614eb9578287015190505b614ec38582614963565b865550614f2b565b601f198416614ed986614e06565b60005b82811015614f0157848901518255600182019150602085019450602081019050614edc565b86831015614f1e5784890151614f1a601f891682614945565b8355505b6001600288020188555050505b505050505050565b6000604082019050614f4860008301856133c0565b8181036020830152614f5a81846137cf565b90509392505050565b6000614f6e82613269565b9150614f7983613269565b9250828201905080821115614f9157614f90614a51565b5b92915050565b60007fffffffffffffffffffff0000000000000000000000000000000000000000000082169050919050565b6000819050919050565b614fde614fd982614f97565b614fc3565b82525050565b60007fffff00000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b61502b61502682614fe4565b615010565b82525050565b6000819050919050565b61504c61504782614c68565b615031565b82525050565b600061505e8286614fcd565b600a8201915061506e828561501a565b60028201915061507e828461503b565b601482019150819050949350505050565b600061509b82516133b6565b80915050919050565b60006150af826137c4565b826150b984614c58565b90506150c48161508f565b92506020821015615104576150ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff836020036008026147f8565b831692505b5050919050565b600061511e6151198461368c565b613671565b90508281526020810184848401111561513a5761513961360c565b5b615145848285613344565b509392505050565b600082601f83011261516257615161613607565b5b815161517284826020860161510b565b91505092915050565b600060208284031215615191576151906131a4565b5b600082015167ffffffffffffffff8111156151af576151ae6131a9565b5b6151bb8482850161514d565b91505092915050565b7f736c6963655f6f766572666c6f77000000000000000000000000000000000000600082015250565b60006151fa600e83613333565b9150615205826151c4565b602082019050919050565b60006020820190508181036000830152615229816151ed565b9050919050565b7f736c6963655f6f75744f66426f756e6473000000000000000000000000000000600082015250565b6000615266601183613333565b915061527182615230565b602082019050919050565b6000602082019050818103600083015261529581615259565b9050919050565b60006152a782613269565b91506152b283613269565b92508282039050818111156152ca576152c9614a51565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212200284f6d6111606ee72bc78734808163bc8835d2354efe48a1fc0311068294a9164736f6c63430008140033000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000048294a067d1bc5a58bcbab4b3be329d078d9e1af000000000000000000000000000000000000000000000000000000000000000750696e5361766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000350494e0000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106101d15760003560e01c8063715018a6116100f75780639790242111610095578063b92223c311610064578063b92223c314610715578063dedff9c614610731578063f1b97e041461076e578063f2fde38b14610797576101d8565b80639790242114610656578063a3b261f214610672578063a56581df146106af578063b19805af146106ec576101d8565b806386a10ddd116100d157806386a10ddd146105ae57806387cf3ef4146105d75780638da5cb5b1461060257806395b9945b1461062d576101d8565b8063715018a6146105525780637e87632c146105695780637f23690c14610592576101d8565b8063476343ee1161016f5780635a64ad951161013e5780635a64ad95146104965780636a1db1bf146104c15780636f9fb98a146104ea57806370a0823114610515576101d8565b8063476343ee146103dc57806349a6078d146103f3578063511b69521461043057806354f6127f14610459576101d8565b806318160ddd116101ab57806318160ddd146102fa578063217b2270146103255780632a3654a41461036257806345c146711461039f576101d8565b806301ffc9a714610240578063085f441f1461027d57806316ebbe04146102ba576101d8565b366101d857005b60003660606004600036905010156102295782826040517fe5099ee3000000000000000000000000000000000000000000000000000000008152600401610220929190613176565b60405180910390fd5b61023383836107c0565b9050915050805190602001f35b34801561024c57600080fd5b5061026760048036038101906102629190613206565b61093d565b604051610274919061324e565b60405180910390f35b34801561028957600080fd5b506102a4600480360381019061029f919061329f565b6109ae565b6040516102b1919061330d565b60405180910390f35b3480156102c657600080fd5b506102e160048036038101906102dc919061329f565b6109d6565b6040516102f194939291906133cf565b60405180910390f35b34801561030657600080fd5b5061030f610aae565b60405161031c919061341b565b60405180910390f35b34801561033157600080fd5b5061034c60048036038101906103479190613462565b610ab8565b604051610359919061330d565b60405180910390f35b34801561036e57600080fd5b50610389600480360381019061038491906134bb565b610b6b565b604051610396919061324e565b60405180910390f35b3480156103ab57600080fd5b506103c660048036038101906103c1919061329f565b610b88565b6040516103d3919061330d565b60405180910390f35b3480156103e857600080fd5b506103f1610bc8565b005b3480156103ff57600080fd5b5061041a60048036038101906104159190613462565b610d2f565b60405161042791906135b9565b60405180910390f35b34801561043c57600080fd5b506104576004803603810190610452919061372d565b610d5c565b005b34801561046557600080fd5b50610480600480360381019061047b9190613462565b610dc3565b60405161048d9190613808565b60405180910390f35b3480156104a257600080fd5b506104ab610dd5565b6040516104b8919061341b565b60405180910390f35b3480156104cd57600080fd5b506104e860048036038101906104e3919061329f565b610ddb565b005b3480156104f657600080fd5b506104ff610e75565b60405161050c919061341b565b60405180910390f35b34801561052157600080fd5b5061053c6004803603810190610537919061382a565b610e7d565b604051610549919061341b565b60405180910390f35b34801561055e57600080fd5b50610567610ecd565b005b34801561057557600080fd5b50610590600480360381019061058b9190613b86565b610ee1565b005b6105ac60048036038101906105a79190613c8d565b610ff5565b005b3480156105ba57600080fd5b506105d560048036038101906105d09190613ce9565b611045565b005b3480156105e357600080fd5b506105ec61129d565b6040516105f9919061330d565b60405180910390f35b34801561060e57600080fd5b506106176112c3565b604051610624919061330d565b60405180910390f35b34801561063957600080fd5b50610654600480360381019061064f9190613eda565b6112ec565b005b610670600480360381019061066b9190613f65565b61134d565b005b34801561067e57600080fd5b506106996004803603810190610694919061382a565b61145f565b6040516106a6919061409b565b60405180910390f35b3480156106bb57600080fd5b506106d660048036038101906106d1919061329f565b6114af565b6040516106e391906140bd565b60405180910390f35b3480156106f857600080fd5b50610713600480360381019061070e919061382a565b611557565b005b61072f600480360381019061072a91906140df565b61162b565b005b34801561073d57600080fd5b506107586004803603810190610753919061414e565b611840565b60405161076591906142a3565b60405180910390f35b34801561077a57600080fd5b5061079560048036038101906107909190613ce9565b6118f1565b005b3480156107a357600080fd5b506107be60048036038101906107b9919061382a565b611a82565b005b606060006107f16000357fffffffff0000000000000000000000000000000000000000000000000000000016611b05565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610888576000357fffffffff00000000000000000000000000000000000000000000000000000000166040517fbb370b2b00000000000000000000000000000000000000000000000000000000815260040161087f91906142d4565b60405180910390fd5b6000808273ffffffffffffffffffffffffffffffffffffffff1634878733346040516020016108ba9493929190614388565b6040516020818303038152906040526040516108d691906143f4565b60006040518083038185875af1925050503d8060008114610913576040519150601f19603f3d011682016040523d82523d6000602084013e610918565b606091505b5091509150811561092e57809350505050610937565b80518060208301fd5b92915050565b6000631ae9ba1f60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610997575061099682611bb9565b5b806109a757506109a682611c1a565b5b9050919050565b60006109cf600e600084815260200190815260200160002060030154610ab8565b9050919050565b600e6020528060005260406000206000915090508060000180546109f99061443a565b80601f0160208091040260200160405190810160405280929190818152602001828054610a259061443a565b8015610a725780601f10610a4757610100808354040283529160200191610a72565b820191906000526020600020905b815481529060010190602001808311610a5557829003601f168201915b5050505050908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020154908060030154905084565b6000600254905090565b6000806003600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610b6257826040517fae8f9a36000000000000000000000000000000000000000000000000000000008152600401610b59919061446b565b60405180910390fd5b80915050919050565b6000610b7682611c80565b610b808383611ccd565b905092915050565b6000600e600083815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b600760019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c58576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c4f906144d2565b60405180910390fd5b60004790506000600760019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1682604051610ca590614518565b60006040518083038185875af1925050503d8060008114610ce2576040519150601f19603f3d011682016040523d82523d6000602084013e610ce7565b606091505b5050905080610d2b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d2290614579565b60405180910390fd5b5050565b6060610d3a82611c80565b610d5560056000848152602001908152602001600020611d3f565b9050919050565b6000339050610d6b8185611ccd565b610dae5783816040517f1294d2a9000000000000000000000000000000000000000000000000000000008152600401610da5929190614599565b60405180910390fd5b610dbb8686868686611d60565b505050505050565b6060610dce8261206f565b9050919050565b60085481565b600760019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610e6b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e629061460e565b60405180910390fd5b8060088190555050565b600047905090565b6000610ec6600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612114565b9050919050565b610ed5612129565b610edf60006121a0565b565b600085519050845181141580610ef8575083518114155b80610f04575082518114155b80610f10575081518114155b15610f47576040517f93a8311900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610fec57610fe1878281518110610f6857610f6761462e565b5b6020026020010151878381518110610f8357610f8261462e565b5b6020026020010151878481518110610f9e57610f9d61462e565b5b6020026020010151878581518110610fb957610fb861462e565b5b6020026020010151878681518110610fd457610fd361462e565b5b6020026020010151610d5c565b806001019050610f4a565b50505050505050565b610ffd612129565b60003414611037576040517ff36ba73700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611041828261229f565b5050565b600061105083610ab8565b90503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146110c6578083336040517f5b271ea20000000000000000000000000000000000000000000000000000000081526004016110bd9392919061465d565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361112c576040517f9577b8b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611191576040517f89fdad6200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006111b885600560008781526020019081526020016000206123d390919063ffffffff16565b9050806111fe5784846040517fa7626b680000000000000000000000000000000000000000000000000000000081526004016111f5929190614694565b60405180910390fd5b838273ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167e52e433f2d4225671bc164dd1cdc9a76044356091f27ad234798bd0cbf083498660405161125b9190613808565b60405180910390a4600033858560405160200161127a939291906146bd565b60405160208183030381529060405290506112958682612403565b505050505050565b600760019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008151905060005b8181146113465761133b858583815181106113135761131261462e565b5b602002602001015185848151811061132e5761132d61462e565b5b602002602001015161162b565b8060010190506112f5565b5050505050565b611355612129565b6000341461138f576040517ff36ba73700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80518251146113ca576040517f3bcc897900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000825103611405576040517f97da5f9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b825181101561145a5761144f8382815181106114275761142661462e565b5b60200260200101518383815181106114425761144161462e565b5b602002602001015161229f565b806001019050611408565b505050565b60606114a8600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612522565b9050919050565b6060600e600083815260200190815260200160002060000180546114d29061443a565b80601f01602080910402602001604051908101604052809291908181526020018280546114fe9061443a565b801561154b5780601f106115205761010080835404028352916020019161154b565b820191906000526020600020905b81548152906001019060200180831161152e57829003601f168201915b50505050509050919050565b600760019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146115e7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115de9061460e565b60405180910390fd5b80600760016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600760009054906101000a900460ff161561167b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161167290614747565b60405180910390fd5b6001600760006101000a81548160ff0219169083151502179055506008543410156116db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116d2906147b3565b60405180910390fd5b81600960000190816116ed919061497f565b5033600960010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600d6000815461174190614a80565b919050819055600960020181905550806009600301819055506009600e6000600d548152602001908152602001600020600082018160000190816117859190614ade565b506001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060028201548160020155600382015481600301559050506118208382600160405180602001604052806000815250612543565b6000600760006101000a81548160ff021916908315150217905550505050565b6060815167ffffffffffffffff81111561185d5761185c613611565b5b60405190808252806020026020018201604052801561189057816020015b606081526020019060019003908161187b5790505b50905060005b82518110156118eb576118c28382815181106118b5576118b461462e565b5b602002602001015161206f565b8282815181106118d5576118d461462e565b5b6020026020010181905250806001019050611896565b50919050565b60006118fc83610ab8565b90503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611972578083336040517f5b271ea20000000000000000000000000000000000000000000000000000000081526004016119699392919061465d565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036119d8576040517f9577b8b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611a3d576040517f89fdad6200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a498482858561276b565b6000338484604051602001611a60939291906146bd565b6040516020818303038152906040529050611a7b8582612403565b5050505050565b611a8a612129565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611af9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611af090614c38565b60405180910390fd5b611b02816121a0565b50565b600080611b3e69cee78b4094da8601109660b01b847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916612845565b90506000611b4b8261206f565b90506014815114158015611b6157506000815114155b15611ba357806040517f42bfe79f000000000000000000000000000000000000000000000000000000008152600401611b9a9190613808565b60405180910390fd5b80611bad90614ca9565b60601c92505050919050565b600063a918fa6b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611c135750611c1282612885565b5b9050919050565b600080611c2d6301ffc9a760e01b611b05565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611c6d576000915050611c7b565b611c7781846128e6565b9150505b919050565b611c8981612985565b611cca57806040517fae8f9a36000000000000000000000000000000000000000000000000000000008152600401611cc1919061446b565b60405180910390fd5b50565b600080611cd983610ab8565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480611d365750611d3584600560008681526020019081526020016000206129f190919063ffffffff16565b5b91505092915050565b60606000611d4f83600001612a21565b905060608190508092505050919050565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611dc5576040517f5d67d6c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611dd084610ab8565b90508573ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611e46578084876040517f5b271ea2000000000000000000000000000000000000000000000000000000008152600401611e3d9392919061465d565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611eac576040517f24ecef4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000339050611ebc878787612a7d565b611ec68786612a82565b611f1785600460008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612af790919063ffffffff16565b50611f6985600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612b0e90919063ffffffff16565b50856003600087815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550848673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf84888860405161201e93929190614d10565b60405180910390a460008787878660405160200161203f9493929190614d4e565b604051602081830303815290604052905061205a8882612b25565b612065878683612be7565b5050505050505050565b606060016000838152602001908152602001600020805461208f9061443a565b80601f01602080910402602001604051908101604052809291908181526020018280546120bb9061443a565b80156121085780601f106120dd57610100808354040283529160200191612108565b820191906000526020600020905b8154815290600101906020018083116120eb57829003601f168201915b50505050509050919050565b600061212282600001612d4e565b9050919050565b3373ffffffffffffffffffffffffffffffffffffffff166121486112c3565b73ffffffffffffffffffffffffffffffffffffffff161461219e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161219590614de6565b60405180910390fd5b565b6121a86112c3565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461229c5760008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3505b50565b7fdeba1e292f8ba88238e10ab3c7f88bd4be4fac56cad5194b6ecceaf653468af160001b82036122fb576040517f85c169bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2f0a68ab07768e01943a599e73362a0e17a63a72e94dd2e384d2c1d4db93275660001b8203612357576040517f76755b3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600084815260200190815260200160002090816123779190614e61565b50817fece574603820d07bc9b91f2a932baadf4628aabcb8afba49776529c14a6104b2610100835111156123b8576123b3836000610100612d5f565b6123ba565b825b6040516123c79190613808565b60405180910390a25050565b60006123fb836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612e7d565b905092915050565b61241482636bb56a1460e01b6128e6565b1561251e578173ffffffffffffffffffffffffffffffffffffffff16636bb56a1460e01b7f8a1c15a8799f71b547e08e2bcb2e85257e81b0a07eee2ce6712549eef1f0097060001b8360405160240161246e929190614f33565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516124d891906143f4565b6000604051808303816000865af19150503d8060008114612515576040519150601f19603f3d011682016040523d82523d6000602084013e61251a565b606091505b5050505b5050565b6060600061253283600001612a21565b905060608190508092505050919050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036125a9576040517f24ecef4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125b283612985565b156125f457826040517f34c7b5110000000000000000000000000000000000000000000000000000000081526004016125eb919061446b565b60405180910390fd5b600033905061260560008686612a7d565b6001600260008282546126189190614f63565b9250508190555061267084600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612b0e90919063ffffffff16565b50846003600086815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838573ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf84878760405161272693929190614d10565b60405180910390a46000808686856040516020016127479493929190614d4e565b6040516020818303038152906040529050612763868583612be7565b505050505050565b60006127928560056000868152602001908152602001600020612eed90919063ffffffff16565b9050806127d85784836040517f4aa31a8c0000000000000000000000000000000000000000000000000000000081526004016127cf929190614694565b60405180910390fd5b828473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f501bc920d7f604417e315bcf29247652b2327fa1076b27b7f132bd8927cb15ea856040516128369190613808565b60405180910390a45050505050565b60008083600060f01b8460405160200161286193929190615052565b60405160208183030381529060405290508061287c906150a4565b91505092915050565b600063629aa69460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806128df57506128de82612f1d565b5b9050919050565b600080826040516024016128fa91906142d4565b6040516020818303038152906040526301ffc9a760e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000806000602060008551602087018a617530fa92503d9150600051905082801561296d575060208210155b80156129795750600081115b94505050505092915050565b60008073ffffffffffffffffffffffffffffffffffffffff166003600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614159050919050565b6000612a19836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612f87565b905092915050565b606081600001805480602002602001604051908101604052809291908181526020018280548015612a7157602002820191906000526020600020905b815481526020019060010190808311612a5d575b50505050509050919050565b505050565b60006005600083815260200190815260200160002090506000612aa482612faa565b905060005b81811015612af0576000612ac7600085612fbf90919063ffffffff16565b9050612ae48187876040518060200160405280600081525061276b565b81600101915050612aa9565b5050505050565b6000612b068360000183612fd9565b905092915050565b6000612b1d8360000183612e7d565b905092915050565b612b3682636bb56a1460e01b6128e6565b15612be3578173ffffffffffffffffffffffffffffffffffffffff16636bb56a147fb23eae7e6d1564b295b4c3e3be402d9a2f0776c57bdf365903496f6fa481ab0060001b836040518363ffffffff1660e01b8152600401612b99929190614f33565b6000604051808303816000875af1158015612bb8573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190612be1919061517b565b505b5050565b612bf883636bb56a1460e01b6128e6565b15612ca9578273ffffffffffffffffffffffffffffffffffffffff16636bb56a147f0b084a55ebf70fd3c06fd755269dac2212c4d3f0f4d09079780bfa50c1b2984d60001b836040518363ffffffff1660e01b8152600401612c5b929190614f33565b6000604051808303816000875af1158015612c7a573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190612ca3919061517b565b50612d49565b81612d485760008373ffffffffffffffffffffffffffffffffffffffff163b1115612d0b57826040517f4349776d000000000000000000000000000000000000000000000000000000008152600401612d02919061330d565b60405180910390fd5b826040517f03173137000000000000000000000000000000000000000000000000000000008152600401612d3f919061330d565b60405180910390fd5b5b505050565b600081600001805490509050919050565b606081601f83612d6f9190614f63565b1015612db0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612da790615210565b60405180910390fd5b8183612dbc9190614f63565b84511015612dff576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612df69061527c565b60405180910390fd5b6060821560008114612e205760405191506000825260208201604052612e71565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015612e5e5780518352602083019250602081019050612e41565b50868552601f19601f8301166040525050505b50809150509392505050565b6000612e898383612f87565b612ee2578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050612ee7565b600090505b92915050565b6000612f15836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612fd9565b905092915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b600080836001016000848152602001908152602001600020541415905092915050565b6000612fb882600001612d4e565b9050919050565b6000612fce83600001836130ed565b60001c905092915050565b600080836001016000848152602001908152602001600020549050600081146130e157600060018261300b919061529c565b9050600060018660000180549050613023919061529c565b90508082146130925760008660000182815481106130445761304361462e565b5b90600052602060002001549050808760000184815481106130685761306761462e565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b856000018054806130a6576130a56152d0565b5b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506130e7565b60009150505b92915050565b60008260000182815481106131055761310461462e565b5b9060005260206000200154905092915050565b600082825260208201905092915050565b82818337600083830152505050565b6000601f19601f8301169050919050565b60006131558385613118565b9350613162838584613129565b61316b83613138565b840190509392505050565b60006020820190508181036000830152613191818486613149565b90509392505050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6131e3816131ae565b81146131ee57600080fd5b50565b600081359050613200816131da565b92915050565b60006020828403121561321c5761321b6131a4565b5b600061322a848285016131f1565b91505092915050565b60008115159050919050565b61324881613233565b82525050565b6000602082019050613263600083018461323f565b92915050565b6000819050919050565b61327c81613269565b811461328757600080fd5b50565b60008135905061329981613273565b92915050565b6000602082840312156132b5576132b46131a4565b5b60006132c38482850161328a565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006132f7826132cc565b9050919050565b613307816132ec565b82525050565b600060208201905061332260008301846132fe565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613362578082015181840152602081019050613347565b60008484015250505050565b600061337982613328565b6133838185613333565b9350613393818560208601613344565b61339c81613138565b840191505092915050565b6133b081613269565b82525050565b6000819050919050565b6133c9816133b6565b82525050565b600060808201905081810360008301526133e9818761336e565b90506133f860208301866132fe565b61340560408301856133a7565b61341260608301846133c0565b95945050505050565b600060208201905061343060008301846133a7565b92915050565b61343f816133b6565b811461344a57600080fd5b50565b60008135905061345c81613436565b92915050565b600060208284031215613478576134776131a4565b5b60006134868482850161344d565b91505092915050565b613498816132ec565b81146134a357600080fd5b50565b6000813590506134b58161348f565b92915050565b600080604083850312156134d2576134d16131a4565b5b60006134e0858286016134a6565b92505060206134f18582860161344d565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b613530816132ec565b82525050565b60006135428383613527565b60208301905092915050565b6000602082019050919050565b6000613566826134fb565b6135708185613506565b935061357b83613517565b8060005b838110156135ac5781516135938882613536565b975061359e8361354e565b92505060018101905061357f565b5085935050505092915050565b600060208201905081810360008301526135d3818461355b565b905092915050565b6135e481613233565b81146135ef57600080fd5b50565b600081359050613601816135db565b92915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61364982613138565b810181811067ffffffffffffffff8211171561366857613667613611565b5b80604052505050565b600061367b61319a565b90506136878282613640565b919050565b600067ffffffffffffffff8211156136a7576136a6613611565b5b6136b082613138565b9050602081019050919050565b60006136d06136cb8461368c565b613671565b9050828152602081018484840111156136ec576136eb61360c565b5b6136f7848285613129565b509392505050565b600082601f83011261371457613713613607565b5b81356137248482602086016136bd565b91505092915050565b600080600080600060a08688031215613749576137486131a4565b5b6000613757888289016134a6565b9550506020613768888289016134a6565b94505060406137798882890161344d565b935050606061378a888289016135f2565b925050608086013567ffffffffffffffff8111156137ab576137aa6131a9565b5b6137b7888289016136ff565b9150509295509295909350565b600081519050919050565b60006137da826137c4565b6137e48185613118565b93506137f4818560208601613344565b6137fd81613138565b840191505092915050565b6000602082019050818103600083015261382281846137cf565b905092915050565b6000602082840312156138405761383f6131a4565b5b600061384e848285016134a6565b91505092915050565b600067ffffffffffffffff82111561387257613871613611565b5b602082029050602081019050919050565b600080fd5b600061389b61389684613857565b613671565b905080838252602082019050602084028301858111156138be576138bd613883565b5b835b818110156138e757806138d388826134a6565b8452602084019350506020810190506138c0565b5050509392505050565b600082601f83011261390657613905613607565b5b8135613916848260208601613888565b91505092915050565b600067ffffffffffffffff82111561393a57613939613611565b5b602082029050602081019050919050565b600061395e6139598461391f565b613671565b9050808382526020820190506020840283018581111561398157613980613883565b5b835b818110156139aa5780613996888261344d565b845260208401935050602081019050613983565b5050509392505050565b600082601f8301126139c9576139c8613607565b5b81356139d984826020860161394b565b91505092915050565b600067ffffffffffffffff8211156139fd576139fc613611565b5b602082029050602081019050919050565b6000613a21613a1c846139e2565b613671565b90508083825260208201905060208402830185811115613a4457613a43613883565b5b835b81811015613a6d5780613a5988826135f2565b845260208401935050602081019050613a46565b5050509392505050565b600082601f830112613a8c57613a8b613607565b5b8135613a9c848260208601613a0e565b91505092915050565b600067ffffffffffffffff821115613ac057613abf613611565b5b602082029050602081019050919050565b6000613ae4613adf84613aa5565b613671565b90508083825260208201905060208402830185811115613b0757613b06613883565b5b835b81811015613b4e57803567ffffffffffffffff811115613b2c57613b2b613607565b5b808601613b3989826136ff565b85526020850194505050602081019050613b09565b5050509392505050565b600082601f830112613b6d57613b6c613607565b5b8135613b7d848260208601613ad1565b91505092915050565b600080600080600060a08688031215613ba257613ba16131a4565b5b600086013567ffffffffffffffff811115613bc057613bbf6131a9565b5b613bcc888289016138f1565b955050602086013567ffffffffffffffff811115613bed57613bec6131a9565b5b613bf9888289016138f1565b945050604086013567ffffffffffffffff811115613c1a57613c196131a9565b5b613c26888289016139b4565b935050606086013567ffffffffffffffff811115613c4757613c466131a9565b5b613c5388828901613a77565b925050608086013567ffffffffffffffff811115613c7457613c736131a9565b5b613c8088828901613b58565b9150509295509295909350565b60008060408385031215613ca457613ca36131a4565b5b6000613cb28582860161344d565b925050602083013567ffffffffffffffff811115613cd357613cd26131a9565b5b613cdf858286016136ff565b9150509250929050565b600080600060608486031215613d0257613d016131a4565b5b6000613d10868287016134a6565b9350506020613d218682870161344d565b925050604084013567ffffffffffffffff811115613d4257613d416131a9565b5b613d4e868287016136ff565b9150509250925092565b600067ffffffffffffffff821115613d7357613d72613611565b5b602082029050602081019050919050565b600067ffffffffffffffff821115613d9f57613d9e613611565b5b613da882613138565b9050602081019050919050565b6000613dc8613dc384613d84565b613671565b905082815260208101848484011115613de457613de361360c565b5b613def848285613129565b509392505050565b600082601f830112613e0c57613e0b613607565b5b8135613e1c848260208601613db5565b91505092915050565b6000613e38613e3384613d58565b613671565b90508083825260208201905060208402830185811115613e5b57613e5a613883565b5b835b81811015613ea257803567ffffffffffffffff811115613e8057613e7f613607565b5b808601613e8d8982613df7565b85526020850194505050602081019050613e5d565b5050509392505050565b600082601f830112613ec157613ec0613607565b5b8135613ed1848260208601613e25565b91505092915050565b600080600060608486031215613ef357613ef26131a4565b5b6000613f01868287016134a6565b935050602084013567ffffffffffffffff811115613f2257613f216131a9565b5b613f2e86828701613eac565b925050604084013567ffffffffffffffff811115613f4f57613f4e6131a9565b5b613f5b868287016139b4565b9150509250925092565b60008060408385031215613f7c57613f7b6131a4565b5b600083013567ffffffffffffffff811115613f9a57613f996131a9565b5b613fa6858286016139b4565b925050602083013567ffffffffffffffff811115613fc757613fc66131a9565b5b613fd385828601613b58565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b614012816133b6565b82525050565b60006140248383614009565b60208301905092915050565b6000602082019050919050565b600061404882613fdd565b6140528185613fe8565b935061405d83613ff9565b8060005b8381101561408e5781516140758882614018565b975061408083614030565b925050600181019050614061565b5085935050505092915050565b600060208201905081810360008301526140b5818461403d565b905092915050565b600060208201905081810360008301526140d7818461336e565b905092915050565b6000806000606084860312156140f8576140f76131a4565b5b6000614106868287016134a6565b935050602084013567ffffffffffffffff811115614127576141266131a9565b5b61413386828701613df7565b92505060406141448682870161344d565b9150509250925092565b600060208284031215614164576141636131a4565b5b600082013567ffffffffffffffff811115614182576141816131a9565b5b61418e848285016139b4565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600082825260208201905092915050565b60006141df826137c4565b6141e981856141c3565b93506141f9818560208601613344565b61420281613138565b840191505092915050565b600061421983836141d4565b905092915050565b6000602082019050919050565b600061423982614197565b61424381856141a2565b935083602082028501614255856141b3565b8060005b858110156142915784840389528151614272858261420d565b945061427d83614221565b925060208a01995050600181019050614259565b50829750879550505050505092915050565b600060208201905081810360008301526142bd818461422e565b905092915050565b6142ce816131ae565b82525050565b60006020820190506142e960008301846142c5565b92915050565b600081905092915050565b600061430683856142ef565b9350614313838584613129565b82840190509392505050565b60008160601b9050919050565b60006143378261431f565b9050919050565b60006143498261432c565b9050919050565b61436161435c826132ec565b61433e565b82525050565b6000819050919050565b61438261437d82613269565b614367565b82525050565b60006143958286886142fa565b91506143a18285614350565b6014820191506143b18284614371565b60208201915081905095945050505050565b60006143ce826137c4565b6143d881856142ef565b93506143e8818560208601613344565b80840191505092915050565b600061440082846143c3565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061445257607f821691505b6020821081036144655761446461440b565b5b50919050565b600060208201905061448060008301846133c0565b92915050565b7f4f6e6c792061646d696e2063616e207769746864726177206665657300000000600082015250565b60006144bc601c83613333565b91506144c782614486565b602082019050919050565b600060208201905081810360008301526144eb816144af565b9050919050565b50565b60006145026000836142ef565b915061450d826144f2565b600082019050919050565b6000614523826144f5565b9150819050919050565b7f4661696c656420746f2073656e64206665657300000000000000000000000000600082015250565b6000614563601383613333565b915061456e8261452d565b602082019050919050565b6000602082019050818103600083015261459281614556565b9050919050565b60006040820190506145ae60008301856133c0565b6145bb60208301846132fe565b9392505050565b7f464f5242494444454e0000000000000000000000000000000000000000000000600082015250565b60006145f8600983613333565b9150614603826145c2565b602082019050919050565b60006020820190508181036000830152614627816145eb565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060608201905061467260008301866132fe565b61467f60208301856133c0565b61468c60408301846132fe565b949350505050565b60006040820190506146a960008301856132fe565b6146b660208301846133c0565b9392505050565b60006060820190506146d260008301866132fe565b6146df60208301856133c0565b81810360408301526146f181846137cf565b9050949350505050565b7f4e6f2072652d656e7472616e6379000000000000000000000000000000000000600082015250565b6000614731600e83613333565b915061473c826146fb565b602082019050919050565b6000602082019050818103600083015261476081614724565b9050919050565b7f496e73756666696369656e742066656500000000000000000000000000000000600082015250565b600061479d601083613333565b91506147a882614767565b602082019050919050565b600060208201905081810360008301526147cc81614790565b9050919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026148357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826147f8565b61483f86836147f8565b95508019841693508086168417925050509392505050565b6000819050919050565b600061487c61487761487284613269565b614857565b613269565b9050919050565b6000819050919050565b61489683614861565b6148aa6148a282614883565b848454614805565b825550505050565b600090565b6148bf6148b2565b6148ca81848461488d565b505050565b5b818110156148ee576148e36000826148b7565b6001810190506148d0565b5050565b601f82111561493357614904816147d3565b61490d846147e8565b8101602085101561491c578190505b614930614928856147e8565b8301826148cf565b50505b505050565b600082821c905092915050565b600061495660001984600802614938565b1980831691505092915050565b600061496f8383614945565b9150826002028217905092915050565b61498882613328565b67ffffffffffffffff8111156149a1576149a0613611565b5b6149ab825461443a565b6149b68282856148f2565b600060209050601f8311600181146149e957600084156149d7578287015190505b6149e18582614963565b865550614a49565b601f1984166149f7866147d3565b60005b82811015614a1f578489015182556001820191506020850194506020810190506149fa565b86831015614a3c5784890151614a38601f891682614945565b8355505b6001600288020188555050505b505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614a8b82613269565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614abd57614abc614a51565b5b600182019050919050565b600081549050614ad78161443a565b9050919050565b818103614aec575050614bc4565b614af582614ac8565b67ffffffffffffffff811115614b0e57614b0d613611565b5b614b18825461443a565b614b238282856148f2565b6000601f831160018114614b525760008415614b40578287015490505b614b4a8582614963565b865550614bbd565b601f198416614b60876147d3565b9650614b6b866147d3565b60005b82811015614b9357848901548255600182019150600185019450602081019050614b6e565b86831015614bb05784890154614bac601f891682614945565b8355505b6001600288020188555050505b5050505050505b565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000614c22602683613333565b9150614c2d82614bc6565b604082019050919050565b60006020820190508181036000830152614c5181614c15565b9050919050565b6000819050602082019050919050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b6000614ca08251614c68565b80915050919050565b6000614cb4826137c4565b82614cbe84614c58565b9050614cc981614c94565b92506014821015614d0957614d047fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026147f8565b831692505b5050919050565b6000606082019050614d2560008301866132fe565b614d32602083018561323f565b8181036040830152614d4481846137cf565b9050949350505050565b6000608082019050614d6360008301876132fe565b614d7060208301866132fe565b614d7d60408301856133c0565b8181036060830152614d8f81846137cf565b905095945050505050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000614dd0602083613333565b9150614ddb82614d9a565b602082019050919050565b60006020820190508181036000830152614dff81614dc3565b9050919050565b60008190508160005260206000209050919050565b601f821115614e5c57614e2d81614e06565b614e36846147e8565b81016020851015614e45578190505b614e59614e51856147e8565b8301826148cf565b50505b505050565b614e6a826137c4565b67ffffffffffffffff811115614e8357614e82613611565b5b614e8d825461443a565b614e98828285614e1b565b600060209050601f831160018114614ecb5760008415614eb9578287015190505b614ec38582614963565b865550614f2b565b601f198416614ed986614e06565b60005b82811015614f0157848901518255600182019150602085019450602081019050614edc565b86831015614f1e5784890151614f1a601f891682614945565b8355505b6001600288020188555050505b505050505050565b6000604082019050614f4860008301856133c0565b8181036020830152614f5a81846137cf565b90509392505050565b6000614f6e82613269565b9150614f7983613269565b9250828201905080821115614f9157614f90614a51565b5b92915050565b60007fffffffffffffffffffff0000000000000000000000000000000000000000000082169050919050565b6000819050919050565b614fde614fd982614f97565b614fc3565b82525050565b60007fffff00000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b61502b61502682614fe4565b615010565b82525050565b6000819050919050565b61504c61504782614c68565b615031565b82525050565b600061505e8286614fcd565b600a8201915061506e828561501a565b60028201915061507e828461503b565b601482019150819050949350505050565b600061509b82516133b6565b80915050919050565b60006150af826137c4565b826150b984614c58565b90506150c48161508f565b92506020821015615104576150ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff836020036008026147f8565b831692505b5050919050565b600061511e6151198461368c565b613671565b90508281526020810184848401111561513a5761513961360c565b5b615145848285613344565b509392505050565b600082601f83011261516257615161613607565b5b815161517284826020860161510b565b91505092915050565b600060208284031215615191576151906131a4565b5b600082015167ffffffffffffffff8111156151af576151ae6131a9565b5b6151bb8482850161514d565b91505092915050565b7f736c6963655f6f766572666c6f77000000000000000000000000000000000000600082015250565b60006151fa600e83613333565b9150615205826151c4565b602082019050919050565b60006020820190508181036000830152615229816151ed565b9050919050565b7f736c6963655f6f75744f66426f756e6473000000000000000000000000000000600082015250565b6000615266601183613333565b915061527182615230565b602082019050919050565b6000602082019050818103600083015261529581615259565b9050919050565b60006152a782613269565b91506152b283613269565b92508282039050818111156152ca576152c9614a51565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212200284f6d6111606ee72bc78734808163bc8835d2354efe48a1fc0311068294a9164736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000048294a067d1bc5a58bcbab4b3be329d078d9e1af000000000000000000000000000000000000000000000000000000000000000750696e5361766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000350494e0000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : name_ (string): PinSave
Arg [1] : symbol_ (string): PIN
Arg [2] : newOwner_ (address): 0x48294a067D1bC5a58BCbAB4b3bE329d078D9E1Af
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [2] : 00000000000000000000000048294a067d1bc5a58bcbab4b3be329d078d9e1af
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [4] : 50696e5361766500000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [6] : 50494e0000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.