编译器
0.8.10+commit.fc410830
文件 1 的 10:IERC165.sol
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;
}
}
文件 2 的 10:IERC2981.sol
pragma solidity 0.8.10;
interface IERC2981 {
function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}
文件 3 的 10:IERC721.sol
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);
}
文件 4 的 10:IMirrorOpenSaleV0.sol
pragma solidity 0.8.10;
interface IMirrorOpenSaleV0Events {
event RegisteredSale(
bytes32 h,
address indexed token,
uint256 startTokenId,
uint256 endTokenId,
address indexed operator,
address indexed recipient,
uint256 price,
bool open,
uint256 feePercentage
);
event Purchase(
bytes32 h,
address indexed token,
uint256 tokenId,
address indexed buyer,
address indexed recipient
);
event Withdraw(
bytes32 h,
uint256 amount,
uint256 fee,
address indexed recipient
);
event OpenSale(bytes32 h);
event CloseSale(bytes32 h);
}
interface IMirrorOpenSaleV0 {
struct Sale {
bool registered;
bool open;
uint256 sold;
address operator;
}
struct SaleConfig {
address token;
uint256 startTokenId;
uint256 endTokenId;
address operator;
address recipient;
uint256 price;
bool open;
uint256 feePercentage;
}
function treasuryConfig() external returns (address);
function feeRegistry() external returns (address);
function tributaryRegistry() external returns (address);
function sale(bytes32 h) external view returns (Sale memory);
function register(SaleConfig calldata saleConfig_) external;
function close(SaleConfig calldata saleConfig_) external;
function open(SaleConfig calldata saleConfig_) external;
function purchase(SaleConfig calldata saleConfig_, address recipient)
external
payable;
}
文件 5 的 10:IMirrorTreasury.sol
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;
}
文件 6 的 10:ITreasuryConfig.sol
pragma solidity 0.8.10;
interface ITreasuryConfig {
function treasury() external returns (address payable);
function distributionModel() external returns (address);
}
文件 7 的 10:MirrorFeeRegistry.sol
pragma solidity 0.8.10;
import {Ownable} from "../lib/Ownable.sol";
interface IMirrorFeeRegistry {
function maxFee() external returns (uint256);
function updateMaxFee(uint256 newFee) external;
}
contract MirrorFeeRegistry is IMirrorFeeRegistry, Ownable {
uint256 public override maxFee = 500;
constructor(address owner_) Ownable(owner_) {}
function updateMaxFee(uint256 newFee) external override onlyOwner {
maxFee = newFee;
}
}
文件 8 的 10:MirrorOpenSaleV0.sol
pragma solidity 0.8.10;
import {IMirrorOpenSaleV0, IMirrorOpenSaleV0Events} from "./interface/IMirrorOpenSaleV0.sol";
import {Reentrancy} from "../../lib/Reentrancy.sol";
import {IERC165} from "../../lib/ERC165/interface/IERC165.sol";
import {IERC2981} from "../../lib/ERC2981/interface/IERC2981.sol";
import {ITreasuryConfig} from "../../treasury/interface/ITreasuryConfig.sol";
import {IMirrorTreasury} from "../../treasury/interface/IMirrorTreasury.sol";
import {IMirrorFeeRegistry} from "../../fee-registry/MirrorFeeRegistry.sol";
import {IERC721Events} from "../../lib/ERC721/interface/IERC721.sol";
contract MirrorOpenSaleV0 is
IMirrorOpenSaleV0,
IMirrorOpenSaleV0Events,
IERC721Events,
Reentrancy
{
uint8 public constant VERSION = 0;
address public immutable override treasuryConfig;
address public immutable override feeRegistry;
address public immutable override tributaryRegistry;
mapping(bytes32 => Sale) internal sales_;
constructor(
address treasuryConfig_,
address feeRegistry_,
address tributaryRegistry_
) {
treasuryConfig = treasuryConfig_;
feeRegistry = feeRegistry_;
tributaryRegistry = tributaryRegistry_;
}
function sale(bytes32 h) external view override returns (Sale memory) {
return sales_[h];
}
function register(SaleConfig calldata saleConfig_) external override {
require(
msg.sender == saleConfig_.token ||
msg.sender == saleConfig_.operator,
"cannot register"
);
_register(saleConfig_);
}
function close(SaleConfig calldata saleConfig_) external override {
require(msg.sender == saleConfig_.operator, "not operator");
_setSaleStatus(saleConfig_, false);
}
function open(SaleConfig calldata saleConfig_) external override {
require(msg.sender == saleConfig_.operator, "not operator");
_setSaleStatus(saleConfig_, true);
}
function purchase(SaleConfig calldata saleConfig_, address recipient)
external
payable
override
nonReentrant
{
bytes32 h = _getHash(saleConfig_);
Sale storage s = sales_[h];
require(s.registered && s.open, "closed sale");
require(msg.value == saleConfig_.price, "incorrect value");
uint256 tokenId = saleConfig_.startTokenId + s.sold++;
require(tokenId <= saleConfig_.endTokenId, "sold out");
IERC721(saleConfig_.token).transferFrom(
saleConfig_.operator,
recipient,
tokenId
);
emit Purchase(
h,
saleConfig_.token,
tokenId,
msg.sender,
recipient
);
_withdraw(
saleConfig_.operator,
saleConfig_.token,
tokenId,
h,
saleConfig_.recipient,
msg.value,
saleConfig_.feePercentage
);
}
function _feeAmount(uint256 amount, uint256 fee)
internal
pure
returns (uint256)
{
return (amount * fee) / 10_000;
}
function _getHash(SaleConfig calldata saleConfig_)
internal
pure
returns (bytes32)
{
return
keccak256(
abi.encode(
saleConfig_.token,
saleConfig_.startTokenId,
saleConfig_.endTokenId,
saleConfig_.operator,
saleConfig_.recipient,
saleConfig_.price,
saleConfig_.open,
saleConfig_.feePercentage
)
);
}
function _register(SaleConfig calldata saleConfig_) internal {
uint256 maxFee = IMirrorFeeRegistry(feeRegistry).maxFee();
require(saleConfig_.feePercentage <= maxFee, "fee too high");
bytes32 h = _getHash(saleConfig_);
require(!sales_[h].registered, "sale already registered");
sales_[h] = Sale({
registered: true,
open: saleConfig_.open,
sold: 0,
operator: saleConfig_.operator
});
emit RegisteredSale(
h,
saleConfig_.token,
saleConfig_.startTokenId,
saleConfig_.endTokenId,
saleConfig_.operator,
saleConfig_.recipient,
saleConfig_.price,
saleConfig_.open,
saleConfig_.feePercentage
);
if (saleConfig_.open) {
emit OpenSale(h);
} else {
emit CloseSale(h);
}
}
function _setSaleStatus(SaleConfig calldata saleConfig_, bool status)
internal
{
bytes32 h = _getHash(saleConfig_);
require(sales_[h].registered, "unregistered sale");
require(sales_[h].open != status, "status already set");
sales_[h].open = status;
if (status) {
emit OpenSale(h);
} else {
emit CloseSale(h);
}
}
function _withdraw(
address operator,
address token,
uint256 tokenId,
bytes32 h,
address recipient,
uint256 totalAmount,
uint256 feePercentage
) internal {
uint256 feeAmount = 0;
if (feePercentage > 0) {
feeAmount = _feeAmount(totalAmount, feePercentage);
IMirrorTreasury(ITreasuryConfig(treasuryConfig).treasury())
.contributeWithTributary{value: feeAmount}(operator);
}
uint256 saleAmount = totalAmount - feeAmount;
(address royaltyRecipient, uint256 royaltyAmount) = _royaltyInfo(
token,
tokenId,
saleAmount
);
require(royaltyAmount < saleAmount, "invalid royalty amount");
if (msg.sender == royaltyRecipient || royaltyRecipient == address(0)) {
_send(payable(recipient), saleAmount);
emit Withdraw(h, totalAmount, feeAmount, recipient);
} else {
_send(payable(recipient), saleAmount - royaltyAmount);
_send(payable(royaltyRecipient), royaltyAmount);
emit Withdraw(h, totalAmount, feeAmount, recipient);
}
}
function _royaltyInfo(
address token,
uint256 tokenId,
uint256 amount
) internal view returns (address royaltyRecipient, uint256 royaltyAmount) {
if (IERC165(token).supportsInterface(type(IERC2981).interfaceId)) {
(royaltyRecipient, royaltyAmount) = IERC2981(token).royaltyInfo(
tokenId,
amount
);
}
}
function _send(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "recipient reverted");
}
}
interface IERC721 {
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
}
文件 9 的 10:Ownable.sol
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;
modifier onlyOwner() {
require(isOwner(), "caller is not the owner.");
_;
}
modifier onlyNextOwner() {
require(isNextOwner(), "current owner must set caller as next owner.");
_;
}
constructor(address owner_) {
owner = owner_;
emit OwnershipTransferred(address(0), owner);
}
function transferOwnership(address nextOwner_) external onlyOwner {
require(nextOwner_ != address(0), "Next owner is the zero address.");
nextOwner = nextOwner_;
}
function cancelOwnershipTransfer() external onlyOwner {
delete nextOwner;
}
function acceptOwnership() external onlyNextOwner {
delete nextOwner;
owner = msg.sender;
emit OwnershipTransferred(owner, msg.sender);
}
function renounceOwnership() external onlyOwner {
_renounceOwnership();
}
function isOwner() public view returns (bool) {
return msg.sender == 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 {
owner = address(0);
emit OwnershipTransferred(owner, address(0));
}
}
文件 10 的 10:Reentrancy.sol
pragma solidity 0.8.10;
contract Reentrancy {
uint256 internal constant REENTRANCY_NOT_ENTERED = 1;
uint256 internal constant REENTRANCY_ENTERED = 2;
uint256 internal reentrancyStatus;
modifier nonReentrant() {
require(reentrancyStatus != REENTRANCY_ENTERED, "Reentrant call");
reentrancyStatus = REENTRANCY_ENTERED;
_;
reentrancyStatus = REENTRANCY_NOT_ENTERED;
}
}
{
"compilationTarget": {
"contracts/distributors/open-sale/MirrorOpenSaleV0.sol": "MirrorOpenSaleV0"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 2000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"treasuryConfig_","type":"address"},{"internalType":"address","name":"feeRegistry_","type":"address"},{"internalType":"address","name":"tributaryRegistry_","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":false,"internalType":"bytes32","name":"h","type":"bytes32"}],"name":"CloseSale","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"h","type":"bytes32"}],"name":"OpenSale","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"h","type":"bytes32"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"Purchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"h","type":"bytes32"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"startTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"bool","name":"open","type":"bool"},{"indexed":false,"internalType":"uint256","name":"feePercentage","type":"uint256"}],"name":"RegisteredSale","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":"bytes32","name":"h","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"startTokenId","type":"uint256"},{"internalType":"uint256","name":"endTokenId","type":"uint256"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"open","type":"bool"},{"internalType":"uint256","name":"feePercentage","type":"uint256"}],"internalType":"struct IMirrorOpenSaleV0.SaleConfig","name":"saleConfig_","type":"tuple"}],"name":"close","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"startTokenId","type":"uint256"},{"internalType":"uint256","name":"endTokenId","type":"uint256"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"open","type":"bool"},{"internalType":"uint256","name":"feePercentage","type":"uint256"}],"internalType":"struct IMirrorOpenSaleV0.SaleConfig","name":"saleConfig_","type":"tuple"}],"name":"open","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"startTokenId","type":"uint256"},{"internalType":"uint256","name":"endTokenId","type":"uint256"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"open","type":"bool"},{"internalType":"uint256","name":"feePercentage","type":"uint256"}],"internalType":"struct IMirrorOpenSaleV0.SaleConfig","name":"saleConfig_","type":"tuple"},{"internalType":"address","name":"recipient","type":"address"}],"name":"purchase","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"startTokenId","type":"uint256"},{"internalType":"uint256","name":"endTokenId","type":"uint256"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"open","type":"bool"},{"internalType":"uint256","name":"feePercentage","type":"uint256"}],"internalType":"struct IMirrorOpenSaleV0.SaleConfig","name":"saleConfig_","type":"tuple"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"h","type":"bytes32"}],"name":"sale","outputs":[{"components":[{"internalType":"bool","name":"registered","type":"bool"},{"internalType":"bool","name":"open","type":"bool"},{"internalType":"uint256","name":"sold","type":"uint256"},{"internalType":"address","name":"operator","type":"address"}],"internalType":"struct IMirrorOpenSaleV0.Sale","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasuryConfig","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tributaryRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]