编译器
0.8.17+commit.8df45f5f
文件 1 的 25:AdminControl.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./IAdminControl.sol";
abstract contract AdminControl is Ownable, IAdminControl, ERC165 {
using EnumerableSet for EnumerableSet.AddressSet;
EnumerableSet.AddressSet private _admins;
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IAdminControl).interfaceId
|| super.supportsInterface(interfaceId);
}
modifier adminRequired() {
require(owner() == msg.sender || _admins.contains(msg.sender), "AdminControl: Must be owner or admin");
_;
}
function getAdmins() external view override returns (address[] memory admins) {
admins = new address[](_admins.length());
for (uint i = 0; i < _admins.length(); i++) {
admins[i] = _admins.at(i);
}
return admins;
}
function approveAdmin(address admin) external override onlyOwner {
if (!_admins.contains(admin)) {
emit AdminApproved(admin, msg.sender);
_admins.add(admin);
}
}
function revokeAdmin(address admin) external override onlyOwner {
if (_admins.contains(admin)) {
emit AdminRevoked(admin, msg.sender);
_admins.remove(admin);
}
}
function isAdmin(address admin) public override view returns (bool) {
return (owner() == admin || _admins.contains(admin));
}
}
文件 2 的 25:BurnRedeemCore.sol
pragma solidity ^0.8.0;
import "@manifoldxyz/creator-core-solidity/contracts/extensions/ICreatorExtensionTokenURI.sol";
import "@manifoldxyz/libraries-solidity/contracts/access/AdminControl.sol";
import "@manifoldxyz/libraries-solidity/contracts/access/IAdminControl.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "../../libraries/manifold-membership/IManifoldMembership.sol";
import "./BurnRedeemLib.sol";
import "./IBurnRedeemCore.sol";
import "./Interfaces.sol";
abstract contract BurnRedeemCore is ERC165, AdminControl, ReentrancyGuard, IBurnRedeemCore, ICreatorExtensionTokenURI {
using Strings for uint256;
uint256 public constant BURN_FEE = 690000000000000;
uint256 public constant MULTI_BURN_FEE = 990000000000000;
string internal constant ARWEAVE_PREFIX = "https://arweave.net/";
string internal constant IPFS_PREFIX = "ipfs://";
uint256 internal constant MAX_UINT_16 = 0xffff;
uint256 internal constant MAX_UINT_24 = 0xffffff;
uint256 internal constant MAX_UINT_32 = 0xffffffff;
uint256 internal constant MAX_UINT_56 = 0xffffffffffffff;
uint256 internal constant MAX_UINT_256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
mapping(address => mapping(uint256 => BurnRedeem)) internal _burnRedeems;
address public manifoldMembershipContract;
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165, AdminControl) returns (bool) {
return interfaceId == type(IBurnRedeemCore).interfaceId ||
interfaceId == type(IERC721Receiver).interfaceId ||
interfaceId == type(IERC1155Receiver).interfaceId ||
interfaceId == type(ICreatorExtensionTokenURI).interfaceId ||
super.supportsInterface(interfaceId);
}
modifier creatorAdminRequired(address creatorContractAddress) {
require(IAdminControl(creatorContractAddress).isAdmin(msg.sender), "Wallet is not an admin");
_;
}
function _initialize(
address creatorContractAddress,
uint8 creatorContractVersion,
uint256 instanceId,
BurnRedeemParameters calldata burnRedeemParameters
) internal {
BurnRedeemLib.initialize(creatorContractAddress, creatorContractVersion, instanceId, _burnRedeems[creatorContractAddress][instanceId], burnRedeemParameters);
}
function _update(
address creatorContractAddress,
uint256 instanceId,
BurnRedeemParameters calldata burnRedeemParameters
) internal {
BurnRedeemLib.update(creatorContractAddress, instanceId, _getBurnRedeem(creatorContractAddress, instanceId), burnRedeemParameters);
}
function getBurnRedeem(address creatorContractAddress, uint256 instanceId) external override view returns(BurnRedeem memory) {
return _getBurnRedeem(creatorContractAddress, instanceId);
}
function _getBurnRedeem(address creatorContractAddress, uint256 instanceId) internal view returns(BurnRedeem storage burnRedeemInstance) {
burnRedeemInstance = _burnRedeems[creatorContractAddress][instanceId];
require(burnRedeemInstance.storageProtocol != StorageProtocol.INVALID, "Burn redeem not initialized");
}
function _getActiveBurnRedeem(address creatorContractAddress, uint256 instanceId) private view returns(BurnRedeem storage burnRedeemInstance) {
burnRedeemInstance = _burnRedeems[creatorContractAddress][instanceId];
require(burnRedeemInstance.storageProtocol != StorageProtocol.INVALID, "Burn redeem not initialized");
require(
burnRedeemInstance.startDate <= block.timestamp &&
(block.timestamp < burnRedeemInstance.endDate || burnRedeemInstance.endDate == 0),
"Burn redeem not active"
);
}
function burnRedeem(address creatorContractAddress, uint256 instanceId, uint32 burnRedeemCount, BurnToken[] calldata burnTokens) external payable override nonReentrant {
uint256 payableCost = _burnRedeem(msg.value, creatorContractAddress, instanceId, burnRedeemCount, burnTokens, _isActiveMember(msg.sender), true);
if (msg.value > payableCost) {
_forwardValue(payable(msg.sender), msg.value - payableCost);
}
}
function burnRedeem(address[] calldata creatorContractAddresses, uint256[] calldata instanceIds, uint32[] calldata burnRedeemCounts, BurnToken[][] calldata burnTokens) external payable override nonReentrant {
require(
creatorContractAddresses.length == instanceIds.length &&
creatorContractAddresses.length == burnRedeemCounts.length &&
creatorContractAddresses.length == burnTokens.length,
"Invalid calldata"
);
bool isActiveMember = _isActiveMember(msg.sender);
uint256 msgValueRemaining = msg.value;
for (uint256 i; i < creatorContractAddresses.length;) {
msgValueRemaining -= _burnRedeem(msgValueRemaining, creatorContractAddresses[i], instanceIds[i], burnRedeemCounts[i], burnTokens[i], isActiveMember, false);
unchecked { ++i; }
}
if (msgValueRemaining != 0) {
_forwardValue(payable(msg.sender), msgValueRemaining);
}
}
function airdrop(address creatorContractAddress, uint256 instanceId, address[] calldata recipients, uint32[] calldata amounts) external override creatorAdminRequired(creatorContractAddress) {
require(recipients.length == amounts.length, "Invalid calldata");
BurnRedeem storage burnRedeemInstance = _getBurnRedeem(creatorContractAddress, instanceId);
uint256 totalAmount;
for (uint256 i; i < amounts.length;) {
totalAmount += amounts[i] * burnRedeemInstance.redeemAmount;
unchecked{ ++i; }
}
require(
totalAmount + burnRedeemInstance.redeemedCount <= MAX_UINT_32,
"Invalid amount"
);
for (uint256 i; i < recipients.length;) {
_redeem(creatorContractAddress, instanceId, burnRedeemInstance, recipients[i], amounts[i]);
unchecked{ ++i; }
}
BurnRedeemLib.syncTotalSupply(burnRedeemInstance);
}
function _burnRedeem(uint256 msgValue, address creatorContractAddress, uint256 instanceId, uint32 burnRedeemCount, BurnToken[] calldata burnTokens, bool isActiveMember, bool revertNoneRemaining) private returns (uint256) {
BurnRedeem storage burnRedeemInstance = _getActiveBurnRedeem(creatorContractAddress, instanceId);
burnRedeemCount = _getAvailableBurnRedeemCount(burnRedeemInstance.totalSupply, burnRedeemInstance.redeemedCount, burnRedeemInstance.redeemAmount, burnRedeemCount);
if (burnRedeemCount == 0) {
if (revertNoneRemaining) revert("No tokens available");
return 0;
}
uint256 payableCost = burnRedeemInstance.cost;
uint256 cost = burnRedeemInstance.cost;
if (!isActiveMember) {
payableCost += _getManifoldFee(burnTokens.length);
}
if (burnRedeemCount > 1) {
payableCost *= burnRedeemCount;
cost *= burnRedeemCount;
}
require(msgValue >= payableCost, "Invalid amount");
if (cost > 0) {
_forwardValue(burnRedeemInstance.paymentReceiver, cost);
}
_burnTokens(burnRedeemInstance, burnTokens, burnRedeemCount, msg.sender);
_redeem(creatorContractAddress, instanceId, burnRedeemInstance, msg.sender, burnRedeemCount);
return payableCost;
}
function recoverERC721(address tokenAddress, uint256 tokenId, address destination) external override adminRequired {
IERC721(tokenAddress).transferFrom(address(this), destination, tokenId);
}
function withdraw(address payable recipient, uint256 amount) external override adminRequired {
(bool sent, ) = recipient.call{value: amount}("");
require(sent, "Failed to transfer to recipient");
}
function setMembershipAddress(address addr) external override adminRequired {
manifoldMembershipContract = addr;
}
function onERC721Received(
address,
address from,
uint256 id,
bytes calldata data
) external override nonReentrant returns(bytes4) {
_onERC721Received(from, id, data);
return this.onERC721Received.selector;
}
function onERC1155Received(
address,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external override nonReentrant returns(bytes4) {
require(data.length % 32 == 0, "Invalid data");
address creatorContractAddress;
uint256 instanceId;
uint32 burnRedeemCount;
uint256 burnItemIndex;
bytes32[] memory merkleProof;
(creatorContractAddress, instanceId, burnRedeemCount, burnItemIndex, merkleProof) = abi.decode(data, (address, uint256, uint32, uint256, bytes32[]));
_onERC1155Received(from, id, value, creatorContractAddress, instanceId, burnRedeemCount, burnItemIndex, merkleProof);
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external override nonReentrant returns(bytes4) {
require(data.length % 32 == 0, "Invalid data");
address creatorContractAddress;
uint256 instanceId;
uint32 burnRedeemCount;
BurnToken[] memory burnTokens;
(creatorContractAddress, instanceId, burnRedeemCount, burnTokens) = abi.decode(data, (address, uint256, uint32, BurnToken[]));
_onERC1155BatchReceived(from, ids, values, creatorContractAddress, instanceId, burnRedeemCount, burnTokens);
return this.onERC1155BatchReceived.selector;
}
function _onERC721Received(
address from,
uint256 id,
bytes calldata data
) private {
require(data.length % 32 == 0, "Invalid data");
address creatorContractAddress;
uint256 instanceId;
uint256 burnItemIndex;
bytes32[] memory merkleProof;
(creatorContractAddress, instanceId, burnItemIndex, merkleProof) = abi.decode(data, (address, uint256, uint256, bytes32[]));
BurnRedeem storage burnRedeemInstance = _getActiveBurnRedeem(creatorContractAddress, instanceId);
require(
burnRedeemInstance.cost == 0 &&
burnRedeemInstance.burnSet.length == 1 &&
burnRedeemInstance.burnSet[0].requiredCount == 1 &&
_isActiveMember(from),
"Invalid input"
);
uint256 burnRedeemCount = _getAvailableBurnRedeemCount(burnRedeemInstance.totalSupply, burnRedeemInstance.redeemedCount, burnRedeemInstance.redeemAmount, 1);
require(burnRedeemCount != 0, "No tokens available");
BurnItem memory burnItem = burnRedeemInstance.burnSet[0].items[burnItemIndex];
require(burnItem.tokenSpec == TokenSpec.ERC721, "Invalid input");
BurnRedeemLib.validateBurnItem(burnItem, msg.sender, id, merkleProof);
_burn(burnItem, address(this), msg.sender, id, 1);
_redeem(creatorContractAddress, instanceId, burnRedeemInstance, from, 1);
}
function _onERC1155Received(address from, uint256 tokenId, uint256 value, address creatorContractAddress, uint256 instanceId, uint32 burnRedeemCount, uint256 burnItemIndex, bytes32[] memory merkleProof) private {
BurnRedeem storage burnRedeemInstance = _getActiveBurnRedeem(creatorContractAddress, instanceId);
require(
burnRedeemInstance.cost == 0 &&
burnRedeemInstance.burnSet.length == 1 &&
burnRedeemInstance.burnSet[0].requiredCount == 1 &&
_isActiveMember(from),
"Invalid input"
);
uint32 availableBurnRedeemCount = _getAvailableBurnRedeemCount(burnRedeemInstance.totalSupply, burnRedeemInstance.redeemedCount, burnRedeemInstance.redeemAmount, burnRedeemCount);
require(availableBurnRedeemCount != 0, "No tokens available");
BurnItem memory burnItem = burnRedeemInstance.burnSet[0].items[burnItemIndex];
require(value == burnItem.amount * burnRedeemCount, "Invalid input");
BurnRedeemLib.validateBurnItem(burnItem, msg.sender, tokenId, merkleProof);
_burn(burnItem, address(this), msg.sender, tokenId, availableBurnRedeemCount);
_redeem(creatorContractAddress, instanceId, burnRedeemInstance, from, availableBurnRedeemCount);
if (availableBurnRedeemCount != burnRedeemCount) {
IERC1155(msg.sender).safeTransferFrom(address(this), from, tokenId, (burnRedeemCount - availableBurnRedeemCount) * burnItem.amount, "");
}
}
function _onERC1155BatchReceived(address from, uint256[] memory tokenIds, uint256[] memory values, address creatorContractAddress, uint256 instanceId, uint32 burnRedeemCount, BurnToken[] memory burnTokens) private {
BurnRedeem storage burnRedeemInstance = _getActiveBurnRedeem(creatorContractAddress, instanceId);
require(
burnRedeemInstance.cost == 0 &&
burnTokens.length == tokenIds.length &&
_isActiveMember(from),
"Invalid input"
);
uint32 availableBurnRedeemCount = _getAvailableBurnRedeemCount(burnRedeemInstance.totalSupply, burnRedeemInstance.redeemedCount, burnRedeemInstance.redeemAmount, burnRedeemCount);
require(availableBurnRedeemCount != 0, "No tokens available");
uint256[] memory returnValues = new uint256[](tokenIds.length);
for (uint256 i; i < burnTokens.length;) {
BurnToken memory burnToken = burnTokens[i];
BurnItem memory burnItem = burnRedeemInstance.burnSet[burnToken.groupIndex].items[burnToken.itemIndex];
require(burnToken.id == tokenIds[i], "Invalid token");
require(burnItem.amount * burnRedeemCount == values[i], "Invalid amount");
if (availableBurnRedeemCount != burnRedeemCount) {
returnValues[i] = values[i] - burnItem.amount * availableBurnRedeemCount;
}
unchecked { ++i; }
}
_burnTokens(burnRedeemInstance, burnTokens, availableBurnRedeemCount, address(this));
_redeem(creatorContractAddress, instanceId, burnRedeemInstance, from, availableBurnRedeemCount);
if (availableBurnRedeemCount != burnRedeemCount) {
IERC1155(msg.sender).safeBatchTransferFrom(address(this), from, tokenIds, returnValues, "");
}
}
function _forwardValue(address payable receiver, uint256 amount) private {
(bool sent, ) = receiver.call{value: amount}("");
require(sent, "Failed to transfer to recipient");
}
function _burnTokens(BurnRedeem storage burnRedeemInstance, BurnToken[] memory burnTokens, uint256 burnRedeemCount, address owner) private {
uint256[] memory groupCounts = new uint256[](burnRedeemInstance.burnSet.length);
for (uint256 i; i < burnTokens.length;) {
BurnToken memory burnToken = burnTokens[i];
BurnItem memory burnItem = burnRedeemInstance.burnSet[burnToken.groupIndex].items[burnToken.itemIndex];
BurnRedeemLib.validateBurnItem(burnItem, burnToken.contractAddress, burnToken.id, burnToken.merkleProof);
_burn(burnItem, owner, burnToken.contractAddress, burnToken.id, burnRedeemCount);
groupCounts[burnToken.groupIndex] += burnRedeemCount;
unchecked { ++i; }
}
for (uint256 i; i < groupCounts.length;) {
require(groupCounts[i] == burnRedeemInstance.burnSet[i].requiredCount * burnRedeemCount, "Invalid number of tokens");
unchecked { ++i; }
}
}
function _getManifoldFee(uint256 burnTokenCount) private pure returns(uint256 fee) {
fee = burnTokenCount <= 1 ? BURN_FEE : MULTI_BURN_FEE;
}
function _isActiveMember(address sender) private view returns(bool) {
return manifoldMembershipContract != address(0) &&
IManifoldMembership(manifoldMembershipContract).isActiveMember(sender);
}
function _getAvailableBurnRedeemCount(uint32 totalSupply, uint32 redeemedCount, uint32 redeemAmount, uint32 desiredCount) internal pure returns(uint32 burnRedeemCount) {
if (totalSupply == 0) {
burnRedeemCount = desiredCount;
} else {
uint32 remainingCount = (totalSupply - redeemedCount) / redeemAmount;
if (remainingCount > desiredCount) {
burnRedeemCount = desiredCount;
} else {
burnRedeemCount = remainingCount;
}
}
}
function _redeem(address creatorContractAddress, uint256 instanceId, BurnRedeem storage burnRedeemInstance, address to, uint32 count) internal virtual;
function _burn(BurnItem memory burnItem, address from, address contractAddress, uint256 tokenId, uint256 burnRedeemCount) private {
if (burnItem.tokenSpec == TokenSpec.ERC1155) {
uint256 amount = burnItem.amount * burnRedeemCount;
if (burnItem.burnSpec == BurnSpec.NONE) {
IERC1155(contractAddress).safeTransferFrom(from, address(0xdEaD), tokenId, amount, "");
} else if (burnItem.burnSpec == BurnSpec.MANIFOLD) {
uint256[] memory tokenIds = new uint256[](1);
tokenIds[0] = tokenId;
uint256[] memory amounts = new uint256[](1);
amounts[0] = amount;
Manifold1155(contractAddress).burn(from, tokenIds, amounts);
} else if (burnItem.burnSpec == BurnSpec.OPENZEPPELIN) {
OZBurnable1155(contractAddress).burn(from, tokenId, amount);
} else {
revert("Invalid burn spec");
}
} else if (burnItem.tokenSpec == TokenSpec.ERC721) {
require(burnRedeemCount == 1, "Invalid burn count");
if (burnItem.burnSpec == BurnSpec.NONE) {
IERC721(contractAddress).safeTransferFrom(from, address(0xdEaD), tokenId, "");
} else if (burnItem.burnSpec == BurnSpec.MANIFOLD || burnItem.burnSpec == BurnSpec.OPENZEPPELIN) {
if (from != address(this)) {
require(IERC721(contractAddress).ownerOf(tokenId) == from, "Sender is not owner");
}
Burnable721(contractAddress).burn(tokenId);
} else {
revert("Invalid burn spec");
}
} else {
revert("Invalid token spec");
}
}
}
文件 3 的 25:BurnRedeemLib.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "./IBurnRedeemCore.sol";
library BurnRedeemLib {
event BurnRedeemInitialized(address indexed creatorContract, uint256 indexed instanceId, address initializer);
event BurnRedeemUpdated(address indexed creatorContract, uint256 indexed instanceId);
event BurnRedeemMint(address indexed creatorContract, uint256 indexed instanceId, uint256 indexed tokenId, uint32 redeemedCount);
function initialize(
address creatorContractAddress,
uint8 creatorContractVersion,
uint256 instanceId,
IBurnRedeemCore.BurnRedeem storage burnRedeemInstance,
IBurnRedeemCore.BurnRedeemParameters calldata burnRedeemParameters
) public {
require(burnRedeemInstance.storageProtocol == IBurnRedeemCore.StorageProtocol.INVALID, "Burn redeem already initialized");
_validateParameters(burnRedeemParameters);
burnRedeemInstance.contractVersion = creatorContractVersion;
_setParameters(burnRedeemInstance, burnRedeemParameters);
_setBurnGroups(burnRedeemInstance, burnRedeemParameters.burnSet);
emit BurnRedeemInitialized(creatorContractAddress, instanceId, msg.sender);
}
function update(
address creatorContractAddress,
uint256 instanceId,
IBurnRedeemCore.BurnRedeem storage burnRedeemInstance,
IBurnRedeemCore.BurnRedeemParameters calldata burnRedeemParameters
) public {
require(burnRedeemInstance.storageProtocol != IBurnRedeemCore.StorageProtocol.INVALID, "Burn redeem not initialized");
_validateParameters(burnRedeemParameters);
require(burnRedeemInstance.redeemedCount % burnRedeemParameters.redeemAmount == 0, "Invalid amount");
_setParameters(burnRedeemInstance, burnRedeemParameters);
_setBurnGroups(burnRedeemInstance, burnRedeemParameters.burnSet);
syncTotalSupply(burnRedeemInstance);
emit BurnRedeemUpdated(creatorContractAddress, instanceId);
}
function syncTotalSupply(IBurnRedeemCore.BurnRedeem storage burnRedeemInstance) public {
if (
burnRedeemInstance.totalSupply != 0 &&
burnRedeemInstance.redeemedCount > burnRedeemInstance.totalSupply
) {
burnRedeemInstance.totalSupply = burnRedeemInstance.redeemedCount;
}
}
function validateBurnItem(IBurnRedeemCore.BurnItem memory burnItem, address contractAddress, uint256 tokenId, bytes32[] memory merkleProof) public pure {
require(contractAddress == burnItem.contractAddress, "Invalid burn token");
if (burnItem.validationType == IBurnRedeemCore.ValidationType.CONTRACT) {
return;
} else if (burnItem.validationType == IBurnRedeemCore.ValidationType.RANGE) {
require(tokenId >= burnItem.minTokenId && tokenId <= burnItem.maxTokenId, "Invalid token ID");
return;
} else if (burnItem.validationType == IBurnRedeemCore.ValidationType.MERKLE_TREE) {
bytes32 leaf = keccak256(abi.encodePacked(tokenId));
require(MerkleProof.verify(merkleProof, burnItem.merkleRoot, leaf), "Invalid merkle proof");
return;
}
revert("Invalid burn item");
}
function _validateParameters(IBurnRedeemCore.BurnRedeemParameters calldata burnRedeemParameters) internal pure {
require(burnRedeemParameters.storageProtocol != IBurnRedeemCore.StorageProtocol.INVALID, "Storage protocol invalid");
require(burnRedeemParameters.paymentReceiver != address(0), "Payment receiver required");
require(burnRedeemParameters.endDate == 0 || burnRedeemParameters.startDate < burnRedeemParameters.endDate, "startDate after endDate");
require(burnRedeemParameters.totalSupply % burnRedeemParameters.redeemAmount == 0, "Remainder left from totalSupply");
}
function _setParameters(IBurnRedeemCore.BurnRedeem storage burnRedeemInstance, IBurnRedeemCore.BurnRedeemParameters calldata burnRedeemParameters) private {
burnRedeemInstance.startDate = burnRedeemParameters.startDate;
burnRedeemInstance.endDate = burnRedeemParameters.endDate;
burnRedeemInstance.redeemAmount = burnRedeemParameters.redeemAmount;
burnRedeemInstance.totalSupply = burnRedeemParameters.totalSupply;
burnRedeemInstance.storageProtocol = burnRedeemParameters.storageProtocol;
burnRedeemInstance.location = burnRedeemParameters.location;
burnRedeemInstance.cost = burnRedeemParameters.cost;
burnRedeemInstance.paymentReceiver = burnRedeemParameters.paymentReceiver;
}
function _setBurnGroups(IBurnRedeemCore.BurnRedeem storage burnRedeemInstance, IBurnRedeemCore.BurnGroup[] calldata burnGroups) private {
delete burnRedeemInstance.burnSet;
for (uint256 i; i < burnGroups.length;) {
burnRedeemInstance.burnSet.push();
IBurnRedeemCore.BurnGroup storage burnGroup = burnRedeemInstance.burnSet[i];
require(
burnGroups[i].requiredCount > 0 &&
burnGroups[i].requiredCount <= burnGroups[i].items.length,
"Invalid input"
);
burnGroup.requiredCount = burnGroups[i].requiredCount;
for (uint256 j; j < burnGroups[i].items.length;) {
IBurnRedeemCore.BurnItem memory burnItem = burnGroups[i].items[j];
require(
(
(burnItem.tokenSpec == IBurnRedeemCore.TokenSpec.ERC1155 && burnItem.amount > 0) ||
(burnItem.tokenSpec == IBurnRedeemCore.TokenSpec.ERC721 && burnItem.amount == 0)
) &&
burnItem.validationType != IBurnRedeemCore.ValidationType.INVALID,
"Invalid input");
burnGroup.items.push(burnGroups[i].items[j]);
unchecked { ++j; }
}
unchecked { ++i; }
}
}
}
文件 4 的 25:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 5 的 25:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 6 的 25:ERC721BurnRedeem.sol
pragma solidity ^0.8.0;
import "@manifoldxyz/creator-core-solidity/contracts/core/IERC721CreatorCore.sol";
import "./BurnRedeemCore.sol";
import "./BurnRedeemLib.sol";
import "./IERC721BurnRedeem.sol";
import "../../libraries/IERC721CreatorCoreVersion.sol";
contract ERC721BurnRedeem is BurnRedeemCore, IERC721BurnRedeem {
using Strings for uint256;
mapping(address => mapping(uint256 => RedeemToken)) internal _redeemTokens;
mapping(address => mapping(uint256 => bool)) private _identicalTokenURI;
function supportsInterface(bytes4 interfaceId) public view virtual override(BurnRedeemCore, IERC165) returns (bool) {
return interfaceId == type(IERC721BurnRedeem).interfaceId || super.supportsInterface(interfaceId);
}
function initializeBurnRedeem(
address creatorContractAddress,
uint256 instanceId,
BurnRedeemParameters calldata burnRedeemParameters,
bool identicalTokenURI
) external creatorAdminRequired(creatorContractAddress) {
require(instanceId > 0 && instanceId <= MAX_UINT_56, "Invalid instanceId");
uint8 creatorContractVersion;
try IERC721CreatorCoreVersion(creatorContractAddress).VERSION() returns(uint256 version) {
require(version <= 255, "Unsupported contract version");
creatorContractVersion = uint8(version);
} catch {}
_initialize(creatorContractAddress, creatorContractVersion, instanceId, burnRedeemParameters);
_identicalTokenURI[creatorContractAddress][instanceId] = identicalTokenURI;
}
function updateBurnRedeem(
address creatorContractAddress,
uint256 instanceId,
BurnRedeemParameters calldata burnRedeemParameters,
bool identicalTokenURI
) external creatorAdminRequired(creatorContractAddress) {
_update(creatorContractAddress, instanceId, burnRedeemParameters);
_identicalTokenURI[creatorContractAddress][instanceId] = identicalTokenURI;
}
function updateTokenURI(
address creatorContractAddress,
uint256 instanceId,
StorageProtocol storageProtocol,
string calldata location,
bool identicalTokenURI
) external override creatorAdminRequired(creatorContractAddress) {
BurnRedeem storage burnRedeemInstance = _getBurnRedeem(creatorContractAddress, instanceId);
burnRedeemInstance.storageProtocol = storageProtocol;
burnRedeemInstance.location = location;
_identicalTokenURI[creatorContractAddress][instanceId] = identicalTokenURI;
emit BurnRedeemLib.BurnRedeemUpdated(creatorContractAddress, instanceId);
}
function _redeem(address creatorContractAddress, uint256 instanceId, BurnRedeem storage burnRedeemInstance, address to, uint32 count) internal override {
if (burnRedeemInstance.redeemAmount == 1 && count == 1) {
++burnRedeemInstance.redeemedCount;
uint256 newTokenId;
if (burnRedeemInstance.contractVersion >= 3) {
uint80 tokenData = uint56(instanceId) << 24 | burnRedeemInstance.redeemedCount;
newTokenId = IERC721CreatorCore(creatorContractAddress).mintExtension(to, tokenData);
} else {
newTokenId = IERC721CreatorCore(creatorContractAddress).mintExtension(to);
_redeemTokens[creatorContractAddress][newTokenId] = RedeemToken(uint224(instanceId), burnRedeemInstance.redeemedCount);
}
emit BurnRedeemLib.BurnRedeemMint(creatorContractAddress, instanceId, newTokenId, 1);
} else {
uint256 totalCount = burnRedeemInstance.redeemAmount * count;
require(totalCount <= MAX_UINT_16, "Invalid input");
uint256 startingCount = burnRedeemInstance.redeemedCount + 1;
burnRedeemInstance.redeemedCount += uint32(totalCount);
if (burnRedeemInstance.contractVersion >= 3) {
uint80[] memory tokenDatas = new uint80[](totalCount);
for (uint256 i; i < totalCount;) {
tokenDatas[i] = uint56(instanceId) << 24 | uint24(startingCount+i);
unchecked { ++i; }
}
uint256[] memory newTokenIds = IERC721CreatorCore(creatorContractAddress).mintExtensionBatch(to, tokenDatas);
for (uint256 i; i < totalCount;) {
emit BurnRedeemLib.BurnRedeemMint(creatorContractAddress, instanceId, newTokenIds[i], 1);
unchecked { i++; }
}
} else {
uint256[] memory newTokenIds = IERC721CreatorCore(creatorContractAddress).mintExtensionBatch(to, uint16(totalCount));
for (uint256 i; i < totalCount;) {
_redeemTokens[creatorContractAddress][newTokenIds[i]] = RedeemToken(uint224(instanceId), uint32(startingCount + i));
emit BurnRedeemLib.BurnRedeemMint(creatorContractAddress, instanceId, newTokenIds[i], 1);
unchecked { i++; }
}
}
}
}
function tokenURI(address creatorContractAddress, uint256 tokenId) external override view returns(string memory uri) {
RedeemToken memory token = _redeemTokens[creatorContractAddress][tokenId];
BurnRedeem memory burnRedeem;
uint256 mintNumber;
uint256 instanceId;
if (token.instanceId == 0) {
uint80 tokenData = IERC721CreatorCore(creatorContractAddress).tokenData(tokenId);
instanceId = uint56(tokenData >> 24);
require(instanceId != 0, "Token does not exist");
mintNumber = uint24(tokenData & MAX_UINT_24);
} else {
instanceId = token.instanceId;
mintNumber = token.mintNumber;
}
burnRedeem = _burnRedeems[creatorContractAddress][instanceId];
string memory prefix = "";
if (burnRedeem.storageProtocol == StorageProtocol.ARWEAVE) {
prefix = ARWEAVE_PREFIX;
} else if (burnRedeem.storageProtocol == StorageProtocol.IPFS) {
prefix = IPFS_PREFIX;
}
uri = string(abi.encodePacked(prefix, burnRedeem.location));
if (!_identicalTokenURI[creatorContractAddress][instanceId]) {
uri = string(abi.encodePacked(uri, "/", uint256(mintNumber).toString()));
}
}
function getBurnRedeemForToken(address creatorContractAddress, uint256 tokenId) external override view returns(uint256 instanceId, BurnRedeem memory burnRedeem) {
RedeemToken memory token = _redeemTokens[creatorContractAddress][tokenId];
if (token.instanceId == 0) {
uint80 tokenData = IERC721CreatorCore(creatorContractAddress).tokenData(tokenId);
instanceId = uint56(tokenData >> 24);
} else {
instanceId = token.instanceId;
}
require(instanceId != 0, "Token does not exist");
burnRedeem = _burnRedeems[creatorContractAddress][instanceId];
}
}
文件 7 的 25:EnumerableSet.sol
pragma solidity ^0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
set._values[toDeleteIndex] = lastValue;
set._indexes[lastValue] = valueIndex;
}
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 8 的 25:IAdminControl.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IAdminControl is IERC165 {
event AdminApproved(address indexed account, address indexed sender);
event AdminRevoked(address indexed account, address indexed sender);
function getAdmins() external view returns (address[] memory);
function approveAdmin(address admin) external;
function revokeAdmin(address admin) external;
function isAdmin(address admin) external view returns (bool);
}
文件 9 的 25:IBurnRedeemCore.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IBurnRedeemCore is IERC165, IERC721Receiver, IERC1155Receiver {
enum StorageProtocol { INVALID, NONE, ARWEAVE, IPFS }
enum ValidationType { INVALID, CONTRACT, RANGE, MERKLE_TREE }
enum TokenSpec { INVALID, ERC721, ERC1155 }
enum BurnSpec { NONE, MANIFOLD, OPENZEPPELIN }
struct BurnItem {
ValidationType validationType;
address contractAddress;
TokenSpec tokenSpec;
BurnSpec burnSpec;
uint72 amount;
uint256 minTokenId;
uint256 maxTokenId;
bytes32 merkleRoot;
}
struct BurnGroup {
uint256 requiredCount;
BurnItem[] items;
}
struct BurnRedeemParameters {
address payable paymentReceiver;
StorageProtocol storageProtocol;
uint16 redeemAmount;
uint32 totalSupply;
uint48 startDate;
uint48 endDate;
uint160 cost;
string location;
BurnGroup[] burnSet;
}
struct BurnRedeem {
address payable paymentReceiver;
StorageProtocol storageProtocol;
uint32 redeemedCount;
uint16 redeemAmount;
uint32 totalSupply;
uint8 contractVersion;
uint48 startDate;
uint48 endDate;
uint160 cost;
string location;
BurnGroup[] burnSet;
}
struct BurnToken {
uint48 groupIndex;
uint48 itemIndex;
address contractAddress;
uint256 id;
bytes32[] merkleProof;
}
function getBurnRedeem(address creatorContractAddress, uint256 instanceId) external view returns(BurnRedeem memory);
function getBurnRedeemForToken(address creatorContractAddress, uint256 tokenId) external view returns(uint256, BurnRedeem memory);
function burnRedeem(address creatorContractAddress, uint256 instanceId, uint32 burnRedeemCount, BurnToken[] calldata burnTokens) external payable;
function burnRedeem(address[] calldata creatorContractAddresses, uint256[] calldata instanceIds, uint32[] calldata burnRedeemCounts, BurnToken[][] calldata burnTokens) external payable;
function airdrop(address creatorContractAddress, uint256 instanceId, address[] calldata recipients, uint32[] calldata amounts) external;
function recoverERC721(address tokenAddress, uint256 tokenId, address destination) external;
function withdraw(address payable recipient, uint256 amount) external;
function setMembershipAddress(address addr) external;
}
文件 10 的 25:ICreatorCore.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface ICreatorCore is IERC165 {
event ExtensionRegistered(address indexed extension, address indexed sender);
event ExtensionUnregistered(address indexed extension, address indexed sender);
event ExtensionBlacklisted(address indexed extension, address indexed sender);
event MintPermissionsUpdated(address indexed extension, address indexed permissions, address indexed sender);
event RoyaltiesUpdated(uint256 indexed tokenId, address payable[] receivers, uint256[] basisPoints);
event DefaultRoyaltiesUpdated(address payable[] receivers, uint256[] basisPoints);
event ApproveTransferUpdated(address extension);
event ExtensionRoyaltiesUpdated(address indexed extension, address payable[] receivers, uint256[] basisPoints);
event ExtensionApproveTransferUpdated(address indexed extension, bool enabled);
function getExtensions() external view returns (address[] memory);
function registerExtension(address extension, string calldata baseURI) external;
function registerExtension(address extension, string calldata baseURI, bool baseURIIdentical) external;
function unregisterExtension(address extension) external;
function blacklistExtension(address extension) external;
function setBaseTokenURIExtension(string calldata uri) external;
function setBaseTokenURIExtension(string calldata uri, bool identical) external;
function setTokenURIPrefixExtension(string calldata prefix) external;
function setTokenURIExtension(uint256 tokenId, string calldata uri) external;
function setTokenURIExtension(uint256[] memory tokenId, string[] calldata uri) external;
function setBaseTokenURI(string calldata uri) external;
function setTokenURIPrefix(string calldata prefix) external;
function setTokenURI(uint256 tokenId, string calldata uri) external;
function setTokenURI(uint256[] memory tokenIds, string[] calldata uris) external;
function setMintPermissions(address extension, address permissions) external;
function setApproveTransferExtension(bool enabled) external;
function tokenExtension(uint256 tokenId) external view returns (address);
function setRoyalties(address payable[] calldata receivers, uint256[] calldata basisPoints) external;
function setRoyalties(uint256 tokenId, address payable[] calldata receivers, uint256[] calldata basisPoints) external;
function setRoyaltiesExtension(address extension, address payable[] calldata receivers, uint256[] calldata basisPoints) external;
function getRoyalties(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory);
function getFeeRecipients(uint256 tokenId) external view returns (address payable[] memory);
function getFeeBps(uint256 tokenId) external view returns (uint[] memory);
function getFees(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory);
function royaltyInfo(uint256 tokenId, uint256 value) external view returns (address, uint256);
function setApproveTransfer(address extension) external;
function getApproveTransfer() external view returns (address);
}
文件 11 的 25:ICreatorExtensionTokenURI.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface ICreatorExtensionTokenURI is IERC165 {
function tokenURI(address creator, uint256 tokenId) external view returns (string memory);
}
文件 12 的 25:IERC1155.sol
pragma solidity ^0.8.0;
import "../../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 amount,
bytes calldata data
) external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
文件 13 的 25:IERC1155Receiver.sol
pragma solidity ^0.8.0;
import "../../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);
}
文件 14 的 25:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 15 的 25:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
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);
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,
bytes calldata data
) external;
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 setApprovalForAll(address operator, bool _approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
文件 16 的 25:IERC721BurnRedeem.sol
pragma solidity ^0.8.0;
import "./IBurnRedeemCore.sol";
interface IERC721BurnRedeem is IBurnRedeemCore {
struct RedeemToken {
uint224 instanceId;
uint32 mintNumber;
}
function initializeBurnRedeem(address creatorContractAddress, uint256 instanceId, BurnRedeemParameters calldata burnRedeemParameters, bool identicalTokenURI) external;
function updateBurnRedeem(address creatorContractAddress, uint256 instanceId, BurnRedeemParameters calldata burnRedeemParameters, bool identicalTokenURI) external;
function updateTokenURI(address creatorContractAddress, uint256 instanceId, StorageProtocol storageProtocol, string calldata location, bool identicalTokenURI) external;
}
文件 17 的 25:IERC721CreatorCore.sol
pragma solidity ^0.8.0;
import "./ICreatorCore.sol";
interface IERC721CreatorCore is ICreatorCore {
function mintBase(address to) external returns (uint256);
function mintBase(address to, string calldata uri) external returns (uint256);
function mintBaseBatch(address to, uint16 count) external returns (uint256[] memory);
function mintBaseBatch(address to, string[] calldata uris) external returns (uint256[] memory);
function mintExtension(address to) external returns (uint256);
function mintExtension(address to, string calldata uri) external returns (uint256);
function mintExtension(address to, uint80 data) external returns (uint256);
function mintExtensionBatch(address to, uint16 count) external returns (uint256[] memory);
function mintExtensionBatch(address to, string[] calldata uris) external returns (uint256[] memory);
function mintExtensionBatch(address to, uint80[] calldata data) external returns (uint256[] memory);
function burn(uint256 tokenId) external;
function tokenData(uint256 tokenId) external view returns (uint80);
}
文件 18 的 25:IERC721CreatorCoreVersion.sol
pragma solidity ^0.8.0;
interface IERC721CreatorCoreVersion {
function VERSION() external view returns(uint256);
}
文件 19 的 25:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 20 的 25:IManifoldMembership.sol
pragma solidity ^0.8.0;
interface IManifoldMembership {
function isActiveMember(address sender) external view returns (bool);
}
文件 21 的 25:Interfaces.sol
pragma solidity ^0.8.0;
interface Burnable721 {
function burn(uint256 tokenId) external;
}
interface OZBurnable1155 {
function burn(address account, uint256 id, uint256 value) external;
}
interface Manifold1155 {
function burn(address account, uint256[] memory tokenIds, uint256[] memory amounts) external;
}
文件 22 的 25:MerkleProof.sol
pragma solidity ^0.8.0;
library MerkleProof {
function verify(
bytes32[] memory proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
function verifyCalldata(
bytes32[] calldata proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
文件 23 的 25:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 24 的 25: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;
}
}
文件 25 的 25:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
{
"compilationTarget": {
"contracts/manifold/burnredeem/ERC721BurnRedeem.sol": "ERC721BurnRedeem"
},
"evmVersion": "london",
"libraries": {
"contracts/manifold/burnredeem/BurnRedeemLib.sol:BurnRedeemLib": "0xf56dfc2f506f3fbe85d33fd70653d7bac0907d56"
},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 150
},
"remappings": []
}
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"AdminApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"AdminRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"BURN_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MULTI_BURN_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"instanceId","type":"uint256"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint32[]","name":"amounts","type":"uint32[]"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"approveAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"creatorContractAddresses","type":"address[]"},{"internalType":"uint256[]","name":"instanceIds","type":"uint256[]"},{"internalType":"uint32[]","name":"burnRedeemCounts","type":"uint32[]"},{"components":[{"internalType":"uint48","name":"groupIndex","type":"uint48"},{"internalType":"uint48","name":"itemIndex","type":"uint48"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"internalType":"struct IBurnRedeemCore.BurnToken[][]","name":"burnTokens","type":"tuple[][]"}],"name":"burnRedeem","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"instanceId","type":"uint256"},{"internalType":"uint32","name":"burnRedeemCount","type":"uint32"},{"components":[{"internalType":"uint48","name":"groupIndex","type":"uint48"},{"internalType":"uint48","name":"itemIndex","type":"uint48"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"internalType":"struct IBurnRedeemCore.BurnToken[]","name":"burnTokens","type":"tuple[]"}],"name":"burnRedeem","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getAdmins","outputs":[{"internalType":"address[]","name":"admins","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"instanceId","type":"uint256"}],"name":"getBurnRedeem","outputs":[{"components":[{"internalType":"address payable","name":"paymentReceiver","type":"address"},{"internalType":"enum IBurnRedeemCore.StorageProtocol","name":"storageProtocol","type":"uint8"},{"internalType":"uint32","name":"redeemedCount","type":"uint32"},{"internalType":"uint16","name":"redeemAmount","type":"uint16"},{"internalType":"uint32","name":"totalSupply","type":"uint32"},{"internalType":"uint8","name":"contractVersion","type":"uint8"},{"internalType":"uint48","name":"startDate","type":"uint48"},{"internalType":"uint48","name":"endDate","type":"uint48"},{"internalType":"uint160","name":"cost","type":"uint160"},{"internalType":"string","name":"location","type":"string"},{"components":[{"internalType":"uint256","name":"requiredCount","type":"uint256"},{"components":[{"internalType":"enum IBurnRedeemCore.ValidationType","name":"validationType","type":"uint8"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"enum IBurnRedeemCore.TokenSpec","name":"tokenSpec","type":"uint8"},{"internalType":"enum IBurnRedeemCore.BurnSpec","name":"burnSpec","type":"uint8"},{"internalType":"uint72","name":"amount","type":"uint72"},{"internalType":"uint256","name":"minTokenId","type":"uint256"},{"internalType":"uint256","name":"maxTokenId","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct IBurnRedeemCore.BurnItem[]","name":"items","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnGroup[]","name":"burnSet","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnRedeem","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getBurnRedeemForToken","outputs":[{"internalType":"uint256","name":"instanceId","type":"uint256"},{"components":[{"internalType":"address payable","name":"paymentReceiver","type":"address"},{"internalType":"enum IBurnRedeemCore.StorageProtocol","name":"storageProtocol","type":"uint8"},{"internalType":"uint32","name":"redeemedCount","type":"uint32"},{"internalType":"uint16","name":"redeemAmount","type":"uint16"},{"internalType":"uint32","name":"totalSupply","type":"uint32"},{"internalType":"uint8","name":"contractVersion","type":"uint8"},{"internalType":"uint48","name":"startDate","type":"uint48"},{"internalType":"uint48","name":"endDate","type":"uint48"},{"internalType":"uint160","name":"cost","type":"uint160"},{"internalType":"string","name":"location","type":"string"},{"components":[{"internalType":"uint256","name":"requiredCount","type":"uint256"},{"components":[{"internalType":"enum IBurnRedeemCore.ValidationType","name":"validationType","type":"uint8"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"enum IBurnRedeemCore.TokenSpec","name":"tokenSpec","type":"uint8"},{"internalType":"enum IBurnRedeemCore.BurnSpec","name":"burnSpec","type":"uint8"},{"internalType":"uint72","name":"amount","type":"uint72"},{"internalType":"uint256","name":"minTokenId","type":"uint256"},{"internalType":"uint256","name":"maxTokenId","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct IBurnRedeemCore.BurnItem[]","name":"items","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnGroup[]","name":"burnSet","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnRedeem","name":"burnRedeem","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"instanceId","type":"uint256"},{"components":[{"internalType":"address payable","name":"paymentReceiver","type":"address"},{"internalType":"enum IBurnRedeemCore.StorageProtocol","name":"storageProtocol","type":"uint8"},{"internalType":"uint16","name":"redeemAmount","type":"uint16"},{"internalType":"uint32","name":"totalSupply","type":"uint32"},{"internalType":"uint48","name":"startDate","type":"uint48"},{"internalType":"uint48","name":"endDate","type":"uint48"},{"internalType":"uint160","name":"cost","type":"uint160"},{"internalType":"string","name":"location","type":"string"},{"components":[{"internalType":"uint256","name":"requiredCount","type":"uint256"},{"components":[{"internalType":"enum IBurnRedeemCore.ValidationType","name":"validationType","type":"uint8"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"enum IBurnRedeemCore.TokenSpec","name":"tokenSpec","type":"uint8"},{"internalType":"enum IBurnRedeemCore.BurnSpec","name":"burnSpec","type":"uint8"},{"internalType":"uint72","name":"amount","type":"uint72"},{"internalType":"uint256","name":"minTokenId","type":"uint256"},{"internalType":"uint256","name":"maxTokenId","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct IBurnRedeemCore.BurnItem[]","name":"items","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnGroup[]","name":"burnSet","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnRedeemParameters","name":"burnRedeemParameters","type":"tuple"},{"internalType":"bool","name":"identicalTokenURI","type":"bool"}],"name":"initializeBurnRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manifoldMembershipContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"destination","type":"address"}],"name":"recoverERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"revokeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setMembershipAddress","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":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"instanceId","type":"uint256"},{"components":[{"internalType":"address payable","name":"paymentReceiver","type":"address"},{"internalType":"enum IBurnRedeemCore.StorageProtocol","name":"storageProtocol","type":"uint8"},{"internalType":"uint16","name":"redeemAmount","type":"uint16"},{"internalType":"uint32","name":"totalSupply","type":"uint32"},{"internalType":"uint48","name":"startDate","type":"uint48"},{"internalType":"uint48","name":"endDate","type":"uint48"},{"internalType":"uint160","name":"cost","type":"uint160"},{"internalType":"string","name":"location","type":"string"},{"components":[{"internalType":"uint256","name":"requiredCount","type":"uint256"},{"components":[{"internalType":"enum IBurnRedeemCore.ValidationType","name":"validationType","type":"uint8"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"enum IBurnRedeemCore.TokenSpec","name":"tokenSpec","type":"uint8"},{"internalType":"enum IBurnRedeemCore.BurnSpec","name":"burnSpec","type":"uint8"},{"internalType":"uint72","name":"amount","type":"uint72"},{"internalType":"uint256","name":"minTokenId","type":"uint256"},{"internalType":"uint256","name":"maxTokenId","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct IBurnRedeemCore.BurnItem[]","name":"items","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnGroup[]","name":"burnSet","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnRedeemParameters","name":"burnRedeemParameters","type":"tuple"},{"internalType":"bool","name":"identicalTokenURI","type":"bool"}],"name":"updateBurnRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"instanceId","type":"uint256"},{"internalType":"enum IBurnRedeemCore.StorageProtocol","name":"storageProtocol","type":"uint8"},{"internalType":"string","name":"location","type":"string"},{"internalType":"bool","name":"identicalTokenURI","type":"bool"}],"name":"updateTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]