文件 1 的 5:IFilteredMinterV0.sol
pragma solidity ^0.8.0;
interface IFilteredMinterV0 {
event PricePerTokenInWeiUpdated(
uint256 indexed _projectId,
uint256 indexed _pricePerTokenInWei
);
event ProjectCurrencyInfoUpdated(
uint256 indexed _projectId,
address indexed _currencyAddress,
string _currencySymbol
);
event PurchaseToDisabledUpdated(
uint256 indexed _projectId,
bool _purchaseToDisabled
);
function minterType() external view returns (string memory);
function genArt721CoreAddress() external returns (address);
function minterFilterAddress() external returns (address);
function purchase(uint256 _projectId)
external
payable
returns (uint256 tokenId);
function purchaseTo(address _to, uint256 _projectId)
external
payable
returns (uint256 tokenId);
function togglePurchaseToDisabled(uint256 _projectId) external;
function setProjectMaxInvocations(uint256 _projectId) external;
function getPriceInfo(uint256 _projectId)
external
view
returns (
bool isConfigured,
uint256 tokenPriceInWei,
string memory currencySymbol,
address currencyAddress
);
}
文件 2 的 5:IGenArt721CoreContractV1.sol
pragma solidity ^0.8.0;
interface IGenArt721CoreContractV1 {
event Mint(
address indexed _to,
uint256 indexed _tokenId,
uint256 indexed _projectId
);
function admin() external view returns (address);
function nextProjectId() external view returns (uint256);
function tokenIdToProjectId(uint256 tokenId)
external
view
returns (uint256 projectId);
function isWhitelisted(address sender) external view returns (bool);
function isMintWhitelisted(address minter) external view returns (bool);
function projectIdToArtistAddress(uint256 _projectId)
external
view
returns (address payable);
function projectIdToAdditionalPayee(uint256 _projectId)
external
view
returns (address payable);
function projectIdToAdditionalPayeePercentage(uint256 _projectId)
external
view
returns (uint256);
function projectTokenInfo(uint256 _projectId)
external
view
returns (
address,
uint256,
uint256,
uint256,
bool,
address,
uint256,
string memory,
address
);
function artblocksAddress() external view returns (address payable);
function artblocksPercentage() external view returns (uint256);
function mint(
address _to,
uint256 _projectId,
address _by
) external returns (uint256 tokenId);
function getRoyaltyData(uint256 _tokenId)
external
view
returns (
address artistAddress,
address additionalPayee,
uint256 additionalPayeePercentage,
uint256 royaltyFeeByID
);
}
文件 3 的 5:IMinterFilterV0.sol
pragma solidity ^0.8.0;
interface IMinterFilterV0 {
event MinterApproved(address indexed _minterAddress, string _minterType);
event MinterRevoked(address indexed _minterAddress);
event ProjectMinterRegistered(
uint256 indexed _projectId,
address indexed _minterAddress,
string _minterType
);
event ProjectMinterRemoved(uint256 indexed _projectId);
function genArt721CoreAddress() external returns (address);
function setMinterForProject(uint256, address) external;
function removeMinterForProject(uint256) external;
function mint(
address _to,
uint256 _projectId,
address sender
) external returns (uint256);
function getMinterForProject(uint256) external view returns (address);
function projectHasMinter(uint256) external view returns (bool);
}
文件 4 的 5:MinterDAExpV1.sol
import "../interfaces/0.8.x/IGenArt721CoreContractV1.sol";
import "../interfaces/0.8.x/IMinterFilterV0.sol";
import "../interfaces/0.8.x/IFilteredMinterV0.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
pragma solidity 0.8.9;
contract MinterDAExpV1 is ReentrancyGuard, IFilteredMinterV0 {
event SetAuctionDetails(
uint256 indexed projectId,
uint256 _auctionTimestampStart,
uint256 _priceDecayHalfLifeSeconds,
uint256 _startPrice,
uint256 _basePrice
);
event ResetAuctionDetails(uint256 indexed projectId);
event AuctionHalfLifeRangeSecondsUpdated(
uint256 _minimumPriceDecayHalfLifeSeconds,
uint256 _maximumPriceDecayHalfLifeSeconds
);
address public immutable genArt721CoreAddress;
IGenArt721CoreContractV1 private immutable genArtCoreContract;
address public immutable minterFilterAddress;
IMinterFilterV0 private immutable minterFilter;
string public constant minterType = "MinterDAExpV1";
uint256 constant ONE_MILLION = 1_000_000;
mapping(uint256 => bool) public projectMaxHasBeenInvoked;
mapping(uint256 => uint256) public projectMaxInvocations;
uint256 public minimumPriceDecayHalfLifeSeconds = 300;
uint256 public maximumPriceDecayHalfLifeSeconds = 3600;
mapping(uint256 => AuctionParameters) public projectAuctionParameters;
struct AuctionParameters {
uint256 timestampStart;
uint256 priceDecayHalfLifeSeconds;
uint256 startPrice;
uint256 basePrice;
}
modifier onlyCoreWhitelisted() {
require(
genArtCoreContract.isWhitelisted(msg.sender),
"Only Core whitelisted"
);
_;
}
modifier onlyArtist(uint256 _projectId) {
require(
(msg.sender ==
genArtCoreContract.projectIdToArtistAddress(_projectId)),
"Only Artist"
);
_;
}
constructor(address _genArt721Address, address _minterFilter)
ReentrancyGuard()
{
genArt721CoreAddress = _genArt721Address;
genArtCoreContract = IGenArt721CoreContractV1(_genArt721Address);
minterFilterAddress = _minterFilter;
minterFilter = IMinterFilterV0(_minterFilter);
require(
minterFilter.genArt721CoreAddress() == _genArt721Address,
"Illegal contract pairing"
);
}
function setProjectMaxInvocations(uint256 _projectId)
external
onlyCoreWhitelisted
{
uint256 invocations;
uint256 maxInvocations;
(, , invocations, maxInvocations, , , , , ) = genArtCoreContract
.projectTokenInfo(_projectId);
projectMaxInvocations[_projectId] = maxInvocations;
if (invocations < maxInvocations) {
projectMaxHasBeenInvoked[_projectId] = false;
}
}
function togglePurchaseToDisabled(uint256 _projectId)
external
view
onlyArtist(_projectId)
{
revert("Action not supported");
}
function setAllowablePriceDecayHalfLifeRangeSeconds(
uint256 _minimumPriceDecayHalfLifeSeconds,
uint256 _maximumPriceDecayHalfLifeSeconds
) external onlyCoreWhitelisted {
require(
_maximumPriceDecayHalfLifeSeconds >
_minimumPriceDecayHalfLifeSeconds,
"Maximum half life must be greater than minimum"
);
require(
_minimumPriceDecayHalfLifeSeconds > 0,
"Half life of zero not allowed"
);
minimumPriceDecayHalfLifeSeconds = _minimumPriceDecayHalfLifeSeconds;
maximumPriceDecayHalfLifeSeconds = _maximumPriceDecayHalfLifeSeconds;
emit AuctionHalfLifeRangeSecondsUpdated(
_minimumPriceDecayHalfLifeSeconds,
_maximumPriceDecayHalfLifeSeconds
);
}
function setAuctionDetails(
uint256 _projectId,
uint256 _auctionTimestampStart,
uint256 _priceDecayHalfLifeSeconds,
uint256 _startPrice,
uint256 _basePrice
) external onlyArtist(_projectId) {
AuctionParameters memory auctionParams = projectAuctionParameters[
_projectId
];
require(
auctionParams.timestampStart == 0 ||
block.timestamp < auctionParams.timestampStart,
"No modifications mid-auction"
);
require(
block.timestamp < _auctionTimestampStart,
"Only future auctions"
);
require(
_startPrice > _basePrice,
"Auction start price must be greater than auction end price"
);
require(
(_priceDecayHalfLifeSeconds >= minimumPriceDecayHalfLifeSeconds) &&
(_priceDecayHalfLifeSeconds <=
maximumPriceDecayHalfLifeSeconds),
"Price decay half life must fall between min and max allowable values"
);
projectAuctionParameters[_projectId] = AuctionParameters(
_auctionTimestampStart,
_priceDecayHalfLifeSeconds,
_startPrice,
_basePrice
);
emit SetAuctionDetails(
_projectId,
_auctionTimestampStart,
_priceDecayHalfLifeSeconds,
_startPrice,
_basePrice
);
}
function resetAuctionDetails(uint256 _projectId)
external
onlyCoreWhitelisted
{
delete projectAuctionParameters[_projectId];
emit ResetAuctionDetails(_projectId);
}
function purchase(uint256 _projectId)
external
payable
returns (uint256 tokenId)
{
tokenId = purchaseTo(msg.sender, _projectId);
return tokenId;
}
function purchaseTo(address _to, uint256 _projectId)
public
payable
nonReentrant
returns (uint256 tokenId)
{
require(
!projectMaxHasBeenInvoked[_projectId],
"Maximum number of invocations reached"
);
uint256 currentPriceInWei = _getPrice(_projectId);
require(
msg.value >= currentPriceInWei,
"Must send minimum value to mint!"
);
tokenId = minterFilter.mint(_to, _projectId, msg.sender);
if (
projectMaxInvocations[_projectId] > 0 &&
tokenId % ONE_MILLION == projectMaxInvocations[_projectId] - 1
) {
projectMaxHasBeenInvoked[_projectId] = true;
}
_splitFundsETHAuction(_projectId, currentPriceInWei);
return tokenId;
}
function _splitFundsETHAuction(
uint256 _projectId,
uint256 _currentPriceInWei
) internal {
if (msg.value > 0) {
uint256 refund = msg.value - _currentPriceInWei;
if (refund > 0) {
(bool success_, ) = msg.sender.call{value: refund}("");
require(success_, "Refund failed");
}
uint256 foundationAmount = (_currentPriceInWei *
genArtCoreContract.artblocksPercentage()) / 100;
if (foundationAmount > 0) {
(bool success_, ) = genArtCoreContract.artblocksAddress().call{
value: foundationAmount
}("");
require(success_, "Foundation payment failed");
}
uint256 projectFunds = _currentPriceInWei - foundationAmount;
uint256 additionalPayeeAmount;
if (
genArtCoreContract.projectIdToAdditionalPayeePercentage(
_projectId
) > 0
) {
additionalPayeeAmount =
(projectFunds *
genArtCoreContract.projectIdToAdditionalPayeePercentage(
_projectId
)) /
100;
if (additionalPayeeAmount > 0) {
(bool success_, ) = genArtCoreContract
.projectIdToAdditionalPayee(_projectId)
.call{value: additionalPayeeAmount}("");
require(success_, "Additional payment failed");
}
}
uint256 creatorFunds = projectFunds - additionalPayeeAmount;
if (creatorFunds > 0) {
(bool success_, ) = genArtCoreContract
.projectIdToArtistAddress(_projectId)
.call{value: creatorFunds}("");
require(success_, "Artist payment failed");
}
}
}
function _getPrice(uint256 _projectId) private view returns (uint256) {
AuctionParameters memory auctionParams = projectAuctionParameters[
_projectId
];
require(
block.timestamp > auctionParams.timestampStart,
"Auction not yet started"
);
require(
auctionParams.priceDecayHalfLifeSeconds > 0,
"Only configured auctions"
);
uint256 decayedPrice = auctionParams.startPrice;
uint256 elapsedTimeSeconds = block.timestamp -
auctionParams.timestampStart;
decayedPrice >>=
elapsedTimeSeconds /
auctionParams.priceDecayHalfLifeSeconds;
decayedPrice -=
(decayedPrice *
(elapsedTimeSeconds %
auctionParams.priceDecayHalfLifeSeconds)) /
auctionParams.priceDecayHalfLifeSeconds /
2;
if (decayedPrice < auctionParams.basePrice) {
return auctionParams.basePrice;
}
return decayedPrice;
}
function getPriceInfo(uint256 _projectId)
external
view
returns (
bool isConfigured,
uint256 tokenPriceInWei,
string memory currencySymbol,
address currencyAddress
)
{
AuctionParameters memory auctionParams = projectAuctionParameters[
_projectId
];
isConfigured = (auctionParams.startPrice > 0);
if (block.timestamp <= auctionParams.timestampStart) {
tokenPriceInWei = auctionParams.startPrice;
} else if (auctionParams.startPrice == 0) {
tokenPriceInWei = 0;
} else {
tokenPriceInWei = _getPrice(_projectId);
}
currencySymbol = "ETH";
currencyAddress = address(0);
}
}
文件 5 的 5:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
{
"compilationTarget": {
"contracts/minter-suite/MinterDAExpV1.sol": "MinterDAExpV1"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 100
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_genArt721Address","type":"address"},{"internalType":"address","name":"_minterFilter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_minimumPriceDecayHalfLifeSeconds","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_maximumPriceDecayHalfLifeSeconds","type":"uint256"}],"name":"AuctionHalfLifeRangeSecondsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_pricePerTokenInWei","type":"uint256"}],"name":"PricePerTokenInWeiUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"_currencyAddress","type":"address"},{"indexed":false,"internalType":"string","name":"_currencySymbol","type":"string"}],"name":"ProjectCurrencyInfoUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"_purchaseToDisabled","type":"bool"}],"name":"PurchaseToDisabledUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"ResetAuctionDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_auctionTimestampStart","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_priceDecayHalfLifeSeconds","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_startPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_basePrice","type":"uint256"}],"name":"SetAuctionDetails","type":"event"},{"inputs":[],"name":"genArt721CoreAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"getPriceInfo","outputs":[{"internalType":"bool","name":"isConfigured","type":"bool"},{"internalType":"uint256","name":"tokenPriceInWei","type":"uint256"},{"internalType":"string","name":"currencySymbol","type":"string"},{"internalType":"address","name":"currencyAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maximumPriceDecayHalfLifeSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumPriceDecayHalfLifeSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minterFilterAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minterType","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"projectAuctionParameters","outputs":[{"internalType":"uint256","name":"timestampStart","type":"uint256"},{"internalType":"uint256","name":"priceDecayHalfLifeSeconds","type":"uint256"},{"internalType":"uint256","name":"startPrice","type":"uint256"},{"internalType":"uint256","name":"basePrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"projectMaxHasBeenInvoked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"projectMaxInvocations","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"purchase","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"purchaseTo","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"resetAuctionDetails","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minimumPriceDecayHalfLifeSeconds","type":"uint256"},{"internalType":"uint256","name":"_maximumPriceDecayHalfLifeSeconds","type":"uint256"}],"name":"setAllowablePriceDecayHalfLifeRangeSeconds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"uint256","name":"_auctionTimestampStart","type":"uint256"},{"internalType":"uint256","name":"_priceDecayHalfLifeSeconds","type":"uint256"},{"internalType":"uint256","name":"_startPrice","type":"uint256"},{"internalType":"uint256","name":"_basePrice","type":"uint256"}],"name":"setAuctionDetails","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"setProjectMaxInvocations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"togglePurchaseToDisabled","outputs":[],"stateMutability":"view","type":"function"}]