More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 345 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Safe Transfer Fr... | 23768860 | 38 days ago | IN | 0 ETH | 0.00001851 | ||||
| Set Approval For... | 23732509 | 43 days ago | IN | 0 ETH | 0.00001666 | ||||
| Safe Transfer Fr... | 23435030 | 84 days ago | IN | 0 ETH | 0.00007971 | ||||
| Set Approval For... | 23231823 | 113 days ago | IN | 0 ETH | 0.0000397 | ||||
| Set Approval For... | 23148600 | 124 days ago | IN | 0 ETH | 0.000119 | ||||
| Set Approval For... | 23148253 | 124 days ago | IN | 0 ETH | 0.00002709 | ||||
| Set Approval For... | 23134529 | 126 days ago | IN | 0 ETH | 0.000072 | ||||
| Safe Transfer Fr... | 23134045 | 126 days ago | IN | 0 ETH | 0.00031818 | ||||
| Set Approval For... | 22792656 | 174 days ago | IN | 0 ETH | 0.00013429 | ||||
| Set Approval For... | 22757213 | 179 days ago | IN | 0 ETH | 0.00003939 | ||||
| Set Approval For... | 22756230 | 179 days ago | IN | 0 ETH | 0.00024356 | ||||
| Set Approval For... | 22547123 | 208 days ago | IN | 0 ETH | 0.00006178 | ||||
| Set Approval For... | 21427887 | 365 days ago | IN | 0 ETH | 0.00047691 | ||||
| Set Approval For... | 21426995 | 365 days ago | IN | 0 ETH | 0.00055921 | ||||
| Safe Transfer Fr... | 21391791 | 370 days ago | IN | 0 ETH | 0.00083814 | ||||
| Set Approval For... | 19501612 | 634 days ago | IN | 0 ETH | 0.00082488 | ||||
| Set Approval For... | 18824073 | 729 days ago | IN | 0 ETH | 0.00151774 | ||||
| Safe Transfer Fr... | 17822270 | 869 days ago | IN | 0 ETH | 0.0017126 | ||||
| Set Approval For... | 17779935 | 875 days ago | IN | 0 ETH | 0.00159555 | ||||
| Transfer From | 17566688 | 905 days ago | IN | 0 ETH | 0.00076734 | ||||
| Safe Transfer Fr... | 17470259 | 919 days ago | IN | 0 ETH | 0.00122393 | ||||
| Set Approval For... | 17117827 | 968 days ago | IN | 0 ETH | 0.00258873 | ||||
| Set Approval For... | 17055095 | 977 days ago | IN | 0 ETH | 0.00113494 | ||||
| Set Approval For... | 16987050 | 987 days ago | IN | 0 ETH | 0.00124675 | ||||
| Safe Transfer Fr... | 16987031 | 987 days ago | IN | 0 ETH | 0.00173161 |
Latest 7 internal transactions
Advanced mode:
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Minimal Proxy Contract for 0xc85af08e5d890499c380ffda696ad68945ed7bd2
Contract Name:
Editions
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 2000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
import {Ownable} from "../../lib/Ownable.sol";
import {Pausable} from "../../lib/Pausable.sol";
import {Reentrancy} from "../../lib/Reentrancy.sol";
import {ERC721, IERC721, IERC165} from "../../lib/ERC721/ERC721.sol";
import {IERC721Metadata} from "../../lib/ERC721/interface/IERC721.sol";
import {IERC2309} from "../../lib/ERC2309/interface/IERC2309.sol";
import {IERC2981} from "../../lib/ERC2981/interface/IERC2981.sol";
import {IEditions, IEditionsEvents} from "./interface/IEditions.sol";
import {IRenderer} from "./interface/IRenderer.sol";
import {ITreasuryConfig} from "../../treasury/interface/ITreasuryConfig.sol";
import {IMirrorTreasury} from "../../treasury/interface/IMirrorTreasury.sol";
import {IMirrorFeeConfig} from "../../fee-config/MirrorFeeConfig.sol";
/**
* @title Editions
* @author MirrorXYZ
*/
contract Editions is
Ownable,
Pausable,
Reentrancy,
ERC721,
IERC721Metadata,
IERC2309,
IERC2981,
IEditions,
IEditionsEvents
{
// ============ Deployment ============
/// @notice Address that deploys and initializes clones
address public immutable override factory;
// ============ Fee Configuration ============
/// @notice Address for Mirror fee configuration.
address public immutable override feeConfig;
/// @notice Address for Mirror treasury configuration.
address public immutable override treasuryConfig;
// ============ ERC721 Metadata ============
/// @notice Edition name
string public override name;
/// @notice Ediiton symbol
string public override symbol;
// ============ Edition Data ============
/// @notice Last tokenId that was minted
uint256 internal currentTokenId;
/// @notice Edition contractURI
string internal _contractURI;
/// @notice Edition contentURI
string internal contentURI;
/// @notice Edition price
uint256 public override price;
/// @notice Edition limit
uint256 public override limit;
/// @notice Edition contentHash
bytes32 public override contentHash;
// ============ Royalty Info (ERC2981) ============
/// @notice Account that will receive royalties
/// @dev set address(0) to avoid royalties
address public override royaltyRecipient;
/// @notice Royalty Basis Points
uint256 public override royaltyBPS;
// ============ Rendering ============
/// @notice Rendering contract
address public override renderer;
// ============ Pre allocation ============
/// @notice Allocation recipient (consecutive transfer)
address internal allocationRecipient;
/// @notice Allocation count (consecutive transfer)
uint256 internal allocationCount;
// ============ Constructor ============
constructor(
address factory_,
address feeConfig_,
address treasuryConfig_
) Ownable(address(0)) Pausable(false) {
factory = factory_;
feeConfig = feeConfig_;
treasuryConfig = treasuryConfig_;
}
// ============ Initializing ============
/// @notice Initialize metadata
/// @param owner_ the clone owner
/// @param name_ the name for the edition clone
/// @param symbol_ the symbol for the edition clone
/// @param contentURI_ the contentURI for the edition clone
/// @param contractURI_ the contractURI for the edition clone
/// @param edition_ the parameters for the edition sale
/// @param paused_ the pause state for the edition sale
function initialize(
address owner_,
string memory name_,
string memory symbol_,
string memory contentURI_,
string memory contractURI_,
Edition memory edition_,
bool paused_
) external override {
require(msg.sender == factory, "unauthorized caller");
// store erc721 metadata
name = name_;
symbol = symbol_;
// store edition data
contentURI = contentURI_;
_contractURI = contractURI_;
price = edition_.price;
limit = edition_.limit;
contentHash = edition_.contentHash;
// set pause status
if (paused_) {
_pause();
}
// store owner
_setOwner(address(0), owner_);
// set royalty defaults to owner and 10%
royaltyRecipient = owner_;
royaltyBPS = 1000;
}
// ============ Pause Methods ============
/// @notice Unpause edition sale
function unpause() external override onlyOwner {
_unpause();
}
/// @notice Pause edition sale
function pause() external override onlyOwner {
_pause();
}
// ============ Allocation ============
/// @notice Allocates `count` editions to `recipient`
/// @dev Throws if an edition has been purchased already or `count` exceeds limit
/// @param recipient the account to receive tokens
/// @param count the number of tokens to mint to `recipient`
function allocate(address recipient, uint256 count)
external
override
onlyOwner
{
// check that no purchases have happened and count does not exceed limit
require(
currentTokenId == 0 && (limit == 0 || count <= limit),
"cannot allocate"
);
// set allocation recipient
allocationRecipient = recipient;
allocationCount = count;
// update tokenId
currentTokenId = count;
// update balance
_balances[recipient] = count;
// emit transfer
emit ConsecutiveTransfer(
// fromTokenId
1,
// toTokenId
count,
// fromAddress
address(0),
// toAddress
recipient
);
}
/// @notice Finds the owner of a token
/// @dev this method takes into account allocation
function ownerOf(uint256 tokenId) public view override returns (address) {
address _owner = _owners[tokenId];
// if there is not owner set,
// and the tokenId is within the allocation count
// the allocationRecipient owns it
if (_owner == address(0) && tokenId < allocationCount) {
return allocationRecipient;
}
require(_owner != address(0), "ERC721: query for nonexistent token");
return _owner;
}
// ============ Purchase ============
/// @notice Purchase an edition
/// @dev throws if sale is paused or incorrect value is sent
/// @param recipient the account to receive the edition
function purchase(address recipient)
external
payable
override
whenNotPaused
returns (uint256 tokenId)
{
require(msg.value == price, "incorrect value");
return _purchase(recipient);
}
// ============ Minting ============
/// @notice Mint an edition
/// @dev throws if called by a non-owner
/// @param recipient the account to receive the edition
function mint(address recipient)
external
override
onlyOwner
returns (uint256 tokenId)
{
tokenId = _getTokenIdAndMint(recipient);
}
/// @notice Allows the owner to set a global limit on the total supply
/// @dev throws if attempting to increase the limit
function setLimit(uint256 limit_) external override onlyOwner {
// enforce that the limit should only ever decrease once set
require(
limit == 0 || limit_ < limit,
"limit must be < than current limit"
);
// announce the change in limit
emit EditionLimitSet(
// oldLimit
limit,
// newLimit
limit_
);
// update the limit.
limit = limit_;
}
// ============ ERC2981 Methods ============
/// @notice Called with the sale price to determine how much royalty
// is owed and to whom
/// @param _tokenId - the NFT asset queried for royalty information
/// @param _salePrice - the sale price of the NFT asset specified by _tokenId
/// @return receiver - address of who should be sent the royalty payment
/// @return royaltyAmount - the royalty payment amount for _salePrice
function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
external
view
override
returns (address receiver, uint256 royaltyAmount)
{
receiver = royaltyRecipient;
royaltyAmount = (_salePrice * royaltyBPS) / 10_000;
}
/// @param royaltyRecipient_ the address that will receive royalties
/// @param royaltyBPS_ the royalty amount in basis points (bps)
function setRoyaltyInfo(
address payable royaltyRecipient_,
uint256 royaltyBPS_
) external override onlyOwner {
require(
royaltyBPS_ <= 10_000,
"bps must be less than or equal to 10,000"
);
emit RoyaltyChange(
// oldRoyaltyRecipient
royaltyRecipient,
// oldRoyaltyBPS
royaltyBPS,
// newRoyaltyRecipient
royaltyRecipient_,
// newRoyaltyBPS
royaltyBPS_
);
royaltyRecipient = royaltyRecipient_;
royaltyBPS = royaltyBPS_;
}
// ============ Rendering Methods ============
/// @notice Set the renderer address
/// @dev Throws if renderer is not the zero address
function setRenderer(address renderer_) external override onlyOwner {
require(renderer == address(0), "renderer already set");
renderer = renderer_;
emit RendererSet(
// renderer
renderer_
);
}
/// @notice Get contract metadata
/// @dev If a renderer is set, return the renderer's metadata
function contractURI() external view override returns (string memory) {
if (renderer != address(0)) {
return IRenderer(renderer).contractURI();
}
return _contractURI;
}
/// @notice Get `tokenId` URI or data
/// @dev If a renderer is set, call renderer's tokenURI
/// @param tokenId The tokenId used to request data
function tokenURI(uint256 tokenId)
public
view
override
returns (string memory)
{
require(_exists(tokenId), "ERC721: query for nonexistent token");
if (renderer != address(0)) {
return IRenderer(renderer).tokenURI(tokenId);
}
return string(abi.encodePacked(contentURI, _toString(tokenId)));
}
// ============ Withdrawal ============
/// @notice Set the price
function setPrice(uint256 price_) external override onlyOwner {
price = price_;
emit PriceSet(
// price
price_
);
}
function withdraw(uint16 feeBPS, address fundingRecipient)
external
onlyOwner
nonReentrant
{
require(fundingRecipient != address(0), "must set fundingRecipient");
_withdraw(feeBPS, fundingRecipient);
}
// ============ IERC165 Method ============
function supportsInterface(bytes4 interfaceId)
public
pure
override
returns (bool)
{
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
interfaceId == type(IERC165).interfaceId ||
interfaceId == type(IERC2981).interfaceId;
}
// ============ Internal Methods ============
function _withdraw(uint16 feeBPS, address fundingRecipient) internal {
// assert that the fee is valid
require(IMirrorFeeConfig(feeConfig).isFeeValid(feeBPS), "invalid fee");
// calculate the fee on the current balance, using the fee percentage
uint256 fee = _feeAmount(address(this).balance, feeBPS);
// if the fee is not zero, attempt to send it to the treasury
if (fee != 0) {
_sendEther(ITreasuryConfig(treasuryConfig).treasury(), fee);
}
// broadcast the withdrawal event – with balance and fee
emit Withdrawal(
// recipient
fundingRecipient,
// amount
address(this).balance,
// fee
fee
);
// transfer the remaining balance to the fundingRecipient
_sendEther(payable(fundingRecipient), address(this).balance);
}
function _sendEther(address payable recipient_, uint256 amount) internal {
// ensure sufficient balance
require(address(this).balance >= amount, "insufficient balance");
// send the value
(bool success, ) = recipient_.call{value: amount, gas: gasleft()}("");
require(success, "recipient reverted");
}
function _feeAmount(uint256 amount, uint16 fee)
internal
pure
returns (uint256)
{
return (amount * fee) / 10_000;
}
/// @dev ensure token has an owner, or token is within the allocation
function _exists(uint256 tokenId) internal view override returns (bool) {
return _owners[tokenId] != address(0) || tokenId < allocationCount;
}
/// @dev Mints token and emits purchase event
function _purchase(address recipient) internal returns (uint256 tokenId) {
// mint the token, get a tokenId
tokenId = _getTokenIdAndMint(recipient);
emit EditionPurchased(
// tokenId
tokenId,
// nftRecipient
recipient,
// amountPaid
msg.value
);
}
/// @dev Mints and returns tokenId
function _getTokenIdAndMint(address recipient)
internal
returns (uint256 tokenId)
{
// increment currentTokenId and store tokenId
tokenId = ++currentTokenId;
// check that there are still tokens available to purchase
require(limit == 0 || tokenId < limit + 1, "sold out");
// mint a new token for the recipient, using the `tokenId`.
_mint(recipient, tokenId);
}
// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol
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);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
interface IOwnableEvents {
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
}
contract Ownable is IOwnableEvents {
address public owner;
address private nextOwner;
// modifiers
modifier onlyOwner() {
require(isOwner(), "caller is not the owner.");
_;
}
modifier onlyNextOwner() {
require(isNextOwner(), "current owner must set caller as next owner.");
_;
}
/**
* @dev Initialize contract by setting transaction submitter as initial owner.
*/
constructor(address owner_) {
owner = owner_;
emit OwnershipTransferred(address(0), owner);
}
/**
* @dev Initiate ownership transfer by setting nextOwner.
*/
function transferOwnership(address nextOwner_) external onlyOwner {
require(nextOwner_ != address(0), "Next owner is the zero address.");
nextOwner = nextOwner_;
}
/**
* @dev Cancel ownership transfer by deleting nextOwner.
*/
function cancelOwnershipTransfer() external onlyOwner {
delete nextOwner;
}
/**
* @dev Accepts ownership transfer by setting owner.
*/
function acceptOwnership() external onlyNextOwner {
delete nextOwner;
owner = msg.sender;
emit OwnershipTransferred(owner, msg.sender);
}
/**
* @dev Renounce ownership by setting owner to zero address.
*/
function renounceOwnership() external onlyOwner {
_renounceOwnership();
}
/**
* @dev Returns true if the caller is the current owner.
*/
function isOwner() public view returns (bool) {
return msg.sender == owner;
}
/**
* @dev Returns true if the caller is the next owner.
*/
function isNextOwner() public view returns (bool) {
return msg.sender == nextOwner;
}
function _setOwner(address previousOwner, address newOwner) internal {
owner = newOwner;
emit OwnershipTransferred(previousOwner, owner);
}
function _renounceOwnership() internal {
emit OwnershipTransferred(owner, address(0));
owner = address(0);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
interface IPausableEvents {
/// @notice Emitted when the pause is triggered by `account`.
event Paused(address account);
/// @notice Emitted when the pause is lifted by `account`.
event Unpaused(address account);
}
interface IPausable {
function paused() external returns (bool);
}
contract Pausable is IPausable, IPausableEvents {
bool public override paused;
// Modifiers
modifier whenNotPaused() {
require(!paused, "Pausable: paused");
_;
}
modifier whenPaused() {
require(paused, "Pausable: not paused");
_;
}
/// @notice Initializes the contract in unpaused state.
constructor(bool paused_) {
paused = paused_;
}
// ============ Internal Functions ============
function _pause() internal whenNotPaused {
paused = true;
emit Paused(msg.sender);
}
function _unpause() internal whenPaused {
paused = false;
emit Unpaused(msg.sender);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
contract Reentrancy {
// ============ Constants ============
uint256 internal constant REENTRANCY_NOT_ENTERED = 1;
uint256 internal constant REENTRANCY_ENTERED = 2;
// ============ Mutable Storage ============
uint256 internal reentrancyStatus;
// ============ Modifiers ============
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(reentrancyStatus != REENTRANCY_ENTERED, "Reentrant call");
// Any calls to nonReentrant after this point will fail
reentrancyStatus = REENTRANCY_ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip2200)
reentrancyStatus = REENTRANCY_NOT_ENTERED;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
import {IERC721, IERC721Events, IERC721Metadata, IERC721Receiver} from "./interface/IERC721.sol";
import {IERC165} from "../ERC165/interface/IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override
returns (bool)
{
return interfaceId == type(IERC165).interfaceId;
}
}
/**
* Based on: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol
*/
contract ERC721 is ERC165, IERC721, IERC721Events {
mapping(uint256 => address) internal _owners;
mapping(address => uint256) internal _balances;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override
returns (bool)
{
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address owner)
public
view
virtual
override
returns (uint256)
{
require(
owner != address(0),
"ERC721: balance query for the zero address"
);
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view virtual returns (address) {
address owner = _owners[tokenId];
require(
owner != address(0),
"ERC721: owner query for nonexistent token"
);
return owner;
}
/**
* @dev Base URI for computing {tokenURI}. Empty by default, can be overriden
* in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
function approve(address to, uint256 tokenId) public virtual override {
address owner = ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
msg.sender == owner || isApprovedForAll(owner, msg.sender),
"ERC721: approve caller is not owner nor approved for all"
);
_approve(to, tokenId);
}
function getApproved(uint256 tokenId)
public
view
virtual
override
returns (address)
{
require(
_exists(tokenId),
"ERC721: approved query for nonexistent token"
);
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved)
public
virtual
override
{
require(operator != msg.sender, "ERC721: approve to caller");
_operatorApprovals[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function isApprovedForAll(address owner, address operator)
public
view
virtual
override
returns (bool)
{
return _operatorApprovals[owner][operator];
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
//solhint-disable-next-line max-line-length
require(
_isApprovedOrOwner(msg.sender, tokenId),
"ERC721: transfer caller is not owner nor approved"
);
_transfer(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public virtual override {
require(
_isApprovedOrOwner(msg.sender, tokenId),
"ERC721: transfer caller is not owner nor approved"
);
_safeTransfer(from, to, tokenId, _data);
}
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"
);
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
function _isApprovedOrOwner(address spender, uint256 tokenId)
internal
view
virtual
returns (bool)
{
require(
_exists(tokenId),
"ERC721: operator query for nonexistent token"
);
address owner = ownerOf(tokenId);
return (spender == owner ||
getApproved(tokenId) == spender ||
isApprovedForAll(owner, spender));
}
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
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"
);
}
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");
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
}
function _burn(uint256 tokenId) internal virtual {
address owner = ownerOf(tokenId);
// Clear approvals
_approve(address(0), tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
}
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(
ownerOf(tokenId) == from,
"ERC721: transfer of token that is not own"
);
require(to != address(0), "ERC721: transfer to the zero address");
// Clear approvals from the previous owner
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ownerOf(tokenId), to, tokenId);
}
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
if (isContract(to)) {
try
IERC721Receiver(to).onERC721Received(
msg.sender,
from,
tokenId,
_data
)
returns (bytes4 retval) {
return retval == IERC721Receiver(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert(
"ERC721: transfer to non ERC721Receiver implementer"
);
} else {
// solhint-disable-next-line no-inline-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/7f6a1666fac8ecff5dd467d0938069bc221ea9e0/contracts/utils/Address.sol
function isContract(address account) internal view returns (bool) {
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly {
size := extcodesize(account)
}
return size > 0;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
interface IERC721 {
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId)
external
view
returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator)
external
view
returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
}
interface IERC721Events {
event Transfer(
address indexed from,
address indexed to,
uint256 indexed tokenId
);
event Approval(
address indexed owner,
address indexed approved,
uint256 indexed tokenId
);
event ApprovalForAll(
address indexed owner,
address indexed operator,
bool approved
);
}
interface IERC721Metadata {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
interface IERC721Burnable is IERC721 {
function burn(uint256 tokenId) external;
}
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
interface IERC721Royalties {
function getFeeRecipients(uint256 id)
external
view
returns (address payable[] memory);
function getFeeBps(uint256 id) external view returns (uint256[] memory);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
interface IERC2309 {
event ConsecutiveTransfer(
uint256 indexed fromTokenId,
uint256 toTokenId,
address indexed fromAddress,
address indexed toAddress
);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
/**
* @title IERC2981
* @notice Interface for the NFT Royalty Standard
*/
interface IERC2981 {
// / bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
/**
* @notice Called with the sale price to determine how much royalty
* is owed and to whom.
* @param _tokenId - the NFT asset queried for royalty information
* @param _salePrice - the sale price of the NFT asset specified by _tokenId
* @return receiver - address of who should be sent the royalty payment
* @return royaltyAmount - the royalty payment amount for _salePrice
*/
function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
interface IEditionsEvents {
event EditionPurchased(
uint256 indexed tokenId,
address indexed nftRecipient,
uint256 amountPaid
);
event RoyaltyChange(
address indexed oldRoyaltyRecipient,
uint256 oldRoyaltyBPS,
address indexed newRoyaltyRecipient,
uint256 newRoyaltyBPS
);
event RendererSet(address indexed renderer);
event EditionLimitSet(uint256 oldLimit, uint256 newLimit);
event Withdrawal(address indexed recipient, uint256 amount, uint256 fee);
event FundingRecipientSet(
address indexed oldFundingRecipient,
address indexed newFundingRecipient
);
event PriceSet(uint256 price);
}
interface IEditions {
struct Edition {
// Edition price
uint256 price;
// Edition supply limit
uint256 limit;
// Edition contentHash
bytes32 contentHash;
}
// ============ Authorization ============
function factory() external returns (address);
// ============ Fee Configuration ============
function feeConfig() external returns (address);
function treasuryConfig() external returns (address);
// ============ Edition Data ============
function price() external returns (uint256);
function limit() external returns (uint256);
function contentHash() external returns (bytes32);
// ============ Royalty Info (ERC2981) ============
function royaltyRecipient() external returns (address);
function royaltyBPS() external returns (uint256);
// ============ Rendering ============
function renderer() external view returns (address);
// ============ Initializing ============
function initialize(
address owner_,
string memory name_,
string memory symbol_,
string memory contentURI_,
string memory contractURI_,
Edition memory edition_,
bool paused_
) external;
// ============ Pause Methods ============
function unpause() external;
function pause() external;
// ============ Allocation ============
function allocate(address recipient, uint256 count) external;
// ============ Purchase ============
function purchase(address recipient)
external
payable
returns (uint256 tokenId);
// ============ Minting ============
function mint(address recipient) external returns (uint256 tokenId);
function setLimit(uint256 limit_) external;
// ============ ERC2981 Methods ============
function setRoyaltyInfo(
address payable royaltyRecipient_,
uint256 royaltyPercentage_
) external;
// ============ Rendering Methods ============
function setRenderer(address renderer_) external;
function contractURI() external view returns (string memory);
// ============ Withdrawal ============
function setPrice(uint256 price_) external;
function withdraw(uint16 feeBPS, address fundingRecipient) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
interface IRenderer {
function tokenURI(uint256 tokenId) external view returns (string calldata);
function contractURI() external view returns (string calldata);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
interface ITreasuryConfig {
function treasury() external returns (address payable);
function distributionModel() external returns (address);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
interface IMirrorTreasury {
function transferFunds(address payable to, uint256 value) external;
function transferERC20(
address token,
address to,
uint256 value
) external;
function contributeWithTributary(address tributary) external payable;
function contribute(uint256 amount) external payable;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
import {Ownable} from "../lib/Ownable.sol";
interface IMirrorFeeConfig {
function maxFee() external returns (uint16);
function minFee() external returns (uint16);
function isFeeValid(uint16) external view returns (bool);
function updateMaxFee(uint16 newFee) external;
function updateMinFee(uint16 newFee) external;
}
/**
* @title MirrorFeeConfig
* @author MirrorXYZ
*/
contract MirrorFeeConfig is IMirrorFeeConfig, Ownable {
uint16 public override maxFee = 500;
uint16 public override minFee = 250;
constructor(address owner_) Ownable(owner_) {}
function updateMaxFee(uint16 newFee) external override onlyOwner {
maxFee = newFee;
}
function updateMinFee(uint16 newFee) external override onlyOwner {
minFee = newFee;
}
function isFeeValid(uint16 fee)
external
view
returns (bool isBeweenMinAndMax)
{
isBeweenMinAndMax = (minFee <= fee) && (fee <= maxFee);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override
returns (bool)
{
return interfaceId == type(IERC165).interfaceId;
}
}{
"optimizer": {
"enabled": true,
"runs": 2000
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"factory_","type":"address"},{"internalType":"address","name":"feeConfig_","type":"address"},{"internalType":"address","name":"treasuryConfig_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"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":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"fromAddress","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"EditionLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"nftRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountPaid","type":"uint256"}],"name":"EditionPurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldFundingRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newFundingRecipient","type":"address"}],"name":"FundingRecipientSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"PriceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"renderer","type":"address"}],"name":"RendererSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldRoyaltyRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldRoyaltyBPS","type":"uint256"},{"indexed":true,"internalType":"address","name":"newRoyaltyRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"newRoyaltyBPS","type":"uint256"}],"name":"RoyaltyChange","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"allocate","outputs":[],"stateMutability":"nonpayable","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":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contentHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeConfig","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"string","name":"contentURI_","type":"string"},{"internalType":"string","name":"contractURI_","type":"string"},{"components":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"bytes32","name":"contentHash","type":"bytes32"}],"internalType":"struct IEditions.Edition","name":"edition_","type":"tuple"},{"internalType":"bool","name":"paused_","type":"bool"}],"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":[],"name":"isNextOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"limit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"purchase","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renderer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"royaltyBPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"royaltyRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":"uint256","name":"limit_","type":"uint256"}],"name":"setLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price_","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"renderer_","type":"address"}],"name":"setRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"royaltyRecipient_","type":"address"},{"internalType":"uint256","name":"royaltyBPS_","type":"uint256"}],"name":"setRoyaltyInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"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"},{"inputs":[{"internalType":"address","name":"nextOwner_","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasuryConfig","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"feeBPS","type":"uint16"},{"internalType":"address","name":"fundingRecipient","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 100.00% | $2,936.63 | 6.8 | $19,969.07 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.