My Name Tag:
Not Available, login to update
Txn Hash |
Method
|
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|---|
0x20f414118e0c0ab7d34bb3dad1ce423f8f2f259fac9e90db7ef13fc63226f3a3 | Mint | 29283378 | 245 days 22 hrs ago | 0x067823e9251be72ddf8854648d6090e81586e63a | IN | Lens Protocol: Collect NFT | 0 MATIC | 0.000656580001 | |
0x2240fb0cd5f7a01b6632f601aebabe00b9283af9f47233ec12c395bc125e380c | 0x60a06040 | 28384618 | 268 days 6 hrs ago | Lens Protocol: Deployer | IN | Create: CollectNFT | 0 MATIC | 0.103883963241 |
[ Download CSV Export ]
Contract Name:
CollectNFT
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import {ICollectNFT} from '../interfaces/ICollectNFT.sol'; import {ILensHub} from '../interfaces/ILensHub.sol'; import {Errors} from '../libraries/Errors.sol'; import {Events} from '../libraries/Events.sol'; import {LensNFTBase} from './base/LensNFTBase.sol'; /** * @title CollectNFT * @author Lens Protocol * * @notice This is the NFT contract that is minted upon collecting a given publication. It is cloned upon * the first collect for a given publication, and the token URI points to the original publication's contentURI. */ contract CollectNFT is LensNFTBase, ICollectNFT { address public immutable HUB; uint256 internal _profileId; uint256 internal _pubId; uint256 internal _tokenIdCounter; bool private _initialized; // We create the CollectNFT with the pre-computed HUB address before deploying the hub proxy in order // to initialize the hub proxy at construction. constructor(address hub) { if (hub == address(0)) revert Errors.InitParamsInvalid(); HUB = hub; _initialized = true; } /// @inheritdoc ICollectNFT function initialize( uint256 profileId, uint256 pubId, string calldata name, string calldata symbol ) external override { if (_initialized) revert Errors.Initialized(); _initialized = true; _profileId = profileId; _pubId = pubId; super._initialize(name, symbol); emit Events.CollectNFTInitialized(profileId, pubId, block.timestamp); } /// @inheritdoc ICollectNFT function mint(address to) external override returns (uint256) { if (msg.sender != HUB) revert Errors.NotHub(); unchecked { uint256 tokenId = ++_tokenIdCounter; _mint(to, tokenId); return tokenId; } } /// @inheritdoc ICollectNFT function getSourcePublicationPointer() external view override returns (uint256, uint256) { return (_profileId, _pubId); } function tokenURI(uint256 tokenId) public view override returns (string memory) { if (!_exists(tokenId)) revert Errors.TokenDoesNotExist(); return ILensHub(HUB).getContentURI(_profileId, _pubId); } /** * @dev Upon transfers, we emit the transfer event in the hub. */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal override { super._beforeTokenTransfer(from, to, tokenId); ILensHub(HUB).emitCollectNFTTransferEvent(_profileId, _pubId, tokenId, from, to); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; /** * @title ICollectNFT * @author Lens Protocol * * @notice This is the interface for the CollectNFT contract. Which is cloned upon the first collect for any given * publication. */ interface ICollectNFT { /** * @notice Initializes the collect NFT, setting the feed as the privileged minter, storing the collected publication pointer * and initializing the name and symbol in the LensNFTBase contract. * * @param profileId The token ID of the profile in the hub that this collectNFT points to. * @param pubId The profile publication ID in the hub that this collectNFT points to. * @param name The name to set for this NFT. * @param symbol The symbol to set for this NFT. */ function initialize( uint256 profileId, uint256 pubId, string calldata name, string calldata symbol ) external; /** * @notice Mints a collect NFT to the specified address. This can only be called by the hub, and is called * upon collection. * * @param to The address to mint the NFT to. * * @return uint256 An interger representing the minted token ID. */ function mint(address to) external returns (uint256); /** * @notice Returns the source publication pointer mapped to this collect NFT. * * @return tuple First the profile ID uint256, and second the pubId uint256. */ function getSourcePublicationPointer() external view returns (uint256, uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import {DataTypes} from '../libraries/DataTypes.sol'; /** * @title ILensHub * @author Lens Protocol * * @notice This is the interface for the LensHub contract, the main entry point for the Lens Protocol. * You'll find all the events and external functions, as well as the reasoning behind them here. */ interface ILensHub { /** * @notice Initializes the LensHub NFT, setting the initial governance address as well as the name and symbol in * the LensNFTBase contract. * * @param name The name to set for the hub NFT. * @param symbol The symbol to set for the hub NFT. * @param newGovernance The governance address to set. */ function initialize( string calldata name, string calldata symbol, address newGovernance ) external; /** * @notice Sets the privileged governance role. This function can only be called by the current governance * address. * * @param newGovernance The new governance address to set. */ function setGovernance(address newGovernance) external; /** * @notice Sets the emergency admin, which is a permissioned role able to set the protocol state. This function * can only be called by the governance address. * * @param newEmergencyAdmin The new emergency admin address to set. */ function setEmergencyAdmin(address newEmergencyAdmin) external; /** * @notice Sets the protocol state to either a global pause, a publishing pause or an unpaused state. This function * can only be called by the governance address or the emergency admin address. * * Note that this reverts if the emergency admin calls it if: * 1. The emergency admin is attempting to unpause. * 2. The emergency admin is calling while the protocol is already paused. * * @param newState The state to set, as a member of the ProtocolState enum. */ function setState(DataTypes.ProtocolState newState) external; /** * @notice Adds or removes a profile creator from the whitelist. This function can only be called by the current * governance address. * * @param profileCreator The profile creator address to add or remove from the whitelist. * @param whitelist Whether or not the profile creator should be whitelisted. */ function whitelistProfileCreator(address profileCreator, bool whitelist) external; /** * @notice Adds or removes a follow module from the whitelist. This function can only be called by the current * governance address. * * @param followModule The follow module contract address to add or remove from the whitelist. * @param whitelist Whether or not the follow module should be whitelisted. */ function whitelistFollowModule(address followModule, bool whitelist) external; /** * @notice Adds or removes a reference module from the whitelist. This function can only be called by the current * governance address. * * @param referenceModule The reference module contract to add or remove from the whitelist. * @param whitelist Whether or not the reference module should be whitelisted. */ function whitelistReferenceModule(address referenceModule, bool whitelist) external; /** * @notice Adds or removes a collect module from the whitelist. This function can only be called by the current * governance address. * * @param collectModule The collect module contract address to add or remove from the whitelist. * @param whitelist Whether or not the collect module should be whitelisted. */ function whitelistCollectModule(address collectModule, bool whitelist) external; /** * @notice Creates a profile with the specified parameters, minting a profile NFT to the given recipient. This * function must be called by a whitelisted profile creator. * * @param vars A CreateProfileData struct containing the following params: * to: The address receiving the profile. * handle: The handle to set for the profile, must be unique and non-empty. * imageURI: The URI to set for the profile image. * followModule: The follow module to use, can be the zero address. * followModuleInitData: The follow module initialization data, if any. */ function createProfile(DataTypes.CreateProfileData calldata vars) external returns (uint256); /** * @notice Sets the mapping between wallet and its main profile identity. * * @param profileId The token ID of the profile to set as the main profile identity. */ function setDefaultProfile(uint256 profileId) external; /** * @notice Sets the mapping between wallet and its main profile identity via signature with the specified parameters. * * @param vars A SetDefaultProfileWithSigData struct, including the regular parameters and an EIP712Signature struct. */ function setDefaultProfileWithSig(DataTypes.SetDefaultProfileWithSigData calldata vars) external; /** * @notice Sets a profile's follow module, must be called by the profile owner. * * @param profileId The token ID of the profile to set the follow module for. * @param followModule The follow module to set for the given profile, must be whitelisted. * @param followModuleInitData The data to be passed to the follow module for initialization. */ function setFollowModule( uint256 profileId, address followModule, bytes calldata followModuleInitData ) external; /** * @notice Sets a profile's follow module via signature with the specified parameters. * * @param vars A SetFollowModuleWithSigData struct, including the regular parameters and an EIP712Signature struct. */ function setFollowModuleWithSig(DataTypes.SetFollowModuleWithSigData calldata vars) external; /** * @notice Sets a profile's dispatcher, giving that dispatcher rights to publish to that profile. * * @param profileId The token ID of the profile of the profile to set the dispatcher for. * @param dispatcher The dispatcher address to set for the given profile ID. */ function setDispatcher(uint256 profileId, address dispatcher) external; /** * @notice Sets a profile's dispatcher via signature with the specified parameters. * * @param vars A SetDispatcherWithSigData struct, including the regular parameters and an EIP712Signature struct. */ function setDispatcherWithSig(DataTypes.SetDispatcherWithSigData calldata vars) external; /** * @notice Sets a profile's URI, which is reflected in the `tokenURI()` function. * * @param profileId The token ID of the profile of the profile to set the URI for. * @param imageURI The URI to set for the given profile. */ function setProfileImageURI(uint256 profileId, string calldata imageURI) external; /** * @notice Sets a profile's URI via signature with the specified parameters. * * @param vars A SetProfileImageURIWithSigData struct, including the regular parameters and an EIP712Signature struct. */ function setProfileImageURIWithSig(DataTypes.SetProfileImageURIWithSigData calldata vars) external; /** * @notice Sets a followNFT URI for a given profile's follow NFT. * * @param profileId The token ID of the profile for which to set the followNFT URI. * @param followNFTURI The follow NFT URI to set. */ function setFollowNFTURI(uint256 profileId, string calldata followNFTURI) external; /** * @notice Sets a followNFT URI via signature with the specified parameters. * * @param vars A SetFollowNFTURIWithSigData struct, including the regular parameters and an EIP712Signature struct. */ function setFollowNFTURIWithSig(DataTypes.SetFollowNFTURIWithSigData calldata vars) external; /** * @notice Publishes a post to a given profile, must be called by the profile owner. * * @param vars A PostData struct containing the needed parameters. * * @return uint256 An integer representing the post's publication ID. */ function post(DataTypes.PostData calldata vars) external returns (uint256); /** * @notice Publishes a post to a given profile via signature with the specified parameters. * * @param vars A PostWithSigData struct containing the regular parameters and an EIP712Signature struct. * * @return uint256 An integer representing the post's publication ID. */ function postWithSig(DataTypes.PostWithSigData calldata vars) external returns (uint256); /** * @notice Publishes a comment to a given profile, must be called by the profile owner. * * @param vars A CommentData struct containing the needed parameters. * * @return uint256 An integer representing the comment's publication ID. */ function comment(DataTypes.CommentData calldata vars) external returns (uint256); /** * @notice Publishes a comment to a given profile via signature with the specified parameters. * * @param vars A CommentWithSigData struct containing the regular parameters and an EIP712Signature struct. * * @return uint256 An integer representing the comment's publication ID. */ function commentWithSig(DataTypes.CommentWithSigData calldata vars) external returns (uint256); /** * @notice Publishes a mirror to a given profile, must be called by the profile owner. * * @param vars A MirrorData struct containing the necessary parameters. * * @return uint256 An integer representing the mirror's publication ID. */ function mirror(DataTypes.MirrorData calldata vars) external returns (uint256); /** * @notice Publishes a mirror to a given profile via signature with the specified parameters. * * @param vars A MirrorWithSigData struct containing the regular parameters and an EIP712Signature struct. * * @return uint256 An integer representing the mirror's publication ID. */ function mirrorWithSig(DataTypes.MirrorWithSigData calldata vars) external returns (uint256); /** * @notice Follows the given profiles, executing each profile's follow module logic (if any) and minting followNFTs to the caller. * * NOTE: Both the `profileIds` and `datas` arrays must be of the same length, regardless if the profiles do not have a follow module set. * * @param profileIds The token ID array of the profiles to follow. * @param datas The arbitrary data array to pass to the follow module for each profile if needed. * * @return uint256[] An array of integers representing the minted follow NFTs token IDs. */ function follow(uint256[] calldata profileIds, bytes[] calldata datas) external returns (uint256[] memory); /** * @notice Follows a given profile via signature with the specified parameters. * * @param vars A FollowWithSigData struct containing the regular parameters as well as the signing follower's address * and an EIP712Signature struct. * * @return uint256[] An array of integers representing the minted follow NFTs token IDs. */ function followWithSig(DataTypes.FollowWithSigData calldata vars) external returns (uint256[] memory); /** * @notice Collects a given publication, executing collect module logic and minting a collectNFT to the caller. * * @param profileId The token ID of the profile that published the publication to collect. * @param pubId The publication to collect's publication ID. * @param data The arbitrary data to pass to the collect module if needed. * * @return uint256 An integer representing the minted token ID. */ function collect( uint256 profileId, uint256 pubId, bytes calldata data ) external returns (uint256); /** * @notice Collects a given publication via signature with the specified parameters. * * @param vars A CollectWithSigData struct containing the regular parameters as well as the collector's address and * an EIP712Signature struct. * * @return uint256 An integer representing the minted token ID. */ function collectWithSig(DataTypes.CollectWithSigData calldata vars) external returns (uint256); /** * @dev Helper function to emit a detailed followNFT transfer event from the hub, to be consumed by frontends to track * followNFT transfers. * * @param profileId The token ID of the profile associated with the followNFT being transferred. * @param followNFTId The followNFT being transferred's token ID. * @param from The address the followNFT is being transferred from. * @param to The address the followNFT is being transferred to. */ function emitFollowNFTTransferEvent( uint256 profileId, uint256 followNFTId, address from, address to ) external; /** * @dev Helper function to emit a detailed collectNFT transfer event from the hub, to be consumed by frontends to track * collectNFT transfers. * * @param profileId The token ID of the profile associated with the collect NFT being transferred. * @param pubId The publication ID associated with the collect NFT being transferred. * @param collectNFTId The collectNFT being transferred's token ID. * @param from The address the collectNFT is being transferred from. * @param to The address the collectNFT is being transferred to. */ function emitCollectNFTTransferEvent( uint256 profileId, uint256 pubId, uint256 collectNFTId, address from, address to ) external; /// ************************ /// *****VIEW FUNCTIONS***** /// ************************ /** * @notice Returns whether or not a profile creator is whitelisted. * * @param profileCreator The address of the profile creator to check. * * @return bool True if the profile creator is whitelisted, false otherwise. */ function isProfileCreatorWhitelisted(address profileCreator) external view returns (bool); /** * @notice Returns default profile for a given wallet address * * @param wallet The address to find the default mapping * * @return uint256 The default profile id, which will be 0 if not mapped. */ function defaultProfile(address wallet) external view returns (uint256); /** * @notice Returns whether or not a follow module is whitelisted. * * @param followModule The address of the follow module to check. * * @return bool True if the the follow module is whitelisted, false otherwise. */ function isFollowModuleWhitelisted(address followModule) external view returns (bool); /** * @notice Returns whether or not a reference module is whitelisted. * * @param referenceModule The address of the reference module to check. * * @return bool True if the the reference module is whitelisted, false otherwise. */ function isReferenceModuleWhitelisted(address referenceModule) external view returns (bool); /** * @notice Returns whether or not a collect module is whitelisted. * * @param collectModule The address of the collect module to check. * * @return bool True if the the collect module is whitelisted, false otherwise. */ function isCollectModuleWhitelisted(address collectModule) external view returns (bool); /** * @notice Returns the currently configured governance address. * * @return address The address of the currently configured governance. */ function getGovernance() external view returns (address); /** * @notice Returns the dispatcher associated with a profile. * * @param profileId The token ID of the profile to query the dispatcher for. * * @return address The dispatcher address associated with the profile. */ function getDispatcher(uint256 profileId) external view returns (address); /** * @notice Returns the publication count for a given profile. * * @param profileId The token ID of the profile to query. * * @return uint256 The number of publications associated with the queried profile. */ function getPubCount(uint256 profileId) external view returns (uint256); /** * @notice Returns the followNFT associated with a given profile, if any. * * @param profileId The token ID of the profile to query the followNFT for. * * @return address The followNFT associated with the given profile. */ function getFollowNFT(uint256 profileId) external view returns (address); /** * @notice Returns the followNFT URI associated with a given profile. * * @param profileId The token ID of the profile to query the followNFT URI for. * * @return string The followNFT URI associated with the given profile. */ function getFollowNFTURI(uint256 profileId) external view returns (string memory); /** * @notice Returns the collectNFT associated with a given publication, if any. * * @param profileId The token ID of the profile that published the publication to query. * @param pubId The publication ID of the publication to query. * * @return address The address of the collectNFT associated with the queried publication. */ function getCollectNFT(uint256 profileId, uint256 pubId) external view returns (address); /** * @notice Returns the follow module associated witha given profile, if any. * * @param profileId The token ID of the profile to query the follow module for. * * @return address The address of the follow module associated with the given profile. */ function getFollowModule(uint256 profileId) external view returns (address); /** * @notice Returns the collect module associated with a given publication. * * @param profileId The token ID of the profile that published the publication to query. * @param pubId The publication ID of the publication to query. * * @return address The address of the collect module associated with the queried publication. */ function getCollectModule(uint256 profileId, uint256 pubId) external view returns (address); /** * @notice Returns the reference module associated witha given profile, if any. * * @param profileId The token ID of the profile that published the publication to querythe reference module for. * @param pubId The publication ID of the publication to query the reference module for. * * @return address The address of the reference module associated with the given profile. */ function getReferenceModule(uint256 profileId, uint256 pubId) external view returns (address); /** * @notice Returns the handle associated with a profile. * * @param profileId The token ID of the profile to query the handle for. * * @return string The handle associated with the profile. */ function getHandle(uint256 profileId) external view returns (string memory); /** * @notice Returns the publication pointer (profileId & pubId) associated with a given publication. * * @param profileId The token ID of the profile that published the publication to query the pointer for. * @param pubId The publication ID of the publication to query the pointer for. * * @return tuple First, the profile ID of the profile the current publication is pointing to, second, the * publication ID of the publication the current publication is pointing to. */ function getPubPointer(uint256 profileId, uint256 pubId) external view returns (uint256, uint256); /** * @notice Returns the URI associated with a given publication. * * @param profileId The token ID of the profile that published the publication to query. * @param pubId The publication ID of the publication to query. * * @return string The URI associated with a given publication. */ function getContentURI(uint256 profileId, uint256 pubId) external view returns (string memory); /** * @notice Returns the profile token ID according to a given handle. * * @param handle The handle to resolve the profile token ID with. * * @return uint256 The profile ID the passed handle points to. */ function getProfileIdByHandle(string calldata handle) external view returns (uint256); /** * @notice Returns the full profile struct associated with a given profile token ID. * * @param profileId The token ID of the profile to query. * * @return ProfileStruct The profile struct of the given profile. */ function getProfile(uint256 profileId) external view returns (DataTypes.ProfileStruct memory); /** * @notice Returns the full publication struct for a given publication. * * @param profileId The token ID of the profile that published the publication to query. * @param pubId The publication ID of the publication to query. * * @return PublicationStruct The publication struct associated with the queried publication. */ function getPub(uint256 profileId, uint256 pubId) external view returns (DataTypes.PublicationStruct memory); /** * @notice Returns the publication type associated with a given publication. * * @param profileId The token ID of the profile that published the publication to query. * @param pubId The publication ID of the publication to query. * * @return PubType The publication type, as a member of an enum (either "post," "comment" or "mirror"). */ function getPubType(uint256 profileId, uint256 pubId) external view returns (DataTypes.PubType); /** * @notice Returns the follow NFT implementation address. * * @return address The follow NFT implementation address. */ function getFollowNFTImpl() external view returns (address); /** * @notice Returns the collect NFT implementation address. * * @return address The collect NFT implementation address. */ function getCollectNFTImpl() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; library Errors { error CannotInitImplementation(); error Initialized(); error SignatureExpired(); error ZeroSpender(); error SignatureInvalid(); error NotOwnerOrApproved(); error NotHub(); error TokenDoesNotExist(); error NotGovernance(); error NotGovernanceOrEmergencyAdmin(); error EmergencyAdminCannotUnpause(); error CallerNotWhitelistedModule(); error CollectModuleNotWhitelisted(); error FollowModuleNotWhitelisted(); error ReferenceModuleNotWhitelisted(); error ProfileCreatorNotWhitelisted(); error NotProfileOwner(); error NotProfileOwnerOrDispatcher(); error NotDispatcher(); error PublicationDoesNotExist(); error HandleTaken(); error HandleLengthInvalid(); error HandleContainsInvalidCharacters(); error HandleFirstCharInvalid(); error ProfileImageURILengthInvalid(); error CallerNotFollowNFT(); error CallerNotCollectNFT(); error BlockNumberInvalid(); error ArrayMismatch(); error CannotCommentOnSelf(); error NotWhitelisted(); // Module Errors error InitParamsInvalid(); error CollectExpired(); error FollowInvalid(); error ModuleDataMismatch(); error FollowNotApproved(); error MintLimitExceeded(); error CollectNotAllowed(); // MultiState Errors error Paused(); error PublishingPaused(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import {DataTypes} from './DataTypes.sol'; library Events { /** * @dev Emitted when the NFT contract's name and symbol are set at initialization. * * @param name The NFT name set. * @param symbol The NFT symbol set. * @param timestamp The current block timestamp. */ event BaseInitialized(string name, string symbol, uint256 timestamp); /** * @dev Emitted when the hub state is set. * * @param caller The caller who set the state. * @param prevState The previous protocol state, an enum of either `Paused`, `PublishingPaused` or `Unpaused`. * @param newState The newly set state, an enum of either `Paused`, `PublishingPaused` or `Unpaused`. * @param timestamp The current block timestamp. */ event StateSet( address indexed caller, DataTypes.ProtocolState indexed prevState, DataTypes.ProtocolState indexed newState, uint256 timestamp ); /** * @dev Emitted when the governance address is changed. We emit the caller even though it should be the previous * governance address, as we cannot guarantee this will always be the case due to upgradeability. * * @param caller The caller who set the governance address. * @param prevGovernance The previous governance address. * @param newGovernance The new governance address set. * @param timestamp The current block timestamp. */ event GovernanceSet( address indexed caller, address indexed prevGovernance, address indexed newGovernance, uint256 timestamp ); /** * @dev Emitted when the emergency admin is changed. We emit the caller even though it should be the previous * governance address, as we cannot guarantee this will always be the case due to upgradeability. * * @param caller The caller who set the emergency admin address. * @param oldEmergencyAdmin The previous emergency admin address. * @param newEmergencyAdmin The new emergency admin address set. * @param timestamp The current block timestamp. */ event EmergencyAdminSet( address indexed caller, address indexed oldEmergencyAdmin, address indexed newEmergencyAdmin, uint256 timestamp ); /** * @dev Emitted when a profile creator is added to or removed from the whitelist. * * @param profileCreator The address of the profile creator. * @param whitelisted Whether or not the profile creator is being added to the whitelist. * @param timestamp The current block timestamp. */ event ProfileCreatorWhitelisted( address indexed profileCreator, bool indexed whitelisted, uint256 timestamp ); /** * @dev Emitted when a follow module is added to or removed from the whitelist. * * @param followModule The address of the follow module. * @param whitelisted Whether or not the follow module is being added to the whitelist. * @param timestamp The current block timestamp. */ event FollowModuleWhitelisted( address indexed followModule, bool indexed whitelisted, uint256 timestamp ); /** * @dev Emitted when a reference module is added to or removed from the whitelist. * * @param referenceModule The address of the reference module. * @param whitelisted Whether or not the reference module is being added to the whitelist. * @param timestamp The current block timestamp. */ event ReferenceModuleWhitelisted( address indexed referenceModule, bool indexed whitelisted, uint256 timestamp ); /** * @dev Emitted when a collect module is added to or removed from the whitelist. * * @param collectModule The address of the collect module. * @param whitelisted Whether or not the collect module is being added to the whitelist. * @param timestamp The current block timestamp. */ event CollectModuleWhitelisted( address indexed collectModule, bool indexed whitelisted, uint256 timestamp ); /** * @dev Emitted when a profile is created. * * @param profileId The newly created profile's token ID. * @param creator The profile creator, who created the token with the given profile ID. * @param to The address receiving the profile with the given profile ID. * @param handle The handle set for the profile. * @param imageURI The image uri set for the profile. * @param followModule The profile's newly set follow module. This CAN be the zero address. * @param followModuleReturnData The data returned from the follow module's initialization. This is abi encoded * and totally depends on the follow module chosen. * @param followNFTURI The URI set for the profile's follow NFT. * @param timestamp The current block timestamp. */ event ProfileCreated( uint256 indexed profileId, address indexed creator, address indexed to, string handle, string imageURI, address followModule, bytes followModuleReturnData, string followNFTURI, uint256 timestamp ); /** * @dev Emitted when a a default profile is set for a wallet as its main identity * * @param wallet The wallet which set or unset its default profile. * @param profileId The token ID of the profile being set as default, or zero. * @param timestamp The current block timestamp. */ event DefaultProfileSet(address indexed wallet, uint256 indexed profileId, uint256 timestamp); /** * @dev Emitted when a dispatcher is set for a specific profile. * * @param profileId The token ID of the profile for which the dispatcher is set. * @param dispatcher The dispatcher set for the given profile. * @param timestamp The current block timestamp. */ event DispatcherSet(uint256 indexed profileId, address indexed dispatcher, uint256 timestamp); /** * @dev Emitted when a profile's URI is set. * * @param profileId The token ID of the profile for which the URI is set. * @param imageURI The URI set for the given profile. * @param timestamp The current block timestamp. */ event ProfileImageURISet(uint256 indexed profileId, string imageURI, uint256 timestamp); /** * @dev Emitted when a follow NFT's URI is set. * * @param profileId The token ID of the profile for which the followNFT URI is set. * @param followNFTURI The follow NFT URI set. * @param timestamp The current block timestamp. */ event FollowNFTURISet(uint256 indexed profileId, string followNFTURI, uint256 timestamp); /** * @dev Emitted when a profile's follow module is set. * * @param profileId The profile's token ID. * @param followModule The profile's newly set follow module. This CAN be the zero address. * @param followModuleReturnData The data returned from the follow module's initialization. This is abi encoded * and totally depends on the follow module chosen. * @param timestamp The current block timestamp. */ event FollowModuleSet( uint256 indexed profileId, address followModule, bytes followModuleReturnData, uint256 timestamp ); /** * @dev Emitted when a "post" is published. * * @param profileId The profile's token ID. * @param pubId The new publication's ID. * @param contentURI The URI mapped to this new publication. * @param collectModule The collect module mapped to this new publication. This CANNOT be the zero address. * @param collectModuleReturnData The data returned from the collect module's initialization for this given * publication. This is abi encoded and totally depends on the collect module chosen. * @param referenceModule The reference module set for this publication. * @param referenceModuleReturnData The data returned from the reference module at initialization. This is abi * encoded and totally depends on the reference module chosen. * @param timestamp The current block timestamp. */ event PostCreated( uint256 indexed profileId, uint256 indexed pubId, string contentURI, address collectModule, bytes collectModuleReturnData, address referenceModule, bytes referenceModuleReturnData, uint256 timestamp ); /** * @dev Emitted when a "comment" is published. * * @param profileId The profile's token ID. * @param pubId The new publication's ID. * @param contentURI The URI mapped to this new publication. * @param profileIdPointed The profile token ID that this comment points to. * @param pubIdPointed The publication ID that this comment points to. * @param referenceModuleData The data passed to the reference module. * @param collectModule The collect module mapped to this new publication. This CANNOT be the zero address. * @param collectModuleReturnData The data returned from the collect module's initialization for this given * publication. This is abi encoded and totally depends on the collect module chosen. * @param referenceModule The reference module set for this publication. * @param referenceModuleReturnData The data returned from the reference module at initialization. This is abi * encoded and totally depends on the reference module chosen. * @param timestamp The current block timestamp. */ event CommentCreated( uint256 indexed profileId, uint256 indexed pubId, string contentURI, uint256 profileIdPointed, uint256 pubIdPointed, bytes referenceModuleData, address collectModule, bytes collectModuleReturnData, address referenceModule, bytes referenceModuleReturnData, uint256 timestamp ); /** * @dev Emitted when a "mirror" is published. * * @param profileId The profile's token ID. * @param pubId The new publication's ID. * @param profileIdPointed The profile token ID that this mirror points to. * @param pubIdPointed The publication ID that this mirror points to. * @param referenceModuleData The data passed to the reference module. * @param referenceModule The reference module set for this publication. * @param referenceModuleReturnData The data returned from the reference module at initialization. This is abi * encoded and totally depends on the reference module chosen. * @param timestamp The current block timestamp. */ event MirrorCreated( uint256 indexed profileId, uint256 indexed pubId, uint256 profileIdPointed, uint256 pubIdPointed, bytes referenceModuleData, address referenceModule, bytes referenceModuleReturnData, uint256 timestamp ); /** * @dev Emitted when a followNFT clone is deployed using a lazy deployment pattern. * * @param profileId The token ID of the profile to which this followNFT is associated. * @param followNFT The address of the newly deployed followNFT clone. * @param timestamp The current block timestamp. */ event FollowNFTDeployed( uint256 indexed profileId, address indexed followNFT, uint256 timestamp ); /** * @dev Emitted when a collectNFT clone is deployed using a lazy deployment pattern. * * @param profileId The publisher's profile token ID. * @param pubId The publication associated with the newly deployed collectNFT clone's ID. * @param collectNFT The address of the newly deployed collectNFT clone. * @param timestamp The current block timestamp. */ event CollectNFTDeployed( uint256 indexed profileId, uint256 indexed pubId, address indexed collectNFT, uint256 timestamp ); /** * @dev Emitted upon a successful collect action. * * @param collector The address collecting the publication. * @param profileId The token ID of the profile that the collect was initiated towards, useful to differentiate mirrors. * @param pubId The publication ID that the collect was initiated towards, useful to differentiate mirrors. * @param rootProfileId The profile token ID of the profile whose publication is being collected. * @param rootPubId The publication ID of the publication being collected. * @param collectModuleData The data passed to the collect module. * @param timestamp The current block timestamp. */ event Collected( address indexed collector, uint256 indexed profileId, uint256 indexed pubId, uint256 rootProfileId, uint256 rootPubId, bytes collectModuleData, uint256 timestamp ); /** * @dev Emitted upon a successful follow action. * * @param follower The address following the given profiles. * @param profileIds The token ID array of the profiles being followed. * @param followModuleDatas The array of data parameters passed to each follow module. * @param timestamp The current block timestamp. */ event Followed( address indexed follower, uint256[] profileIds, bytes[] followModuleDatas, uint256 timestamp ); /** * @dev Emitted via callback when a followNFT is transferred. * * @param profileId The token ID of the profile associated with the followNFT being transferred. * @param followNFTId The followNFT being transferred's token ID. * @param from The address the followNFT is being transferred from. * @param to The address the followNFT is being transferred to. * @param timestamp The current block timestamp. */ event FollowNFTTransferred( uint256 indexed profileId, uint256 indexed followNFTId, address from, address to, uint256 timestamp ); /** * @dev Emitted via callback when a collectNFT is transferred. * * @param profileId The token ID of the profile associated with the collectNFT being transferred. * @param pubId The publication ID associated with the collectNFT being transferred. * @param collectNFTId The collectNFT being transferred's token ID. * @param from The address the collectNFT is being transferred from. * @param to The address the collectNFT is being transferred to. * @param timestamp The current block timestamp. */ event CollectNFTTransferred( uint256 indexed profileId, uint256 indexed pubId, uint256 indexed collectNFTId, address from, address to, uint256 timestamp ); // Collect/Follow NFT-Specific /** * @dev Emitted when a newly deployed follow NFT is initialized. * * @param profileId The token ID of the profile connected to this follow NFT. * @param timestamp The current block timestamp. */ event FollowNFTInitialized(uint256 indexed profileId, uint256 timestamp); /** * @dev Emitted when delegation power in a FollowNFT is changed. * * @param delegate The delegate whose power has been changed. * @param newPower The new governance power mapped to the delegate. * @param timestamp The current block timestamp. */ event FollowNFTDelegatedPowerChanged( address indexed delegate, uint256 indexed newPower, uint256 timestamp ); /** * @dev Emitted when a newly deployed collect NFT is initialized. * * @param profileId The token ID of the profile connected to the publication mapped to this collect NFT. * @param pubId The publication ID connected to the publication mapped to this collect NFT. * @param timestamp The current block timestamp. */ event CollectNFTInitialized( uint256 indexed profileId, uint256 indexed pubId, uint256 timestamp ); // Module-Specific /** * @notice Emitted when the ModuleGlobals governance address is set. * * @param prevGovernance The previous governance address. * @param newGovernance The new governance address set. * @param timestamp The current block timestamp. */ event ModuleGlobalsGovernanceSet( address indexed prevGovernance, address indexed newGovernance, uint256 timestamp ); /** * @notice Emitted when the ModuleGlobals treasury address is set. * * @param prevTreasury The previous treasury address. * @param newTreasury The new treasury address set. * @param timestamp The current block timestamp. */ event ModuleGlobalsTreasurySet( address indexed prevTreasury, address indexed newTreasury, uint256 timestamp ); /** * @notice Emitted when the ModuleGlobals treasury fee is set. * * @param prevTreasuryFee The previous treasury fee in BPS. * @param newTreasuryFee The new treasury fee in BPS. * @param timestamp The current block timestamp. */ event ModuleGlobalsTreasuryFeeSet( uint16 indexed prevTreasuryFee, uint16 indexed newTreasuryFee, uint256 timestamp ); /** * @notice Emitted when a currency is added to or removed from the ModuleGlobals whitelist. * * @param currency The currency address. * @param prevWhitelisted Whether or not the currency was previously whitelisted. * @param whitelisted Whether or not the currency is whitelisted. * @param timestamp The current block timestamp. */ event ModuleGlobalsCurrencyWhitelisted( address indexed currency, bool indexed prevWhitelisted, bool indexed whitelisted, uint256 timestamp ); /** * @notice Emitted when a module inheriting from the `FeeModuleBase` is constructed. * * @param moduleGlobals The ModuleGlobals contract address used. * @param timestamp The current block timestamp. */ event FeeModuleBaseConstructed(address indexed moduleGlobals, uint256 timestamp); /** * @notice Emitted when a module inheriting from the `ModuleBase` is constructed. * * @param hub The LensHub contract address used. * @param timestamp The current block timestamp. */ event ModuleBaseConstructed(address indexed hub, uint256 timestamp); /** * @notice Emitted when one or multiple addresses are approved (or disapproved) for following in * the `ApprovalFollowModule`. * * @param owner The profile owner who executed the approval. * @param profileId The profile ID that the follow approvals are granted/revoked for. * @param addresses The addresses that have had the follow approvals grnated/revoked. * @param approved Whether each corresponding address is now approved or disapproved. * @param timestamp The current block timestamp. */ event FollowsApproved( address indexed owner, uint256 indexed profileId, address[] addresses, bool[] approved, uint256 timestamp ); /** * @dev Emitted when the user wants to enable or disable follows in the `LensPeriphery`. * * @param owner The profile owner who executed the toggle. * @param profileIds The array of token IDs of the profiles each followNFT is associated with. * @param enabled The array of whether each FollowNFT's follow is enabled/disabled. * @param timestamp The current block timestamp. */ event FollowsToggled( address indexed owner, uint256[] profileIds, bool[] enabled, uint256 timestamp ); /** * @dev Emitted when the metadata associated with a profile is set in the `LensPeriphery`. * * @param profileId The profile ID the metadata is set for. * @param metadata The metadata set for the profile and user. * @param timestamp The current block timestamp. */ event ProfileMetadataSet(uint256 indexed profileId, string metadata, uint256 timestamp); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import {ILensNFTBase} from '../../interfaces/ILensNFTBase.sol'; import {Errors} from '../../libraries/Errors.sol'; import {DataTypes} from '../../libraries/DataTypes.sol'; import {Events} from '../../libraries/Events.sol'; import {ERC721Time} from './ERC721Time.sol'; import {ERC721Enumerable} from './ERC721Enumerable.sol'; /** * @title LensNFTBase * @author Lens Protocol * * @notice This is an abstract base contract to be inherited by other Lens Protocol NFTs, it includes * the slightly modified ERC721Enumerable, which itself inherits from the ERC721Time-- which adds an * internal operator approval setter, stores the mint timestamp for each token, and replaces the * constructor with an initializer. */ abstract contract LensNFTBase is ERC721Enumerable, ILensNFTBase { bytes32 internal constant EIP712_REVISION_HASH = keccak256('1'); bytes32 internal constant PERMIT_TYPEHASH = keccak256('Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)'); bytes32 internal constant PERMIT_FOR_ALL_TYPEHASH = keccak256( 'PermitForAll(address owner,address operator,bool approved,uint256 nonce,uint256 deadline)' ); bytes32 internal constant BURN_WITH_SIG_TYPEHASH = keccak256('BurnWithSig(uint256 tokenId,uint256 nonce,uint256 deadline)'); bytes32 internal constant EIP712_DOMAIN_TYPEHASH = keccak256( 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' ); mapping(address => uint256) public sigNonces; /** * @notice Initializer sets the name, symbol and the cached domain separator. * * NOTE: Inheritor contracts *must* call this function to initialize the name & symbol in the * inherited ERC721 contract. * * @param name The name to set in the ERC721 contract. * @param symbol The symbol to set in the ERC721 contract. */ function _initialize(string calldata name, string calldata symbol) internal { ERC721Time.__ERC721_Init(name, symbol); emit Events.BaseInitialized(name, symbol, block.timestamp); } /// @inheritdoc ILensNFTBase function permit( address spender, uint256 tokenId, DataTypes.EIP712Signature calldata sig ) external override { if (spender == address(0)) revert Errors.ZeroSpender(); address owner = ownerOf(tokenId); unchecked { _validateRecoveredAddress( _calculateDigest( keccak256( abi.encode( PERMIT_TYPEHASH, spender, tokenId, sigNonces[owner]++, sig.deadline ) ) ), owner, sig ); } _approve(spender, tokenId); } /// @inheritdoc ILensNFTBase function permitForAll( address owner, address operator, bool approved, DataTypes.EIP712Signature calldata sig ) external override { if (operator == address(0)) revert Errors.ZeroSpender(); unchecked { _validateRecoveredAddress( _calculateDigest( keccak256( abi.encode( PERMIT_FOR_ALL_TYPEHASH, owner, operator, approved, sigNonces[owner]++, sig.deadline ) ) ), owner, sig ); } _setOperatorApproval(owner, operator, approved); } /// @inheritdoc ILensNFTBase function getDomainSeparator() external view override returns (bytes32) { return _calculateDomainSeparator(); } /// @inheritdoc ILensNFTBase function burn(uint256 tokenId) public virtual override { if (!_isApprovedOrOwner(msg.sender, tokenId)) revert Errors.NotOwnerOrApproved(); _burn(tokenId); } /// @inheritdoc ILensNFTBase function burnWithSig(uint256 tokenId, DataTypes.EIP712Signature calldata sig) public virtual override { address owner = ownerOf(tokenId); unchecked { _validateRecoveredAddress( _calculateDigest( keccak256( abi.encode( BURN_WITH_SIG_TYPEHASH, tokenId, sigNonces[owner]++, sig.deadline ) ) ), owner, sig ); } _burn(tokenId); } /** * @dev Wrapper for ecrecover to reduce code size, used in meta-tx specific functions. */ function _validateRecoveredAddress( bytes32 digest, address expectedAddress, DataTypes.EIP712Signature calldata sig ) internal view { if (sig.deadline < block.timestamp) revert Errors.SignatureExpired(); address recoveredAddress = ecrecover(digest, sig.v, sig.r, sig.s); if (recoveredAddress == address(0) || recoveredAddress != expectedAddress) revert Errors.SignatureInvalid(); } /** * @dev Calculates EIP712 DOMAIN_SEPARATOR based on the current contract and chain ID. */ function _calculateDomainSeparator() internal view returns (bytes32) { return keccak256( abi.encode( EIP712_DOMAIN_TYPEHASH, keccak256(bytes(name())), EIP712_REVISION_HASH, block.chainid, address(this) ) ); } /** * @dev Calculates EIP712 digest based on the current DOMAIN_SEPARATOR. * * @param hashedMessage The message hash from which the digest should be calculated. * * @return bytes32 A 32-byte output representing the EIP712 digest. */ function _calculateDigest(bytes32 hashedMessage) internal view returns (bytes32) { bytes32 digest; unchecked { digest = keccak256( abi.encodePacked('\x19\x01', _calculateDomainSeparator(), hashedMessage) ); } return digest; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; /** * @title DataTypes * @author Lens Protocol * * @notice A standard library of data types used throughout the Lens Protocol. */ library DataTypes { /** * @notice An enum containing the different states the protocol can be in, limiting certain actions. * * @param Unpaused The fully unpaused state. * @param PublishingPaused The state where only publication creation functions are paused. * @param Paused The fully paused state. */ enum ProtocolState { Unpaused, PublishingPaused, Paused } /** * @notice An enum specifically used in a helper function to easily retrieve the publication type for integrations. * * @param Post A standard post, having a URI, a collect module but no pointer to another publication. * @param Comment A comment, having a URI, a collect module and a pointer to another publication. * @param Mirror A mirror, having a pointer to another publication, but no URI or collect module. * @param Nonexistent An indicator showing the queried publication does not exist. */ enum PubType { Post, Comment, Mirror, Nonexistent } /** * @notice A struct containing the necessary information to reconstruct an EIP-712 typed data signature. * * @param v The signature's recovery parameter. * @param r The signature's r parameter. * @param s The signature's s parameter * @param deadline The signature's deadline */ struct EIP712Signature { uint8 v; bytes32 r; bytes32 s; uint256 deadline; } /** * @notice A struct containing profile data. * * @param pubCount The number of publications made to this profile. * @param followModule The address of the current follow module in use by this profile, can be empty. * @param followNFT The address of the followNFT associated with this profile, can be empty.. * @param handle The profile's associated handle. * @param imageURI The URI to be used for the profile's image. * @param followNFTURI The URI to be used for the follow NFT. */ struct ProfileStruct { uint256 pubCount; address followModule; address followNFT; string handle; string imageURI; string followNFTURI; } /** * @notice A struct containing data associated with each new publication. * * @param profileIdPointed The profile token ID this publication points to, for mirrors and comments. * @param pubIdPointed The publication ID this publication points to, for mirrors and comments. * @param contentURI The URI associated with this publication. * @param referenceModule The address of the current reference module in use by this profile, can be empty. * @param collectModule The address of the collect module associated with this publication, this exists for all publication. * @param collectNFT The address of the collectNFT associated with this publication, if any. */ struct PublicationStruct { uint256 profileIdPointed; uint256 pubIdPointed; string contentURI; address referenceModule; address collectModule; address collectNFT; } /** * @notice A struct containing the parameters required for the `createProfile()` function. * * @param to The address receiving the profile. * @param handle The handle to set for the profile, must be unique and non-empty. * @param imageURI The URI to set for the profile image. * @param followModule The follow module to use, can be the zero address. * @param followModuleInitData The follow module initialization data, if any. * @param followNFTURI The URI to use for the follow NFT. */ struct CreateProfileData { address to; string handle; string imageURI; address followModule; bytes followModuleInitData; string followNFTURI; } /** * @notice A struct containing the parameters required for the `setDefaultProfileWithSig()` function. Parameters are * the same as the regular `setDefaultProfile()` function, with an added EIP712Signature. * * @param wallet The address of the wallet setting the default profile. * @param profileId The token ID of the profile which will be set as default, or zero. * @param sig The EIP712Signature struct containing the profile owner's signature. */ struct SetDefaultProfileWithSigData { address wallet; uint256 profileId; EIP712Signature sig; } /** * @notice A struct containing the parameters required for the `setFollowModuleWithSig()` function. Parameters are * the same as the regular `setFollowModule()` function, with an added EIP712Signature. * * @param profileId The token ID of the profile to change the followModule for. * @param followModule The followModule to set for the given profile, must be whitelisted. * @param followModuleInitData The data to be passed to the followModule for initialization. * @param sig The EIP712Signature struct containing the profile owner's signature. */ struct SetFollowModuleWithSigData { uint256 profileId; address followModule; bytes followModuleInitData; EIP712Signature sig; } /** * @notice A struct containing the parameters required for the `setDispatcherWithSig()` function. Parameters are the same * as the regular `setDispatcher()` function, with an added EIP712Signature. * * @param profileId The token ID of the profile to set the dispatcher for. * @param dispatcher The dispatcher address to set for the profile. * @param sig The EIP712Signature struct containing the profile owner's signature. */ struct SetDispatcherWithSigData { uint256 profileId; address dispatcher; EIP712Signature sig; } /** * @notice A struct containing the parameters required for the `setProfileImageURIWithSig()` function. Parameters are the same * as the regular `setProfileImageURI()` function, with an added EIP712Signature. * * @param profileId The token ID of the profile to set the URI for. * @param imageURI The URI to set for the given profile image. * @param sig The EIP712Signature struct containing the profile owner's signature. */ struct SetProfileImageURIWithSigData { uint256 profileId; string imageURI; EIP712Signature sig; } /** * @notice A struct containing the parameters required for the `setFollowNFTURIWithSig()` function. Parameters are the same * as the regular `setFollowNFTURI()` function, with an added EIP712Signature. * * @param profileId The token ID of the profile for which to set the followNFT URI. * @param followNFTURI The follow NFT URI to set. * @param sig The EIP712Signature struct containing the followNFT's associated profile owner's signature. */ struct SetFollowNFTURIWithSigData { uint256 profileId; string followNFTURI; EIP712Signature sig; } /** * @notice A struct containing the parameters required for the `post()` function. * * @param profileId The token ID of the profile to publish to. * @param contentURI The URI to set for this new publication. * @param collectModule The collect module to set for this new publication. * @param collectModuleInitData The data to pass to the collect module's initialization. * @param referenceModule The reference module to set for the given publication, must be whitelisted. * @param referenceModuleInitData The data to be passed to the reference module for initialization. */ struct PostData { uint256 profileId; string contentURI; address collectModule; bytes collectModuleInitData; address referenceModule; bytes referenceModuleInitData; } /** * @notice A struct containing the parameters required for the `postWithSig()` function. Parameters are the same as * the regular `post()` function, with an added EIP712Signature. * * @param profileId The token ID of the profile to publish to. * @param contentURI The URI to set for this new publication. * @param collectModule The collectModule to set for this new publication. * @param collectModuleInitData The data to pass to the collectModule's initialization. * @param referenceModule The reference module to set for the given publication, must be whitelisted. * @param referenceModuleInitData The data to be passed to the reference module for initialization. * @param sig The EIP712Signature struct containing the profile owner's signature. */ struct PostWithSigData { uint256 profileId; string contentURI; address collectModule; bytes collectModuleInitData; address referenceModule; bytes referenceModuleInitData; EIP712Signature sig; } /** * @notice A struct containing the parameters required for the `comment()` function. * * @param profileId The token ID of the profile to publish to. * @param contentURI The URI to set for this new publication. * @param profileIdPointed The profile token ID to point the comment to. * @param pubIdPointed The publication ID to point the comment to. * @param referenceModuleData The data passed to the reference module. * @param collectModule The collect module to set for this new publication. * @param collectModuleInitData The data to pass to the collect module's initialization. * @param referenceModule The reference module to set for the given publication, must be whitelisted. * @param referenceModuleInitData The data to be passed to the reference module for initialization. */ struct CommentData { uint256 profileId; string contentURI; uint256 profileIdPointed; uint256 pubIdPointed; bytes referenceModuleData; address collectModule; bytes collectModuleInitData; address referenceModule; bytes referenceModuleInitData; } /** * @notice A struct containing the parameters required for the `commentWithSig()` function. Parameters are the same as * the regular `comment()` function, with an added EIP712Signature. * * @param profileId The token ID of the profile to publish to. * @param contentURI The URI to set for this new publication. * @param profileIdPointed The profile token ID to point the comment to. * @param pubIdPointed The publication ID to point the comment to. * @param referenceModuleData The data passed to the reference module. * @param collectModule The collectModule to set for this new publication. * @param collectModuleInitData The data to pass to the collectModule's initialization. * @param referenceModule The reference module to set for the given publication, must be whitelisted. * @param referenceModuleInitData The data to be passed to the reference module for initialization. * @param sig The EIP712Signature struct containing the profile owner's signature. */ struct CommentWithSigData { uint256 profileId; string contentURI; uint256 profileIdPointed; uint256 pubIdPointed; bytes referenceModuleData; address collectModule; bytes collectModuleInitData; address referenceModule; bytes referenceModuleInitData; EIP712Signature sig; } /** * @notice A struct containing the parameters required for the `mirror()` function. * * @param profileId The token ID of the profile to publish to. * @param profileIdPointed The profile token ID to point the mirror to. * @param pubIdPointed The publication ID to point the mirror to. * @param referenceModuleData The data passed to the reference module. * @param referenceModule The reference module to set for the given publication, must be whitelisted. * @param referenceModuleInitData The data to be passed to the reference module for initialization. */ struct MirrorData { uint256 profileId; uint256 profileIdPointed; uint256 pubIdPointed; bytes referenceModuleData; address referenceModule; bytes referenceModuleInitData; } /** * @notice A struct containing the parameters required for the `mirrorWithSig()` function. Parameters are the same as * the regular `mirror()` function, with an added EIP712Signature. * * @param profileId The token ID of the profile to publish to. * @param profileIdPointed The profile token ID to point the mirror to. * @param pubIdPointed The publication ID to point the mirror to. * @param referenceModuleData The data passed to the reference module. * @param referenceModule The reference module to set for the given publication, must be whitelisted. * @param referenceModuleInitData The data to be passed to the reference module for initialization. * @param sig The EIP712Signature struct containing the profile owner's signature. */ struct MirrorWithSigData { uint256 profileId; uint256 profileIdPointed; uint256 pubIdPointed; bytes referenceModuleData; address referenceModule; bytes referenceModuleInitData; EIP712Signature sig; } /** * @notice A struct containing the parameters required for the `followWithSig()` function. Parameters are the same * as the regular `follow()` function, with the follower's (signer) address and an EIP712Signature added. * * @param follower The follower which is the message signer. * @param profileIds The array of token IDs of the profiles to follow. * @param datas The array of arbitrary data to pass to the followModules if needed. * @param sig The EIP712Signature struct containing the follower's signature. */ struct FollowWithSigData { address follower; uint256[] profileIds; bytes[] datas; EIP712Signature sig; } /** * @notice A struct containing the parameters required for the `collectWithSig()` function. Parameters are the same as * the regular `collect()` function, with the collector's (signer) address and an EIP712Signature added. * * @param collector The collector which is the message signer. * @param profileId The token ID of the profile that published the publication to collect. * @param pubId The publication to collect's publication ID. * @param data The arbitrary data to pass to the collectModule if needed. * @param sig The EIP712Signature struct containing the collector's signature. */ struct CollectWithSigData { address collector; uint256 profileId; uint256 pubId; bytes data; EIP712Signature sig; } /** * @notice A struct containing the parameters required for the `setProfileMetadataWithSig()` function. * * @param profileId The profile ID for which to set the metadata. * @param metadata The metadata string to set for the profile and user. * @param sig The EIP712Signature struct containing the user's signature. */ struct SetProfileMetadataWithSigData { uint256 profileId; string metadata; EIP712Signature sig; } /** * @notice A struct containing the parameters required for the `toggleFollowWithSig()` function. * * @param follower The follower which is the message signer. * @param profileIds The token ID array of the profiles. * @param enables The array of booleans to enable/disable follows. * @param sig The EIP712Signature struct containing the follower's signature. */ struct ToggleFollowWithSigData { address follower; uint256[] profileIds; bool[] enables; EIP712Signature sig; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import {DataTypes} from '../libraries/DataTypes.sol'; /** * @title ILensNFTBase * @author Lens Protocol * * @notice This is the interface for the LensNFTBase contract, from which all Lens NFTs inherit. * It is an expansion of a very slightly modified ERC721Enumerable contract, which allows expanded * meta-transaction functionality. */ interface ILensNFTBase { /** * @notice Implementation of an EIP-712 permit function for an ERC-721 NFT. We don't need to check * if the tokenId exists, since the function calls ownerOf(tokenId), which reverts if the tokenId does * not exist. * * @param spender The NFT spender. * @param tokenId The NFT token ID to approve. * @param sig The EIP712 signature struct. */ function permit( address spender, uint256 tokenId, DataTypes.EIP712Signature calldata sig ) external; /** * @notice Implementation of an EIP-712 permit-style function for ERC-721 operator approvals. Allows * an operator address to control all NFTs a given owner owns. * * @param owner The owner to set operator approvals for. * @param operator The operator to approve. * @param approved Whether to approve or revoke approval from the operator. * @param sig The EIP712 signature struct. */ function permitForAll( address owner, address operator, bool approved, DataTypes.EIP712Signature calldata sig ) external; /** * @notice Burns an NFT, removing it from circulation and essentially destroying it. This function can only * be called by the NFT to burn's owner. * * @param tokenId The token ID of the token to burn. */ function burn(uint256 tokenId) external; /** * @notice Implementation of an EIP-712 permit-style function for token burning. Allows anyone to burn * a token on behalf of the owner with a signature. * * @param tokenId The token ID of the token to burn. * @param sig The EIP712 signature struct. */ function burnWithSig(uint256 tokenId, DataTypes.EIP712Signature calldata sig) external; /** * @notice Returns the domain separator for this NFT contract. * * @return bytes32 The domain separator. */ function getDomainSeparator() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import './IERC721Time.sol'; import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol'; import '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol'; import '@openzeppelin/contracts/utils/Address.sol'; import '@openzeppelin/contracts/utils/Context.sol'; import '@openzeppelin/contracts/utils/Strings.sol'; import '@openzeppelin/contracts/utils/introspection/ERC165.sol'; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. * * Modifications: * 1. Refactored _operatorApprovals setter into an internal function to allow meta-transactions. * 2. Constructor replaced with an initializer. * 3. Mint timestamp is now stored in a TokenData struct alongside the owner address. */ abstract contract ERC721Time is Context, ERC165, IERC721Time, IERC721Metadata { using Address for address; using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to token Data (owner address and mint timestamp uint96), this // replaces the original mapping(uint256 => address) private _owners; mapping(uint256 => IERC721Time.TokenData) private _tokenData; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the ERC721 name and symbol. * * @param name The name to set. * @param symbol The symbol to set. */ function __ERC721_Init(string calldata name, string calldata symbol) internal { _name = name; _symbol = symbol; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), 'ERC721: balance query for the zero address'); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _tokenData[tokenId].owner; require(owner != address(0), 'ERC721: owner query for nonexistent token'); return owner; } /** * @dev See {IERC721Time-mintTimestampOf} */ function mintTimestampOf(uint256 tokenId) public view virtual override returns (uint256) { uint96 mintTimestamp = _tokenData[tokenId].mintTimestamp; require(mintTimestamp != 0, 'ERC721: mint timestamp query for nonexistent token'); return mintTimestamp; } /** * @dev See {IERC721Time-mintTimestampOf} */ function tokenDataOf(uint256 tokenId) public view virtual override returns (IERC721Time.TokenData memory) { require(_exists(tokenId), 'ERC721: token data query for nonexistent token'); return _tokenData[tokenId]; } /** * @dev See {IERC721Time-exists} */ function exists(uint256 tokenId) public view virtual override returns (bool) { return _exists(tokenId); } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { require(_exists(tokenId), 'ERC721Metadata: URI query for nonexistent token'); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ''; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overriden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ''; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721Time.ownerOf(tokenId); require(to != owner, 'ERC721: approval to current owner'); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), 'ERC721: approve caller is not owner nor approved for all' ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { require(_exists(tokenId), 'ERC721: approved query for nonexistent token'); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { require(operator != _msgSender(), 'ERC721: approve to caller'); _setOperatorApproval(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require( _isApprovedOrOwner(_msgSender(), tokenId), 'ERC721: transfer caller is not owner nor approved' ); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ''); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory _data ) public virtual override { require( _isApprovedOrOwner(_msgSender(), tokenId), 'ERC721: transfer caller is not owner nor approved' ); _safeTransfer(from, to, tokenId, _data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `_data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory _data ) internal virtual { _transfer(from, to, tokenId); require( _checkOnERC721Received(from, to, tokenId, _data), 'ERC721: transfer to non ERC721Receiver implementer' ); } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _tokenData[tokenId].owner != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { require(_exists(tokenId), 'ERC721: operator query for nonexistent token'); address owner = ERC721Time.ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ''); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint( address to, uint256 tokenId, bytes memory _data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, _data), 'ERC721: transfer to non ERC721Receiver implementer' ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), 'ERC721: mint to the zero address'); require(!_exists(tokenId), 'ERC721: token already minted'); _beforeTokenTransfer(address(0), to, tokenId); _balances[to] += 1; _tokenData[tokenId].owner = to; _tokenData[tokenId].mintTimestamp = uint96(block.timestamp); emit Transfer(address(0), to, tokenId); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721Time.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId); // Clear approvals _approve(address(0), tokenId); _balances[owner] -= 1; delete _tokenData[tokenId]; emit Transfer(owner, address(0), tokenId); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721Time.ownerOf(tokenId) == from, 'ERC721: transfer of token that is not own'); require(to != address(0), 'ERC721: transfer to the zero address'); _beforeTokenTransfer(from, to, tokenId); // Clear approvals from the previous owner _approve(address(0), tokenId); _balances[from] -= 1; _balances[to] += 1; _tokenData[tokenId].owner = to; emit Transfer(from, to, tokenId); } /** * @dev Approve `to` to operate on `tokenId` * * Emits a {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721Time.ownerOf(tokenId), to, tokenId); } /** * @dev Refactored from the original OZ ERC721 implementation: approve or revoke approval from * `operator` to operate on all tokens owned by `owner`. * * Emits a {ApprovalForAll} event. */ function _setOperatorApproval( address owner, address operator, bool approved ) internal virtual { _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns ( bytes4 retval ) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert('ERC721: transfer to non ERC721Receiver implementer'); } else { assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import './ERC721Time.sol'; import '@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol'; /** * @dev This implements an optional extension of {ERC721} defined in the EIP that adds * enumerability of all the token ids in the contract as well as all token ids owned by each * account. * * NOTE: Modified from Openzeppelin to inherit from a modified ERC721 contract. */ abstract contract ERC721Enumerable is ERC721Time, IERC721Enumerable { // Mapping from owner to list of owned token IDs mapping(address => mapping(uint256 => uint256)) private _ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) private _ownedTokensIndex; // Array with all token ids, used for enumeration uint256[] private _allTokens; // Mapping from token id to position in the allTokens array mapping(uint256 => uint256) private _allTokensIndex; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721Time) returns (bool) { return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. */ function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { require(index < ERC721Time.balanceOf(owner), 'ERC721Enumerable: owner index out of bounds'); return _ownedTokens[owner][index]; } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _allTokens.length; } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view virtual override returns (uint256) { require( index < ERC721Enumerable.totalSupply(), 'ERC721Enumerable: global index out of bounds' ); return _allTokens[index]; } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` cannot be the zero address. * - `to` cannot be the zero address. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual override { super._beforeTokenTransfer(from, to, tokenId); if (from == address(0)) { _addTokenToAllTokensEnumeration(tokenId); } else if (from != to) { _removeTokenFromOwnerEnumeration(from, tokenId); } if (to == address(0)) { _removeTokenFromAllTokensEnumeration(tokenId); } else if (to != from) { _addTokenToOwnerEnumeration(to, tokenId); } } /** * @dev Private function to add a token to this extension's ownership-tracking data structures. * @param to address representing the new owner of the given token ID * @param tokenId uint256 ID of the token to be added to the tokens list of the given address */ function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { uint256 length = ERC721Time.balanceOf(to); _ownedTokens[to][length] = tokenId; _ownedTokensIndex[tokenId] = length; } /** * @dev Private function to add a token to this extension's token tracking data structures. * @param tokenId uint256 ID of the token to be added to the tokens list */ function _addTokenToAllTokensEnumeration(uint256 tokenId) private { _allTokensIndex[tokenId] = _allTokens.length; _allTokens.push(tokenId); } /** * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for * gas optimizations e.g. when performing a transfer operation (avoiding double writes). * This has O(1) time complexity, but alters the order of the _ownedTokens array. * @param from address representing the previous owner of the given token ID * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address */ function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = ERC721Time.balanceOf(from) - 1; uint256 tokenIndex = _ownedTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary if (tokenIndex != lastTokenIndex) { uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index } // This also deletes the contents at the last position of the array delete _ownedTokensIndex[tokenId]; delete _ownedTokens[from][lastTokenIndex]; } /** * @dev Private function to remove a token from this extension's token tracking data structures. * This has O(1) time complexity, but alters the order of the _allTokens array. * @param tokenId uint256 ID of the token to be removed from the tokens list */ function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = _allTokens.length - 1; uint256 tokenIndex = _allTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding // an 'if' statement (like in _removeTokenFromOwnerEnumeration) uint256 lastTokenId = _allTokens[lastTokenIndex]; _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index // This also deletes the contents at the last position of the array delete _allTokensIndex[tokenId]; _allTokens.pop(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import '@openzeppelin/contracts/token/ERC721/IERC721.sol'; /** * @title IERC721Time * @author Lens Protocol * * @notice This is an expansion of the IERC721 interface that includes a struct for token data, * which contains the token owner and the mint timestamp as well as associated getters. */ interface IERC721Time is IERC721 { /** * @notice Contains the owner address and the mint timestamp for every NFT. * * Note: Instead of the owner address in the _tokenOwners private mapping, we now store it in the * _tokenData mapping, alongside the unchanging mintTimestamp. * * @param owner The token owner. * @param mintTimestamp The mint timestamp. */ struct TokenData { address owner; uint96 mintTimestamp; } /** * @notice Returns the mint timestamp associated with a given NFT, stored only once upon initial mint. * * @param tokenId The token ID of the NFT to query the mint timestamp for. * * @return uint256 mint timestamp, this is stored as a uint96 but returned as a uint256 to reduce unnecessary * padding. */ function mintTimestampOf(uint256 tokenId) external view returns (uint256); /** * @notice Returns the token data associated with a given NFT. This allows fetching the token owner and * mint timestamp in a single call. * * @param tokenId The token ID of the NFT to query the token data for. * * @return TokenData token data struct containing both the owner address and the mint timestamp. */ function tokenDataOf(uint256 tokenId) external view returns (TokenData memory); /** * @notice Returns whether a token with the given token ID exists. * * @param tokenId The token ID of the NFT to check existence for. * * @return bool True if the token exists. */ function exists(uint256 tokenId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./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); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); }
{ "optimizer": { "enabled": true, "runs": 200, "details": { "yul": true } }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"hub","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InitParamsInvalid","type":"error"},{"inputs":[],"name":"Initialized","type":"error"},{"inputs":[],"name":"NotHub","type":"error"},{"inputs":[],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[],"name":"SignatureExpired","type":"error"},{"inputs":[],"name":"SignatureInvalid","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"ZeroSpender","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"HUB","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct DataTypes.EIP712Signature","name":"sig","type":"tuple"}],"name":"burnWithSig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDomainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSourcePublicationPointer","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"profileId","type":"uint256"},{"internalType":"uint256","name":"pubId","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mintTimestampOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct DataTypes.EIP712Signature","name":"sig","type":"tuple"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct DataTypes.EIP712Signature","name":"sig","type":"tuple"}],"name":"permitForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"sigNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenDataOf","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint96","name":"mintTimestamp","type":"uint96"}],"internalType":"struct IERC721Time.TokenData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b50604051620024733803806200247383398101604081905262000034916200007b565b6001600160a01b0381166200005c576040516348be0eb360e01b815260040160405180910390fd5b6001600160a01b0316608052600e805460ff19166001179055620000ad565b6000602082840312156200008e57600080fd5b81516001600160a01b0381168114620000a657600080fd5b9392505050565b608051612395620000de6000396000818161039501528181610a4b01528181610e7d01526117e301526123956000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c80636352211e11610104578063a4c52b86116100a2578063dd69cdb111610071578063dd69cdb11461041d578063e985e9c514610430578063ed24911d1461046c578063f990ccd71461047457600080fd5b8063a4c52b8614610390578063b88d4fde146103b7578063c0da9bcd146103ca578063c87b56dd1461040a57600080fd5b80637ef67f99116100de5780637ef67f991461034f57806389028a131461036257806395d89b4114610375578063a22cb4651461037d57600080fd5b80636352211e146103165780636a6278421461032957806370a082311461033c57600080fd5b80633a755ed11161017157806342966c681161014b57806342966c68146102ca5780634f558e79146102dd5780634f6ccce7146102f057806350ddf35c1461030357600080fd5b80633a755ed1146102895780633fa78c0a146102a457806342842e0e146102b757600080fd5b8063095ea7b3116101ad578063095ea7b31461023c57806318160ddd1461025157806323b872dd146102635780632f745c591461027657600080fd5b806301ffc9a7146101d457806306fdde03146101fc578063081812fc14610211575b600080fd5b6101e76101e2366004611c59565b610494565b60405190151581526020015b60405180910390f35b6102046104bf565b6040516101f39190611cd5565b61022461021f366004611ce8565b610551565b6040516001600160a01b0390911681526020016101f3565b61024f61024a366004611d1d565b6105de565b005b6008545b6040519081526020016101f3565b61024f610271366004611d47565b6106f4565b610255610284366004611d1d565b610725565b600b54600c54604080519283526020830191909152016101f3565b61024f6102b2366004611dcc565b6107bb565b61024f6102c5366004611d47565b610845565b61024f6102d8366004611ce8565b610860565b6101e76102eb366004611ce8565b610893565b6102556102fe366004611ce8565b61089e565b610255610311366004611ce8565b610931565b610224610324366004611ce8565b6109c7565b610255610337366004611e4f565b610a3e565b61025561034a366004611e4f565b610a9e565b61024f61035d366004611e82565b610b25565b61024f610370366004611ecf565b610c0b565b610204610cd0565b61024f61038b366004611f24565b610cdf565b6102247f000000000000000000000000000000000000000000000000000000000000000081565b61024f6103c5366004611fc6565b610d47565b6103dd6103d8366004611ce8565b610d79565b6040805182516001600160a01b031681526020928301516001600160601b031692810192909252016101f3565b610204610418366004611ce8565b610e38565b61024f61042b366004612071565b610efe565b6101e761043e366004612095565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b610255610f8c565b610255610482366004611e4f565b600a6020526000908152604090205481565b60006001600160e01b0319821663780e9d6360e01b14806104b957506104b982610f9b565b92915050565b6060600080546104ce906120bf565b80601f01602080910402602001604051908101604052809291908181526020018280546104fa906120bf565b80156105475780601f1061051c57610100808354040283529160200191610547565b820191906000526020600020905b81548152906001019060200180831161052a57829003601f168201915b5050505050905090565b600061055c82610feb565b6105c25760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b60006105e9826109c7565b9050806001600160a01b0316836001600160a01b031614156106575760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084016105b9565b336001600160a01b03821614806106735750610673813361043e565b6106e55760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c000000000000000060648201526084016105b9565b6106ef8383611008565b505050565b6106fe3382611076565b61071a5760405162461bcd60e51b81526004016105b9906120f4565b6106ef838383611160565b600061073083610a9e565b82106107925760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b60648201526084016105b9565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b600e5460ff16156107df576040516302ed543d60e51b815260040160405180910390fd5b600e805460ff19166001179055600b869055600c8590556108028484848461130b565b84867f898a2dec95856255977a0fb48cebc30051d50c0d8d33f93dea1e3ddb2e3424424260405161083591815260200190565b60405180910390a3505050505050565b6106ef83838360405180602001604052806000815250610d47565b61086a3382611076565b61088757604051636d8a29e760e11b815260040160405180910390fd5b6108908161135c565b50565b60006104b982610feb565b60006108a960085490565b821061090c5760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b60648201526084016105b9565b6008828154811061091f5761091f612145565b90600052602060002001549050919050565b600081815260026020526040812054600160a01b90046001600160601b0316806109b85760405162461bcd60e51b815260206004820152603260248201527f4552433732313a206d696e742074696d657374616d7020717565727920666f72604482015271103737b732bc34b9ba32b73a103a37b5b2b760711b60648201526084016105b9565b6001600160601b031692915050565b6000818152600260205260408120546001600160a01b0316806104b95760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b60648201526084016105b9565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a89576040516313bd2e8360e31b815260040160405180910390fd5b600d8054600101908190556104b983826113f8565b60006001600160a01b038216610b095760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b60648201526084016105b9565b506001600160a01b031660009081526003602052604090205490565b6001600160a01b038316610b4c576040516307eb16dd60e21b815260040160405180910390fd5b6000610b57836109c7565b6001600160a01b038181166000908152600a602090815260409182902080546001810190915582517f49ecf333e5b8c95c40fdafc95c1ad136e8914a8fb55e9dc8bb01eaa83a2df9ad9281019290925292881691810191909152606080820187905260808201929092529084013560a0820152909150610bfb90610bf49060c0015b6040516020818303038152906040528051906020012061153a565b8284611584565b610c058484611008565b50505050565b6001600160a01b038316610c32576040516307eb16dd60e21b815260040160405180910390fd5b6001600160a01b038481166000818152600a602090815260409182902080546001810190915582517f47ab88482c90e4bb94b82a947ae78fa91fb25de1469ab491f4c15b9a0a2677ee9281019290925291810192909252918516606080830191909152841515608083015260a08201929092529082013560c0820152610cc590610cbe9060e001610bd9565b8583611584565b610c05848484611662565b6060600180546104ce906120bf565b6001600160a01b038216331415610d385760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c65720000000000000060448201526064016105b9565b610d43338383611662565b5050565b610d513383611076565b610d6d5760405162461bcd60e51b81526004016105b9906120f4565b610c05848484846116cf565b6040805180820190915260008082526020820152610d9682610feb565b610df95760405162461bcd60e51b815260206004820152602e60248201527f4552433732313a20746f6b656e206461746120717565727920666f72206e6f6e60448201526d32bc34b9ba32b73a103a37b5b2b760911b60648201526084016105b9565b506000908152600260209081526040918290208251808401909352546001600160a01b0381168352600160a01b90046001600160601b03169082015290565b6060610e4382610feb565b610e605760405163677510db60e11b815260040160405180910390fd5b600b54600c54604051635ad18a4b60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263b5a3149692610eb992600401918252602082015260400190565b600060405180830381865afa158015610ed6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104b9919081019061215b565b6000610f09836109c7565b6001600160a01b0381166000908152600a602090815260409182902080546001810190915582517f108ccda6d7331b00561a3eea66a2ae331622356585681c62731e4a01aae2261a92810192909252918101869052606080820192909252908401356080820152909150610f8390610bf49060a001610bd9565b6106ef8361135c565b6000610f96611702565b905090565b60006001600160e01b031982166380ac58cd60e01b1480610fcc57506001600160e01b03198216635b5e139f60e01b145b806104b957506301ffc9a760e01b6001600160e01b03198316146104b9565b6000908152600260205260409020546001600160a01b0316151590565b600081815260046020526040902080546001600160a01b0319166001600160a01b038416908117909155819061103d826109c7565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600061108182610feb565b6110e25760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084016105b9565b60006110ed836109c7565b9050806001600160a01b0316846001600160a01b031614806111285750836001600160a01b031661111d84610551565b6001600160a01b0316145b8061115857506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b949350505050565b826001600160a01b0316611173826109c7565b6001600160a01b0316146111db5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b60648201526084016105b9565b6001600160a01b03821661123d5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b60648201526084016105b9565b611248838383611797565b611253600082611008565b6001600160a01b038316600090815260036020526040812080546001929061127c9084906121e8565b90915550506001600160a01b03821660009081526003602052604081208054600192906112aa9084906121ff565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61131784848484611844565b7f414cd0b34676984f09a5f76ce9718d4062e50283abe0e7e274a9a5b4e0c99c30848484844260405161134e959493929190612240565b60405180910390a150505050565b6000611367826109c7565b905061137581600084611797565b611380600083611008565b6001600160a01b03811660009081526003602052604081208054600192906113a99084906121e8565b9091555050600082815260026020526040808220829055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6001600160a01b03821661144e5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f206164647265737360448201526064016105b9565b61145781610feb565b156114a45760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000060448201526064016105b9565b6114b060008383611797565b6001600160a01b03821660009081526003602052604081208054600192906114d99084906121ff565b90915550506000818152600260205260408082206001600160a01b038516600160a01b426001600160601b031602811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b600080611545611702565b60405161190160f01b602082015260228101919091526042810184905260620160408051601f1981840301815291905280516020909101209392505050565b42816060013510156115a957604051630819bdcd60e01b815260040160405180910390fd5b60006001846115bb602085018561227a565b604080516000815260208181018084529490945260ff9092168282015291850135606082015290840135608082015260a0016020604051602081039080840390855afa15801561160f573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615806116445750826001600160a01b0316816001600160a01b031614155b15610c05576040516337e8456b60e01b815260040160405180910390fd5b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6116da848484611160565b6116e684848484611864565b610c055760405162461bcd60e51b81526004016105b99061229d565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61172d6104bf565b80516020918201206040805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6117a2838383611962565b600b54600c546040516386e2947b60e01b815260048101929092526024820152604481018290526001600160a01b03848116606483015283811660848301527f000000000000000000000000000000000000000000000000000000000000000016906386e2947b9060a401600060405180830381600087803b15801561182757600080fd5b505af115801561183b573d6000803e3d6000fd5b50505050505050565b61185060008585611baa565b5061185d60018383611baa565b5050505050565b60006001600160a01b0384163b1561195757604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906118a89033908990889088906004016122ef565b6020604051808303816000875af19250505080156118e3575060408051601f3d908101601f191682019092526118e09181019061232c565b60015b61193d573d808015611911576040519150601f19603f3d011682016040523d82523d6000602084013e611916565b606091505b5080516119355760405162461bcd60e51b81526004016105b99061229d565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611158565b506001949350505050565b6001600160a01b0383166119bd576119b881600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b6119e0565b816001600160a01b0316836001600160a01b0316146119e0576119e08382611a1a565b6001600160a01b0382166119f7576106ef81611ab7565b826001600160a01b0316826001600160a01b0316146106ef576106ef8282611b66565b60006001611a2784610a9e565b611a3191906121e8565b600083815260076020526040902054909150808214611a84576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b600854600090611ac9906001906121e8565b60008381526009602052604081205460088054939450909284908110611af157611af1612145565b906000526020600020015490508060088381548110611b1257611b12612145565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480611b4a57611b4a612349565b6001900381819060005260206000200160009055905550505050565b6000611b7183610a9e565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b828054611bb6906120bf565b90600052602060002090601f016020900481019282611bd85760008555611c1e565b82601f10611bf15782800160ff19823516178555611c1e565b82800160010185558215611c1e579182015b82811115611c1e578235825591602001919060010190611c03565b50611c2a929150611c2e565b5090565b5b80821115611c2a5760008155600101611c2f565b6001600160e01b03198116811461089057600080fd5b600060208284031215611c6b57600080fd5b8135611c7681611c43565b9392505050565b60005b83811015611c98578181015183820152602001611c80565b83811115610c055750506000910152565b60008151808452611cc1816020860160208601611c7d565b601f01601f19169290920160200192915050565b602081526000611c766020830184611ca9565b600060208284031215611cfa57600080fd5b5035919050565b80356001600160a01b0381168114611d1857600080fd5b919050565b60008060408385031215611d3057600080fd5b611d3983611d01565b946020939093013593505050565b600080600060608486031215611d5c57600080fd5b611d6584611d01565b9250611d7360208501611d01565b9150604084013590509250925092565b60008083601f840112611d9557600080fd5b50813567ffffffffffffffff811115611dad57600080fd5b602083019150836020828501011115611dc557600080fd5b9250929050565b60008060008060008060808789031215611de557600080fd5b8635955060208701359450604087013567ffffffffffffffff80821115611e0b57600080fd5b611e178a838b01611d83565b90965094506060890135915080821115611e3057600080fd5b50611e3d89828a01611d83565b979a9699509497509295939492505050565b600060208284031215611e6157600080fd5b611c7682611d01565b600060808284031215611e7c57600080fd5b50919050565b600080600060c08486031215611e9757600080fd5b611ea084611d01565b925060208401359150611eb68560408601611e6a565b90509250925092565b80358015158114611d1857600080fd5b60008060008060e08587031215611ee557600080fd5b611eee85611d01565b9350611efc60208601611d01565b9250611f0a60408601611ebf565b9150611f198660608701611e6a565b905092959194509250565b60008060408385031215611f3757600080fd5b611f4083611d01565b9150611f4e60208401611ebf565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611f9657611f96611f57565b604052919050565b600067ffffffffffffffff821115611fb857611fb8611f57565b50601f01601f191660200190565b60008060008060808587031215611fdc57600080fd5b611fe585611d01565b9350611ff360208601611d01565b925060408501359150606085013567ffffffffffffffff81111561201657600080fd5b8501601f8101871361202757600080fd5b803561203a61203582611f9e565b611f6d565b81815288602083850101111561204f57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b60008060a0838503121561208457600080fd5b82359150611f4e8460208501611e6a565b600080604083850312156120a857600080fd5b6120b183611d01565b9150611f4e60208401611d01565b600181811c908216806120d357607f821691505b60208210811415611e7c57634e487b7160e01b600052602260045260246000fd5b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561216d57600080fd5b815167ffffffffffffffff81111561218457600080fd5b8201601f8101841361219557600080fd5b80516121a361203582611f9e565b8181528560208385010111156121b857600080fd5b6121c9826020830160208601611c7d565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b6000828210156121fa576121fa6121d2565b500390565b60008219821115612212576122126121d2565b500190565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b606081526000612254606083018789612217565b8281036020840152612267818688612217565b9150508260408301529695505050505050565b60006020828403121561228c57600080fd5b813560ff81168114611c7657600080fd5b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061232290830184611ca9565b9695505050505050565b60006020828403121561233e57600080fd5b8151611c7681611c43565b634e487b7160e01b600052603160045260246000fdfea264697066735822122098c30e13d49f73116aef39d1275e641cf384d01f7e9652f8bbad45af2527f69c64736f6c634300080a0033000000000000000000000000db46d1dc155634fbc732f92e853b10b288ad5a1d
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000db46d1dc155634fbc732f92e853b10b288ad5a1d
-----Decoded View---------------
Arg [0] : hub (address): 0xdb46d1dc155634fbc732f92e853b10b288ad5a1d
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000db46d1dc155634fbc732f92e853b10b288ad5a1d
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.