// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)pragmasolidity ^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.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 2 of 8: EFPListMinter.sol
// SPDX-License-Identifier: UNLICENSEDpragmasolidity ^0.8.23;import {Ownable} from'lib/openzeppelin-contracts/contracts/access/Ownable.sol';
import {Pausable} from'lib/openzeppelin-contracts/contracts/security/Pausable.sol';
import {IEFPAccountMetadata} from'./interfaces/IEFPAccountMetadata.sol';
import {IEFPListRegistry} from'./interfaces/IEFPListRegistry.sol';
import {IEFPListRecords} from'./interfaces/IEFPListRecords.sol';
import {ENSReverseClaimer} from'./lib/ENSReverseClaimer.sol';
interfaceIEFPListRegistry_ERC721isIEFPListRegistry{
functionownerOf(uint256 tokenId) externalviewreturns (address);
functiontotalSupply() externalviewreturns (uint256);
}
/**
* @title EFPListMetadata
* @author Cory Gabrielsen (cory.eth)
* @custom:contributor throw; (0xthrpw.eth)
* @custom:benediction DEVS BENEDICAT ET PROTEGAT CONTRACTVS MEAM
*
* @notice This contract mints and assigns primary lists to users, and sets
* EFP List metadata.
*/contractEFPListMinterisENSReverseClaimer, Pausable{
IEFPListRegistry_ERC721 public registry;
IEFPAccountMetadata public accountMetadata;
IEFPListRecords public listRecordsL1;
constructor(address _registryAddress, address _accountMetadataAddress, address _listRecordsL1) {
registry = IEFPListRegistry_ERC721(_registryAddress);
accountMetadata = IEFPAccountMetadata(_accountMetadataAddress);
listRecordsL1 = IEFPListRecords(_listRecordsL1);
}
/////////////////////////////////////////////////////////////////////////////// Pausable//////////////////////////////////////////////////////////////////////////////**
* @dev Pauses the contract. Can only be called by the contract owner.
*/functionpause() publiconlyOwner{
_pause();
}
/**
* @dev Unpauses the contract. Can only be called by the contract owner.
*/functionunpause() publiconlyOwner{
_unpause();
}
/////////////////////////////////////////////////////////////////////////////// minting//////////////////////////////////////////////////////////////////////////////**
* @dev Decode a list storage location with no metadata.
* @param listStorageLocation The storage location of the list.
* @return slot The slot of the list.
* @return contractAddress The contract address of the list.
*/functiondecodeL1ListStorageLocation(bytescalldata listStorageLocation) internalpurereturns (uint256, address) {
// the list storage location is// - version (1 byte)// - list storate location type (1 byte)// - chain id (32 bytes)// - contract address (20 bytes)// - slot (32 bytes)require(listStorageLocation.length==1+1+32+20+32, 'EFPListMinter: invalid list storage location');
require(listStorageLocation[0] ==0x01, 'EFPListMinter: invalid list storage location version');
require(listStorageLocation[1] ==0x01, 'EFPListMinter: invalid list storage location type');
address contractAddress = _bytesToAddress(listStorageLocation, 34);
uint256 slot = _bytesToUint(listStorageLocation, 54);
return (slot, contractAddress);
}
/**
* @dev Mint a primary list.
* @param listStorageLocation The storage location of the list.
*/functioneasyMint(bytescalldata listStorageLocation) publicpayablewhenNotPaused{
// validate the list storage location
(uint256 slot, address recordsContract) = decodeL1ListStorageLocation(listStorageLocation);
uint256 tokenId = registry.totalSupply();
registry.mintTo{value: msg.value}(msg.sender, listStorageLocation);
_setDefaultListForAccount(msg.sender, tokenId);
if (recordsContract ==address(listRecordsL1)) {
listRecordsL1.setListUser(slot, msg.sender);
listRecordsL1.setListManager(slot, msg.sender);
}
}
/**
* @dev Mint a primary list to a specific address.
* @param to The address to mint the list to.
* @param listStorageLocation The storage location of the list.
*/functioneasyMintTo(address to, bytescalldata listStorageLocation) publicpayablewhenNotPaused{
// validate the list storage location
(uint256 slot, address recordsContract) = decodeL1ListStorageLocation(listStorageLocation);
uint256 tokenId = registry.totalSupply();
registry.mintTo{value: msg.value}(to, listStorageLocation);
_setDefaultListForAccount(msg.sender, tokenId);
if (recordsContract ==address(listRecordsL1)) {
listRecordsL1.setListUser(slot, msg.sender);
listRecordsL1.setListManager(slot, msg.sender);
}
}
/**
* @dev Mint a primary list without metadata.
* @param listStorageLocation The storage location of the list.
*/functionmintPrimaryListNoMeta(bytescalldata listStorageLocation) publicpayablewhenNotPaused{
// validate the list storage location
decodeL1ListStorageLocation(listStorageLocation);
uint256 tokenId = registry.totalSupply();
_setDefaultListForAccount(msg.sender, tokenId);
registry.mintTo{value: msg.value}(msg.sender, listStorageLocation);
}
/**
* @dev Mint a primary list without metadata to a specific address.
* @param listStorageLocation The storage location of the list.
*/functionmintNoMeta(bytescalldata listStorageLocation) publicpayablewhenNotPaused{
// validate the list storage location
decodeL1ListStorageLocation(listStorageLocation);
registry.mintTo{value: msg.value}(msg.sender, listStorageLocation);
}
/**
* @dev Mint a primary list without metadata to a specific address.
* @param to The address to mint the list to.
* @param listStorageLocation The storage location of the list.
*/functionmintToNoMeta(address to, bytescalldata listStorageLocation) publicpayablewhenNotPaused{
// validate the list storage location
decodeL1ListStorageLocation(listStorageLocation);
registry.mintTo{value: msg.value}(to, listStorageLocation);
}
/**
* @dev Set the default list for an account.
* @param to The address to set the default list for.
* @param tokenId The token ID of the list.
*/function_setDefaultListForAccount(address to, uint256 tokenId) internal{
accountMetadata.setValueForAddress(to, 'primary-list', abi.encodePacked(tokenId));
}
function_getChainId() internalviewreturns (uint256) {
uint256 id;
assembly {
id :=chainid()
}
return id;
}
// Generalized function to convert bytes to uint256 with a given offsetfunction_bytesToUint(bytesmemory data, uint256 offset) internalpurereturns (uint256) {
require(data.length>= offset +32, 'Data too short');
uint256 value;
assembly {
value :=mload(add(data, add(32, offset)))
}
return value;
}
// Helper function to convert bytes to address with a given offsetfunction_bytesToAddress(bytesmemory data, uint256 offset) internalpurereturns (address addr) {
require(data.length>= offset +20, 'Data too short');
assembly {
// Extract 20 bytes from the specified offset
addr :=mload(add(add(data, 20), offset))
// clear the 12 least significant bits of the address
addr :=and(addr, 0x000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
}
return addr;
}
}
Contract Source Code
File 3 of 8: ENSReverseClaimer.sol
//SPDX-License-Identifier: MITpragmasolidity ^0.8.23;import {Ownable} from'lib/openzeppelin-contracts/contracts/access/Ownable.sol';
interfaceENS{
/**
* @dev Returns the address that owns the specified node.
* @param node The specified node.
* @return address of the owner.
*/functionowner(bytes32 node) externalviewreturns (address);
}
interfaceIReverseRegistrar{
/**
* @dev Transfers ownership of the reverse ENS record associated with the
* calling account.
* @param owner The address to set as the owner of the reverse record in ENS.
* @return The ENS node hash of the reverse record.
*/functionclaim(address owner) externalreturns (bytes32);
/**
* @dev Sets the `name()` record for the reverse ENS record associated with
* the calling account. First updates the resolver to the default reverse
* resolver if necessary.
* @param name The name to set for this address.
* @return The ENS node hash of the reverse record.
*/functionsetName(stringmemory name) externalreturns (bytes32);
}
/**
* @title ENSReverseClaimer
* @dev This contract is used to claim reverse ENS records.
*/abstractcontractENSReverseClaimerisOwnable{
/// @dev The namehash of 'addr.reverse', the domain at which reverse records/// are stored in ENS.bytes32constant ADDR_REVERSE_NODE =0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;
/**
* @dev Transfers ownership of the reverse ENS record associated with the
* contract.
* @param ens The ENS registry.
* @param claimant The address to set as the owner of the reverse record in
* ENS.
* @return The ENS node hash of the reverse record.
*/functionclaimReverseENS(ENS ens, address claimant) externalonlyOwnerreturns (bytes32) {
return IReverseRegistrar(ens.owner(ADDR_REVERSE_NODE)).claim(claimant);
}
/**
* @dev Sets the reverse ENS record associated with the contract.
* @param ens The ENS registry.
* @param name The name to set as the reverse record in ENS.
* @return The ENS node hash of the reverse record.
*/functionsetReverseENS(ENS ens, stringcalldata name) externalonlyOwnerreturns (bytes32) {
return IReverseRegistrar(ens.owner(ADDR_REVERSE_NODE)).setName(name);
}
}
// SPDX-License-Identifier: UNLICENSEDpragmasolidity ^0.8.23;/**
* @title EFPListRegistry
* @notice A registry connecting token IDs with data such as managers, users, and list locations.
*/interfaceIEFPListRegistry{
///////////////////////////////////////////////////////////////////////////// Enums///////////////////////////////////////////////////////////////////////////enumMintState {
Disabled,
OwnerOnly,
PublicMint,
PublicBatch
}
///////////////////////////////////////////////////////////////////////////// Events////////////////////////////////////////////////////////////////////////////// @notice Emitted when a list storage location is seteventUpdateListStorageLocation(uint256indexed tokenId, bytes listStorageLocation);
///////////////////////////////////////////////////////////////////////////// ListStorageLocation///////////////////////////////////////////////////////////////////////////functiongetListStorageLocation(uint256 tokenId) externalviewreturns (bytesmemory);
functionsetListStorageLocation(uint256 tokenId, bytescalldata listStorageLocation) external;
///////////////////////////////////////////////////////////////////////////// Mint////////////////////////////////////////////////////////////////////////////// @notice Fetches the mint state.functiongetMintState() externalviewreturns (MintState);
/// @notice Sets the mint state./// @param _mintState The new mint state.functionsetMintState(MintState _mintState) external;
/// @notice Fetches the max mint batch size.functiongetMaxMintBatchSize() externalviewreturns (uint256);
/// @notice Sets the max mint batch size./// @param _maxMintBatchSize The new max mint batch size.functionsetMaxMintBatchSize(uint256 _maxMintBatchSize) external;
/// @notice Mints a new token.functionmint(bytescalldata listStorageLocation) externalpayable;
/**
* @notice Mints a new token to the given address.
* @param recipient The address to mint the token to.
*/functionmintTo(address recipient, bytescalldata listStorageLocation) externalpayable;
/// @notice Mints a new token to the given address.functionmintBatch(uint256 quantity) externalpayable;
/// @notice Mints a new token to the given address.functionmintBatchTo(address recipient, uint256 quantity) externalpayable;
}
Contract Source Code
File 7 of 8: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)pragmasolidity ^0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/function_checkOwner() internalviewvirtual{
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 8 of 8: Pausable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)pragmasolidity ^0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/abstractcontractPausableisContext{
/**
* @dev Emitted when the pause is triggered by `account`.
*/eventPaused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/eventUnpaused(address account);
boolprivate _paused;
/**
* @dev Initializes the contract in unpaused state.
*/constructor() {
_paused =false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/modifierwhenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/modifierwhenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/functionpaused() publicviewvirtualreturns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/function_requireNotPaused() internalviewvirtual{
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/function_requirePaused() internalviewvirtual{
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/function_pause() internalvirtualwhenNotPaused{
_paused =true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/function_unpause() internalvirtualwhenPaused{
_paused =false;
emit Unpaused(_msgSender());
}
}