编译器
0.8.26+commit.8a97fa7a
文件 1 的 16:AccessControl.sol
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
文件 2 的 16:Arrays.sol
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
import {Math} from "./math/Math.sol";
library Arrays {
using StorageSlot for bytes32;
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
low = mid + 1;
}
}
if (low > 0 && unsafeAccess(array, low - 1).value == element) {
return low - 1;
} else {
return low;
}
}
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
bytes32 slot;
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getAddressSlot();
}
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
bytes32 slot;
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getBytes32Slot();
}
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
bytes32 slot;
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getUint256Slot();
}
function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
}
文件 3 的 16:ArtTech.sol
pragma solidity ^0.8.26;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
contract ArtTech is AccessControl, ReentrancyGuard, ERC1155Supply {
function contractURI() public pure returns (string memory) {
return "https://art.tech/api/metadata/v1";
}
struct Round {
uint256 roundId;
uint256 startTime;
uint256 endTime;
address prizePoolAddress;
uint256 prizePoolTarget;
uint256 startArtId;
uint256 endArtId;
uint256 totalMintFees;
uint256 totalCreatorEarnings;
uint256 totalPrizePoolRewards;
uint256 totalProtocolFees;
uint256 totalTradingVolume;
}
Round public currentRound;
uint256 public artIdCounter;
uint256 public creatorEarningPercent = 200;
uint256 public prizePoolRewardPercent = 200;
uint256 public protocolFeePercent = 200;
uint256 public feePrecision = 10000;
uint256 public mintFee = 0.002 ether;
uint256 public prizePoolTarget;
address[] public prizePoolAddresses;
uint256 public currentPrizePoolIndex;
address public protocolFeeAddress;
mapping(uint256 => address) public artIdToCreator;
mapping(address => uint256) public addressToFreeMints;
uint256 public lifetimeMintFees;
uint256 public lifetimeCreatorEarnings;
uint256 public lifetimePrizePoolRewards;
uint256 public lifetimeProtocolFees;
uint256 public lifetimeTradingVolume;
struct AdminAction {
bytes32 actionId;
address proposer;
uint256 approvals;
bool executed;
uint256 expirationTime;
bytes data;
}
mapping(bytes32 => AdminAction) public pendingAdminActions;
bytes32[] public pendingActionIds;
uint256 public constant ACTION_EXPIRATION_TIME = 30 minutes;
uint256 public constant MAX_PENDING_ACTIONS = 10;
event ArtMinted(uint256 indexed artId, address indexed creator, uint256 indexed roundId, uint256 pricePaid);
event ArtBought(uint256 indexed artId, address indexed buyer, address indexed creator, uint256 roundId, uint256 amount, uint256 grossPrice, uint256 netPrice, uint256 creatorFee, uint256 prizePoolFee, uint256 protocolFee);
event ArtSold(uint256 indexed artId, address indexed seller, address indexed creator, uint256 roundId, uint256 amount, uint256 grossPrice, uint256 netPrice, uint256 creatorFee, uint256 prizePoolFee, uint256 protocolFee);
event RoundStarted(uint256 indexed roundId, uint256 startTime, address indexed prizePoolAddress, uint256 prizePoolTarget, uint256 startBalance, uint256 startArtId);
event RoundEnded(
uint256 indexed roundId,
uint256 endTime,
address indexed prizePoolAddress,
uint256 prizePoolTarget,
uint256 endBalance,
uint256 startArtId,
uint256 endArtId,
uint256 totalMintFees,
uint256 totalCreatorEarnings,
uint256 totalPrizePoolRewards,
uint256 totalProtocolFees,
uint256 totalTradingVolume
);
event AdminActionProposed(bytes32 indexed actionId, address indexed proposer);
event AdminActionApproved(bytes32 indexed actionId, address indexed approver);
event AdminActionExecuted(bytes32 indexed actionId);
event AdminActionPruned(bytes32 indexed actionId);
constructor(address _protocolFeeAddress, uint256 _prizePoolTarget, string memory _uri, address[] memory _initialPrizePoolAddresses, address _secondAdmin) ERC1155(_uri) {
require(_protocolFeeAddress != address(0), "Invalid protocol fee address");
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(DEFAULT_ADMIN_ROLE, _secondAdmin);
protocolFeeAddress = _protocolFeeAddress;
prizePoolTarget = _prizePoolTarget;
prizePoolAddresses = _initialPrizePoolAddresses;
currentPrizePoolIndex = 0;
currentRound = Round(
1,
block.timestamp,
0,
_initialPrizePoolAddresses[0],
_prizePoolTarget,
0,
0,
0,
0,
0,
0,
0
);
emit RoundStarted(
currentRound.roundId,
block.timestamp,
_initialPrizePoolAddresses[0],
_prizePoolTarget,
_initialPrizePoolAddresses[0].balance,
0
);
}
function mintArt(uint256 additionalToBuy) external payable nonReentrant returns (uint256) {
require(additionalToBuy <= 4, "Can acquire a maximum of 5 mints");
uint256 newArtId = artIdCounter;
uint256 totalCost = 0;
if (addressToFreeMints[msg.sender] == 0) {
totalCost += mintFee;
currentRound.totalMintFees += mintFee;
lifetimeMintFees += mintFee;
(bool feeSuccess,) = protocolFeeAddress.call{value: mintFee}("");
require(feeSuccess, "Failed to send minting fee");
emit ArtMinted(newArtId, msg.sender, currentRound.roundId, mintFee);
} else {
emit ArtMinted(newArtId, msg.sender, currentRound.roundId, 0);
addressToFreeMints[msg.sender]--;
}
_mint(msg.sender, newArtId, 1, "");
artIdToCreator[newArtId] = msg.sender;
artIdCounter++;
if (additionalToBuy > 0) {
uint256 netPrice = getBuyPrice(newArtId, additionalToBuy);
uint256 grossPrice = getBuyPriceAfterFees(newArtId, additionalToBuy);
totalCost += grossPrice;
uint256 creatorFee = netPrice * creatorEarningPercent / feePrecision;
uint256 prizePoolFee = netPrice * prizePoolRewardPercent / feePrecision;
uint256 protocolFee = netPrice * protocolFeePercent / feePrecision;
_mint(msg.sender, newArtId, additionalToBuy, "");
_sendFees(creatorFee, prizePoolFee, protocolFee, msg.sender);
lifetimeTradingVolume += grossPrice;
currentRound.totalTradingVolume += grossPrice;
emit ArtBought(newArtId, msg.sender, msg.sender, currentRound.roundId, additionalToBuy, grossPrice, netPrice, creatorFee, prizePoolFee, protocolFee);
}
require(msg.value >= totalCost, "Insufficient payment");
if (msg.value > totalCost) {
(bool success,) = msg.sender.call{value: msg.value - totalCost}("");
require(success, "Failed to refund excess ETH");
}
checkAndEndRound();
return newArtId;
}
function buyArt(uint256 artId, uint256 amount) external payable nonReentrant {
require(totalSupply(artId) > 0, "Art supply should be greater than 0");
uint256 netPrice = getBuyPrice(artId, amount);
uint256 grossPrice = getBuyPriceAfterFees(artId, amount);
require(msg.value >= grossPrice, "Insufficient payment");
if (msg.value > grossPrice) {
(bool success,) = msg.sender.call{value: msg.value - grossPrice}("");
require(success, "Failed to refund excess ETH");
}
uint256 creatorFee = netPrice * creatorEarningPercent / feePrecision;
uint256 prizePoolFee = netPrice * prizePoolRewardPercent / feePrecision;
uint256 protocolFee = netPrice * protocolFeePercent / feePrecision;
_mint(msg.sender, artId, amount, "");
_sendFees(creatorFee, prizePoolFee, protocolFee, artIdToCreator[artId]);
lifetimeTradingVolume += grossPrice;
currentRound.totalTradingVolume += grossPrice;
emit ArtBought(artId, msg.sender, artIdToCreator[artId], currentRound.roundId, amount, grossPrice, netPrice, creatorFee, prizePoolFee, protocolFee);
checkAndEndRound();
}
function sellArt(uint256 artId, uint256 minSupply, uint256 amount) external nonReentrant {
require(totalSupply(artId) >= minSupply, "Art supply should be greater than or equal to minSupply");
require(totalSupply(artId) > 1, "Cannot sell the last art");
require(balanceOf(msg.sender, artId) >= amount, "Insufficient balance");
if (msg.sender == artIdToCreator[artId]) {
require(balanceOf(msg.sender, artId) - amount > 0, "Creator cannot sell the last art");
}
uint256 grossPrice = getSellPrice(artId, amount);
uint256 netPrice = getSellPriceAfterFees(artId, amount);
uint256 creatorFee = (grossPrice * creatorEarningPercent) / feePrecision;
uint256 prizePoolFee = (grossPrice * prizePoolRewardPercent) / feePrecision;
uint256 protocolFee = (grossPrice * protocolFeePercent) / feePrecision;
(bool success,) = msg.sender.call{value: netPrice}("");
require(success, "Unable to send funds to seller");
_burn(msg.sender, artId, amount);
_sendFees(creatorFee, prizePoolFee, protocolFee, artIdToCreator[artId]);
lifetimeTradingVolume += grossPrice;
currentRound.totalTradingVolume += grossPrice;
emit ArtSold(artId, msg.sender, artIdToCreator[artId], currentRound.roundId, amount, grossPrice, netPrice, creatorFee, prizePoolFee, protocolFee);
checkAndEndRound();
}
function getPrice(uint256 supply, uint256 amount) public pure returns (uint256) {
uint256 sum1 = supply == 0 ? 0 : (supply - 1) * supply * (2 * (supply - 1) + 1) / 6;
uint256 sum2 = supply == 0 && amount == 1 ? 0 : (supply - 1 + amount) * (supply + amount) * (2 * (supply - 1 + amount) + 1) / 6;
uint256 summation = sum2 - sum1;
return summation * 1 ether / 16000;
}
function getBuyPrice(uint256 artId, uint256 amount) public view returns (uint256) {
return getPrice(totalSupply(artId), amount);
}
function getSellPrice(uint256 artId, uint256 amount) public view returns (uint256) {
return getPrice(totalSupply(artId) - amount, amount);
}
function getBuyPriceAfterFees(uint256 artId, uint256 amount) public view returns (uint256) {
uint256 price = getBuyPrice(artId, amount);
uint256 protocolFee = price * protocolFeePercent / feePrecision;
uint256 creatorEarning = price * creatorEarningPercent / feePrecision;
uint256 prizePoolReward = price * prizePoolRewardPercent / feePrecision;
return price + creatorEarning + prizePoolReward + protocolFee;
}
function getSellPriceAfterFees(uint256 artId, uint256 amount) public view returns (uint256) {
uint256 price = getSellPrice(artId, amount);
uint256 protocolFee = price * protocolFeePercent / feePrecision;
uint256 creatorEarning = price * creatorEarningPercent / feePrecision;
uint256 prizePoolReward = price * prizePoolRewardPercent / feePrecision;
return price - creatorEarning - prizePoolReward - protocolFee;
}
function checkAndEndRound() private {
address currentPrizePool = currentRound.prizePoolAddress;
if (currentPrizePool.balance >= currentRound.prizePoolTarget) {
currentRound.endTime = block.timestamp;
currentRound.endArtId = artIdCounter - 1;
emit RoundEnded(
currentRound.roundId,
currentRound.endTime,
currentPrizePool,
currentRound.prizePoolTarget,
currentPrizePool.balance,
currentRound.startArtId,
currentRound.endArtId,
currentRound.totalMintFees,
currentRound.totalCreatorEarnings,
currentRound.totalPrizePoolRewards,
currentRound.totalProtocolFees,
currentRound.totalTradingVolume
);
startNewRound();
}
}
function startNewRound() private {
currentPrizePoolIndex = (currentPrizePoolIndex + 1) % prizePoolAddresses.length;
address newPrizePool = prizePoolAddresses[currentPrizePoolIndex];
currentRound = Round(
currentRound.roundId + 1,
block.timestamp,
0,
newPrizePool,
prizePoolTarget,
artIdCounter,
0,
0,
0,
0,
0,
0
);
emit RoundStarted(currentRound.roundId, block.timestamp, newPrizePool, prizePoolTarget, newPrizePool.balance, artIdCounter);
}
function _sendFees(uint256 creatorEarning, uint256 prizePoolReward, uint256 protocolFee, address creator) private {
currentRound.prizePoolAddress.call{value: prizePoolReward}("");
protocolFeeAddress.call{value: protocolFee}("");
creator.call{value: creatorEarning}("");
lifetimeCreatorEarnings += creatorEarning;
lifetimePrizePoolRewards += prizePoolReward;
lifetimeProtocolFees += protocolFee;
currentRound.totalCreatorEarnings += creatorEarning;
currentRound.totalPrizePoolRewards += prizePoolReward;
currentRound.totalProtocolFees += protocolFee;
}
function proposeAdminAction(bytes32 actionId, bytes memory actionData) public onlyRole(DEFAULT_ADMIN_ROLE) {
require(pendingAdminActions[actionId].actionId == bytes32(0), "Action already proposed");
pruneExpiredActions();
require(pendingActionIds.length < MAX_PENDING_ACTIONS, "Too many pending actions");
pendingAdminActions[actionId] = AdminAction({actionId: actionId, proposer: msg.sender, approvals: 1, executed: false, expirationTime: block.timestamp + ACTION_EXPIRATION_TIME, data: actionData});
pendingActionIds.push(actionId);
emit AdminActionProposed(actionId, msg.sender);
}
function getPendingActionIds() external view returns (bytes32[] memory) {
return pendingActionIds;
}
function approveAdminAction(bytes32 actionId) external onlyRole(DEFAULT_ADMIN_ROLE) {
AdminAction storage action = pendingAdminActions[actionId];
require(action.actionId != bytes32(0), "Action not found");
require(!action.executed, "Action already executed");
require(block.timestamp < action.expirationTime, "Action expired");
require(action.proposer != msg.sender, "Proposer cannot approve");
action.approvals++;
emit AdminActionApproved(actionId, msg.sender);
if (action.approvals >= 2) {
action.executed = true;
executeAdminAction(actionId);
emit AdminActionExecuted(actionId);
removePendingAction(actionId);
}
}
function executeAdminAction(bytes32 actionId) internal {
AdminAction storage action = pendingAdminActions[actionId];
if (actionId == keccak256("SET_PROTOCOL_FEE_ADDRESS")) {
address newAddress = abi.decode(action.data, (address));
protocolFeeAddress = newAddress;
} else if (actionId == keccak256("SET_MINT_FEE")) {
uint256 newFee = abi.decode(action.data, (uint256));
require(newFee > 0, "Minting fee must be greater than 0");
mintFee = newFee;
} else if (actionId == keccak256("SET_FEE_PERCENTAGES")) {
(uint256 _protocolFeePercent, uint256 _creatorEarningPercent, uint256 _prizePoolRewardPercent) = abi.decode(action.data, (uint256, uint256, uint256));
require(_protocolFeePercent + _creatorEarningPercent + _prizePoolRewardPercent <= 3000, "Total fee percentage cannot exceed 30%");
require(_protocolFeePercent <= 1000, "Protocol fee percentage cannot exceed 10%");
require(_creatorEarningPercent <= 1000, "Creator earning percentage cannot exceed 10%");
require(_prizePoolRewardPercent <= 1000, "Prize pool reward percentage cannot exceed 10%");
protocolFeePercent = _protocolFeePercent;
creatorEarningPercent = _creatorEarningPercent;
prizePoolRewardPercent = _prizePoolRewardPercent;
} else if (actionId == keccak256("SET_PRIZE_POOL_TARGET")) {
uint256 newTarget = abi.decode(action.data, (uint256));
prizePoolTarget = newTarget;
} else if (actionId == keccak256("ADD_PRIZE_POOL_ADDRESS")) {
address newAddress = abi.decode(action.data, (address));
require(newAddress != address(0), "Invalid address");
prizePoolAddresses.push(newAddress);
} else if (actionId == keccak256("REMOVE_PRIZE_POOL_ADDRESS")) {
require(prizePoolAddresses.length > 1, "Cannot remove last prize pooladdress");
address addressToRemove = abi.decode(action.data, (address));
for (uint256 i; i < prizePoolAddresses.length; i++) {
if (prizePoolAddresses[i] == addressToRemove) {
prizePoolAddresses[i] = prizePoolAddresses[prizePoolAddresses.length - 1];
prizePoolAddresses.pop();
return;
}
}
revert("Address not found in prize pool addresses");
} else if (actionId == keccak256("ADD_FREE_MINT_ALLOWANCE")) {
(address[] memory users, uint256[] memory quantities) = abi.decode(action.data, (address[], uint256[]));
require(users.length == quantities.length, "Array lengths must match");
for (uint256 i; i < users.length; i++) {
require(users[i].code.length == 0, "Only EOA allowed");
addressToFreeMints[users[i]] += quantities[i];
}
} else if (actionId == keccak256("REMOVE_FREE_MINT_ALLOWANCE")) {
address user = abi.decode(action.data, (address));
delete addressToFreeMints[user];
} else if (actionId == keccak256("ADD_ADMIN")) {
address newAdmin = abi.decode(action.data, (address));
_grantRole(DEFAULT_ADMIN_ROLE, newAdmin);
} else if (actionId == keccak256("REMOVE_ADMIN")) {
address admin = abi.decode(action.data, (address));
_revokeRole(DEFAULT_ADMIN_ROLE, admin);
} else {
revert("Unknown action");
}
}
function pruneExpiredActions() public {
for (uint256 i = 0; i < pendingActionIds.length;) {
bytes32 actionId = pendingActionIds[i];
if (block.timestamp >= pendingAdminActions[actionId].expirationTime) {
removePendingAction(actionId);
emit AdminActionPruned(actionId);
} else {
i++;
}
}
}
function removePendingAction(bytes32 actionId) internal {
for (uint256 i; i < pendingActionIds.length; i++) {
if (pendingActionIds[i] == actionId) {
pendingActionIds[i] = pendingActionIds[pendingActionIds.length - 1];
pendingActionIds.pop();
delete pendingAdminActions[actionId];
break;
}
}
}
function proposeSetProtocolFeeAddress(address _protocolFeeAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {
bytes32 actionId = keccak256("SET_PROTOCOL_FEE_ADDRESS");
proposeAdminAction(actionId, abi.encode(_protocolFeeAddress));
}
function proposeSetMintFee(uint256 _mintFee) external onlyRole(DEFAULT_ADMIN_ROLE) {
bytes32 actionId = keccak256("SET_MINT_FEE");
proposeAdminAction(actionId, abi.encode(_mintFee));
}
function proposeSetFeePercentages(uint256 _protocolFeePercent, uint256 _creatorEarningPercent, uint256 _prizePoolRewardPercent) external onlyRole(DEFAULT_ADMIN_ROLE) {
bytes32 actionId = keccak256("SET_FEE_PERCENTAGES");
proposeAdminAction(actionId, abi.encode(_protocolFeePercent, _creatorEarningPercent, _prizePoolRewardPercent));
}
function proposeSetPrizePoolTarget(uint256 _prizePoolTarget) external onlyRole(DEFAULT_ADMIN_ROLE) {
bytes32 actionId = keccak256("SET_PRIZE_POOL_TARGET");
proposeAdminAction(actionId, abi.encode(_prizePoolTarget));
}
function proposeAddPrizePoolAddress(address newAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {
bytes32 actionId = keccak256("ADD_PRIZE_POOL_ADDRESS");
proposeAdminAction(actionId, abi.encode(newAddress));
}
function proposeRemovePrizePoolAddress(address addressToRemove) external onlyRole(DEFAULT_ADMIN_ROLE) {
bytes32 actionId = keccak256("REMOVE_PRIZE_POOL_ADDRESS");
proposeAdminAction(actionId, abi.encode(addressToRemove));
}
function proposeAddFreeMintAllowance(address[] calldata users, uint256[] calldata quantities) external onlyRole(DEFAULT_ADMIN_ROLE) {
bytes32 actionId = keccak256("ADD_FREE_MINT_ALLOWANCE");
proposeAdminAction(actionId, abi.encode(users, quantities));
}
function proposeRemoveFreeMintAllowance(address user) external onlyRole(DEFAULT_ADMIN_ROLE) {
bytes32 actionId = keccak256("REMOVE_FREE_MINT_ALLOWANCE");
proposeAdminAction(actionId, abi.encode(user));
}
function proposeAddAdmin(address newAdmin) external onlyRole(DEFAULT_ADMIN_ROLE) {
bytes32 actionId = keccak256("ADD_ADMIN");
proposeAdminAction(actionId, abi.encode(newAdmin));
}
function proposeRemoveAdmin(address admin) external onlyRole(DEFAULT_ADMIN_ROLE) {
bytes32 actionId = keccak256("REMOVE_ADMIN");
proposeAdminAction(actionId, abi.encode(admin));
}
function supportsInterface(bytes4 interfaceId) public view virtual override(AccessControl, ERC1155) returns (bool) {
return super.supportsInterface(interfaceId);
}
}
文件 4 的 16:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 5 的 16:ERC1155.sol
pragma solidity ^0.8.20;
import {IERC1155} from "./IERC1155.sol";
import {IERC1155Receiver} from "./IERC1155Receiver.sol";
import {IERC1155MetadataURI} from "./extensions/IERC1155MetadataURI.sol";
import {Context} from "../../utils/Context.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
import {Arrays} from "../../utils/Arrays.sol";
import {IERC1155Errors} from "../../interfaces/draft-IERC6093.sol";
abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IERC1155Errors {
using Arrays for uint256[];
using Arrays for address[];
mapping(uint256 id => mapping(address account => uint256)) private _balances;
mapping(address account => mapping(address operator => bool)) private _operatorApprovals;
string private _uri;
constructor(string memory uri_) {
_setURI(uri_);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
function uri(uint256 ) public view virtual returns (string memory) {
return _uri;
}
function balanceOf(address account, uint256 id) public view virtual returns (uint256) {
return _balances[id][account];
}
function balanceOfBatch(
address[] memory accounts,
uint256[] memory ids
) public view virtual returns (uint256[] memory) {
if (accounts.length != ids.length) {
revert ERC1155InvalidArrayLength(ids.length, accounts.length);
}
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts.unsafeMemoryAccess(i), ids.unsafeMemoryAccess(i));
}
return batchBalances;
}
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(address account, address operator) public view virtual returns (bool) {
return _operatorApprovals[account][operator];
}
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual {
address sender = _msgSender();
if (from != sender && !isApprovedForAll(from, sender)) {
revert ERC1155MissingApprovalForAll(sender, from);
}
_safeTransferFrom(from, to, id, value, data);
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) public virtual {
address sender = _msgSender();
if (from != sender && !isApprovedForAll(from, sender)) {
revert ERC1155MissingApprovalForAll(sender, from);
}
_safeBatchTransferFrom(from, to, ids, values, data);
}
function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual {
if (ids.length != values.length) {
revert ERC1155InvalidArrayLength(ids.length, values.length);
}
address operator = _msgSender();
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids.unsafeMemoryAccess(i);
uint256 value = values.unsafeMemoryAccess(i);
if (from != address(0)) {
uint256 fromBalance = _balances[id][from];
if (fromBalance < value) {
revert ERC1155InsufficientBalance(from, fromBalance, value, id);
}
unchecked {
_balances[id][from] = fromBalance - value;
}
}
if (to != address(0)) {
_balances[id][to] += value;
}
}
if (ids.length == 1) {
uint256 id = ids.unsafeMemoryAccess(0);
uint256 value = values.unsafeMemoryAccess(0);
emit TransferSingle(operator, from, to, id, value);
} else {
emit TransferBatch(operator, from, to, ids, values);
}
}
function _updateWithAcceptanceCheck(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) internal virtual {
_update(from, to, ids, values);
if (to != address(0)) {
address operator = _msgSender();
if (ids.length == 1) {
uint256 id = ids.unsafeMemoryAccess(0);
uint256 value = values.unsafeMemoryAccess(0);
_doSafeTransferAcceptanceCheck(operator, from, to, id, value, data);
} else {
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, values, data);
}
}
}
function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(from, to, ids, values, data);
}
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
_updateWithAcceptanceCheck(from, to, ids, values, data);
}
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
function _mint(address to, uint256 id, uint256 value, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(address(0), to, ids, values, data);
}
function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
_updateWithAcceptanceCheck(address(0), to, ids, values, data);
}
function _burn(address from, uint256 id, uint256 value) internal {
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
}
function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal {
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
}
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
if (operator == address(0)) {
revert ERC1155InvalidOperator(address(0));
}
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 value,
bytes memory data
) private {
if (to.code.length > 0) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert ERC1155InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
revert ERC1155InvalidReceiver(to);
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) private {
if (to.code.length > 0) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert ERC1155InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
revert ERC1155InvalidReceiver(to);
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
function _asSingletonArrays(
uint256 element1,
uint256 element2
) private pure returns (uint256[] memory array1, uint256[] memory array2) {
assembly {
array1 := mload(0x40)
mstore(array1, 1)
mstore(add(array1, 0x20), element1)
array2 := add(array1, 0x40)
mstore(array2, 1)
mstore(add(array2, 0x20), element2)
mstore(0x40, add(array2, 0x40))
}
}
}
文件 6 的 16:ERC1155Supply.sol
pragma solidity ^0.8.20;
import {ERC1155} from "../ERC1155.sol";
abstract contract ERC1155Supply is ERC1155 {
mapping(uint256 id => uint256) private _totalSupply;
uint256 private _totalSupplyAll;
function totalSupply(uint256 id) public view virtual returns (uint256) {
return _totalSupply[id];
}
function totalSupply() public view virtual returns (uint256) {
return _totalSupplyAll;
}
function exists(uint256 id) public view virtual returns (bool) {
return totalSupply(id) > 0;
}
function _update(
address from,
address to,
uint256[] memory ids,
uint256[] memory values
) internal virtual override {
super._update(from, to, ids, values);
if (from == address(0)) {
uint256 totalMintValue = 0;
for (uint256 i = 0; i < ids.length; ++i) {
uint256 value = values[i];
_totalSupply[ids[i]] += value;
totalMintValue += value;
}
_totalSupplyAll += totalMintValue;
}
if (to == address(0)) {
uint256 totalBurnValue = 0;
for (uint256 i = 0; i < ids.length; ++i) {
uint256 value = values[i];
unchecked {
_totalSupply[ids[i]] -= value;
totalBurnValue += value;
}
}
unchecked {
_totalSupplyAll -= totalBurnValue;
}
}
}
}
文件 7 的 16:ERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 8 的 16:IAccessControl.sol
pragma solidity ^0.8.20;
interface IAccessControl {
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
error AccessControlBadConfirmation();
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address callerConfirmation) external;
}
文件 9 的 16:IERC1155.sol
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
interface IERC1155 is IERC165 {
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
event URI(string value, uint256 indexed id);
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address account, address operator) external view returns (bool);
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external;
}
文件 10 的 16:IERC1155MetadataURI.sol
pragma solidity ^0.8.20;
import {IERC1155} from "../IERC1155.sol";
interface IERC1155MetadataURI is IERC1155 {
function uri(uint256 id) external view returns (string memory);
}
文件 11 的 16:IERC1155Receiver.sol
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
interface IERC1155Receiver is IERC165 {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
文件 12 的 16:IERC165.sol
pragma solidity ^0.8.20;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 13 的 16:Math.sol
pragma solidity ^0.8.20;
library Math {
error MathOverflowedMulDiv();
enum Rounding {
Floor,
Ceil,
Trunc,
Expand
}
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
return a / b;
}
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0 = x * y;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (0 - denominator);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}
文件 14 的 16:ReentrancyGuard.sol
pragma solidity ^0.8.20;
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
_status = ENTERED;
}
function _nonReentrantAfter() private {
_status = NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
文件 15 的 16:StorageSlot.sol
pragma solidity ^0.8.20;
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly {
r.slot := slot
}
}
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly {
r.slot := slot
}
}
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly {
r.slot := slot
}
}
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly {
r.slot := slot
}
}
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly {
r.slot := slot
}
}
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly {
r.slot := store.slot
}
}
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly {
r.slot := slot
}
}
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly {
r.slot := store.slot
}
}
}
文件 16 的 16:draft-IERC6093.sol
pragma solidity ^0.8.20;
interface IERC20Errors {
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
error ERC20InvalidSender(address sender);
error ERC20InvalidReceiver(address receiver);
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
error ERC20InvalidApprover(address approver);
error ERC20InvalidSpender(address spender);
}
interface IERC721Errors {
error ERC721InvalidOwner(address owner);
error ERC721NonexistentToken(uint256 tokenId);
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
error ERC721InvalidSender(address sender);
error ERC721InvalidReceiver(address receiver);
error ERC721InsufficientApproval(address operator, uint256 tokenId);
error ERC721InvalidApprover(address approver);
error ERC721InvalidOperator(address operator);
}
interface IERC1155Errors {
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
error ERC1155InvalidSender(address sender);
error ERC1155InvalidReceiver(address receiver);
error ERC1155MissingApprovalForAll(address operator, address owner);
error ERC1155InvalidApprover(address approver);
error ERC1155InvalidOperator(address operator);
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
{
"compilationTarget": {
"src/ArtTech.sol": "ArtTech"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"_protocolFeeAddress","type":"address"},{"internalType":"uint256","name":"_prizePoolTarget","type":"uint256"},{"internalType":"string","name":"_uri","type":"string"},{"internalType":"address[]","name":"_initialPrizePoolAddresses","type":"address[]"},{"internalType":"address","name":"_secondAdmin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC1155InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC1155InvalidApprover","type":"error"},{"inputs":[{"internalType":"uint256","name":"idsLength","type":"uint256"},{"internalType":"uint256","name":"valuesLength","type":"uint256"}],"name":"ERC1155InvalidArrayLength","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC1155InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC1155InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC1155InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC1155MissingApprovalForAll","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"actionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"approver","type":"address"}],"name":"AdminActionApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"actionId","type":"bytes32"}],"name":"AdminActionExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"actionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"proposer","type":"address"}],"name":"AdminActionProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"actionId","type":"bytes32"}],"name":"AdminActionPruned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","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":"artId","type":"uint256"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"grossPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"netPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creatorFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"prizePoolFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFee","type":"uint256"}],"name":"ArtBought","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"artId","type":"uint256"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pricePaid","type":"uint256"}],"name":"ArtMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"artId","type":"uint256"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"grossPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"netPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creatorFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"prizePoolFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFee","type":"uint256"}],"name":"ArtSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"},{"indexed":true,"internalType":"address","name":"prizePoolAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"prizePoolTarget","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startArtId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endArtId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalMintFees","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalCreatorEarnings","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalPrizePoolRewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalProtocolFees","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalTradingVolume","type":"uint256"}],"name":"RoundEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":true,"internalType":"address","name":"prizePoolAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"prizePoolTarget","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startArtId","type":"uint256"}],"name":"RoundStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"ACTION_EXPIRATION_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PENDING_ACTIONS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addressToFreeMints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"actionId","type":"bytes32"}],"name":"approveAdminAction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"artIdCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"artIdToCreator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"artId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"buyArt","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"creatorEarningPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentPrizePoolIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentRound","outputs":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"address","name":"prizePoolAddress","type":"address"},{"internalType":"uint256","name":"prizePoolTarget","type":"uint256"},{"internalType":"uint256","name":"startArtId","type":"uint256"},{"internalType":"uint256","name":"endArtId","type":"uint256"},{"internalType":"uint256","name":"totalMintFees","type":"uint256"},{"internalType":"uint256","name":"totalCreatorEarnings","type":"uint256"},{"internalType":"uint256","name":"totalPrizePoolRewards","type":"uint256"},{"internalType":"uint256","name":"totalProtocolFees","type":"uint256"},{"internalType":"uint256","name":"totalTradingVolume","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feePrecision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"artId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getBuyPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"artId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getBuyPriceAfterFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPendingActionIds","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"artId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getSellPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"artId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getSellPriceAfterFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lifetimeCreatorEarnings","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lifetimeMintFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lifetimePrizePoolRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lifetimeProtocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lifetimeTradingVolume","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"additionalToBuy","type":"uint256"}],"name":"mintArt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pendingActionIds","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"pendingAdminActions","outputs":[{"internalType":"bytes32","name":"actionId","type":"bytes32"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint256","name":"approvals","type":"uint256"},{"internalType":"bool","name":"executed","type":"bool"},{"internalType":"uint256","name":"expirationTime","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"prizePoolAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prizePoolRewardPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prizePoolTarget","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"proposeAddAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"uint256[]","name":"quantities","type":"uint256[]"}],"name":"proposeAddFreeMintAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"proposeAddPrizePoolAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"actionId","type":"bytes32"},{"internalType":"bytes","name":"actionData","type":"bytes"}],"name":"proposeAdminAction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"proposeRemoveAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"proposeRemoveFreeMintAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addressToRemove","type":"address"}],"name":"proposeRemovePrizePoolAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_protocolFeePercent","type":"uint256"},{"internalType":"uint256","name":"_creatorEarningPercent","type":"uint256"},{"internalType":"uint256","name":"_prizePoolRewardPercent","type":"uint256"}],"name":"proposeSetFeePercentages","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mintFee","type":"uint256"}],"name":"proposeSetMintFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_prizePoolTarget","type":"uint256"}],"name":"proposeSetPrizePoolTarget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolFeeAddress","type":"address"}],"name":"proposeSetProtocolFeeAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"protocolFeeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pruneExpiredActions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"artId","type":"uint256"},{"internalType":"uint256","name":"minSupply","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sellArt","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":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]