Contract Name:
BurnRedeemLib
Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/////////////////////////////////////////////////////////////////////////////////////
// //
// //
// .%(#. //
// #(((#%, //
// (#(((((#%* //
// /#((((((((##* //
// (#((((((((((##%. //
// ,##(/*/(////((((#%* //
// .###(//****/////(((##%, //
// (, ,%#((((((///******/////((##%( //
// *((, ,##(///////*********////((###%* //
// /(((( ,##(//////************/(((((###% //
// /(((( ,##((////***************/((((###% //
// ((( .###((///*****************((((#### //
// . (##((//*******************((((##%* //
// (#. .###((/********************((((##%. %. //
// ,%(#. .###(/********,,,,,,,*****/(((###%# ((%, //
// /%#/(/ /###(//****,,,,,,,,,,,****/((((((##%%%%#((#%. //
// /##(//(#. ,###((/****,,,,,,,,,,,,,***/((/(((((((((#####% //
// *%##(/////((###((((/***,,,,,,,,,,,,,,,***//((((((((((####%%%/ //
// ####(((//////(//////**,,,,,,.....,,,,,,****/(((((//((####%%%% //
// .####(((/((((((/////**,,,,,.......,,,,,,,,*****/////(#####%%%% //
// .#%###((////(((//***,,,,,,..........,,,,,,,,*****//((#####%%%% //
// /%%%###/////*****,,,,,,,..............,,,,,,,****/(((####%%%% //
// /%%###(////****,,,,,,..... ......,,,,,,**(((####%%%% //
// ,#%###(///****,,,,,.... .....,,,,,***/(/(##%%( //
// (####(//****,,.... ....,,,,,***/(#### //
// (###(/***,,,... ...,,,,***(##/ //
// #. (#((/**,,,,.. ...,,,,*((#, //
// ,#(##(((//,,,,.. ...,,,*/(((#((/ //
// *#(((///*,,.... ....,*//(((( //
// *(///***,.... ...,***//, //
// ,//***,... ..,,*, //
// //
// //
/////////////////////////////////////////////////////////////////////////////////////
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "./IBurnRedeemCore.sol";
/**
* @title Burn Redeem Lib
* @author manifold.xyz
* @notice Library for Burn Redeem shared extensions.
*/
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, bytes data);
error BurnRedeemAlreadyInitialized();
error InvalidBurnItem();
error InvalidBurnToken();
error InvalidMerkleProof();
error InvalidStorageProtocol();
error InvalidPaymentReceiver();
error InvalidDates();
error InvalidInput();
/**
* Initialiazes a burn redeem with base parameters
*/
function initialize(
address creatorContractAddress,
uint8 creatorContractVersion,
uint256 instanceId,
IBurnRedeemCore.BurnRedeem storage burnRedeemInstance,
IBurnRedeemCore.BurnRedeemParameters calldata burnRedeemParameters
) public {
// Sanity checks
if (burnRedeemInstance.storageProtocol != IBurnRedeemCore.StorageProtocol.INVALID) {
revert BurnRedeemAlreadyInitialized();
}
_validateParameters(burnRedeemParameters);
// Create the burn redeem
burnRedeemInstance.contractVersion = creatorContractVersion;
_setParameters(burnRedeemInstance, burnRedeemParameters);
_setBurnGroups(burnRedeemInstance, burnRedeemParameters.burnSet);
emit BurnRedeemInitialized(creatorContractAddress, instanceId, msg.sender);
}
/**
* Updates a burn redeem with base parameters
*/
function update(
address creatorContractAddress,
uint256 instanceId,
IBurnRedeemCore.BurnRedeem storage burnRedeemInstance,
IBurnRedeemCore.BurnRedeemParameters calldata burnRedeemParameters
) public {
// Sanity checks
if (burnRedeemInstance.storageProtocol == IBurnRedeemCore.StorageProtocol.INVALID) {
revert IBurnRedeemCore.BurnRedeemDoesNotExist(instanceId);
}
_validateParameters(burnRedeemParameters);
// The current redeemedCount must be divisible by redeemAmount
if (burnRedeemInstance.redeemedCount % burnRedeemParameters.redeemAmount != 0) {
revert IBurnRedeemCore.InvalidRedeemAmount();
}
// Overwrite the existing burnRedeem
_setParameters(burnRedeemInstance, burnRedeemParameters);
_setBurnGroups(burnRedeemInstance, burnRedeemParameters.burnSet);
syncTotalSupply(burnRedeemInstance);
emit BurnRedeemUpdated(creatorContractAddress, instanceId);
}
/**
* Helper to update total supply if redeemedCount exceeds totalSupply after airdrop or instance update.
*/
function syncTotalSupply(IBurnRedeemCore.BurnRedeem storage burnRedeemInstance) public {
if (
burnRedeemInstance.totalSupply != 0 &&
burnRedeemInstance.redeemedCount > burnRedeemInstance.totalSupply
) {
burnRedeemInstance.totalSupply = burnRedeemInstance.redeemedCount;
}
}
/*
* Helper to validate burn item
*/
function validateBurnItem(IBurnRedeemCore.BurnItem memory burnItem, address contractAddress, uint256 tokenId, bytes32[] memory merkleProof) public pure {
if (burnItem.validationType == IBurnRedeemCore.ValidationType.ANY) {
return;
}
if (contractAddress != burnItem.contractAddress) {
revert InvalidBurnToken();
}
if (burnItem.validationType == IBurnRedeemCore.ValidationType.CONTRACT) {
return;
} else if (burnItem.validationType == IBurnRedeemCore.ValidationType.RANGE) {
if (tokenId < burnItem.minTokenId || tokenId > burnItem.maxTokenId) {
revert IBurnRedeemCore.InvalidToken(tokenId);
}
return;
} else if (burnItem.validationType == IBurnRedeemCore.ValidationType.MERKLE_TREE) {
bytes32 leaf = keccak256(abi.encodePacked(tokenId));
if (!MerkleProof.verify(merkleProof, burnItem.merkleRoot, leaf)) {
revert InvalidMerkleProof();
}
return;
}
revert InvalidBurnItem();
}
/**
* Helper to validate the parameters for a burn redeem
*/
function _validateParameters(IBurnRedeemCore.BurnRedeemParameters calldata burnRedeemParameters) internal pure {
if (burnRedeemParameters.storageProtocol == IBurnRedeemCore.StorageProtocol.INVALID) {
revert InvalidStorageProtocol();
}
if (burnRedeemParameters.paymentReceiver == address(0)) {
revert InvalidPaymentReceiver();
}
if (burnRedeemParameters.endDate != 0 && burnRedeemParameters.startDate >= burnRedeemParameters.endDate) {
revert InvalidDates();
}
if (burnRedeemParameters.totalSupply % burnRedeemParameters.redeemAmount != 0) {
revert IBurnRedeemCore.InvalidRedeemAmount();
}
}
/**
* Helper to set top level properties for a burn redeem
*/
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;
}
/**
* Helper to set the burn groups for a burn redeem
*/
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];
if (burnGroups[i].requiredCount == 0 || burnGroups[i].requiredCount > burnGroups[i].items.length) {
revert InvalidInput();
}
burnGroup.requiredCount = burnGroups[i].requiredCount;
for (uint256 j; j < burnGroups[i].items.length;) {
IBurnRedeemCore.BurnItem memory burnItem = burnGroups[i].items[j];
IBurnRedeemCore.TokenSpec tokenSpec = burnItem.tokenSpec;
uint256 amount = burnItem.amount;
if (
!(
(tokenSpec == IBurnRedeemCore.TokenSpec.ERC1155 && amount > 0) ||
(tokenSpec == IBurnRedeemCore.TokenSpec.ERC721 && amount == 0)
) ||
burnItem.validationType == IBurnRedeemCore.ValidationType.INVALID
) {
revert InvalidInput();
}
burnGroup.items.push(burnGroups[i].items[j]);
unchecked { ++j; }
}
unchecked { ++i; }
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)
pragma solidity ^0.8.0;
/**
* @dev These functions deal with verification of Merkle Tree proofs.
*
* The tree and the proofs can be generated using our
* https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
* You will find a quickstart guide in the readme.
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, or use a hash function other than keccak256 for hashing leaves.
* This is because the concatenation of a sorted pair of internal nodes in
* the merkle tree could be reinterpreted as a leaf value.
* OpenZeppelin's JavaScript library generates merkle trees that are safe
* against this attack out of the box.
*/
library MerkleProof {
/**
* @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
* defined by `root`. For this, a `proof` must be provided, containing
* sibling hashes on the branch from the leaf to the root of the tree. Each
* pair of leaves and each pair of pre-images are assumed to be sorted.
*/
function verify(
bytes32[] memory proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
/**
* @dev Calldata version of {verify}
*
* _Available since v4.7._
*/
function verifyCalldata(
bytes32[] calldata proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. When processing the proof, the pairs
* of leafs & pre-images are assumed to be sorted.
*
* _Available since v4.4._
*/
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;
}
/**
* @dev Calldata version of {processProof}
*
* _Available since v4.7._
*/
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;
}
/**
* @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by
* `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
/**
* @dev Calldata version of {multiProofVerify}
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
/**
* @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
* proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
* leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
* respectively.
*
* CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
* is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
* tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
*
* _Available since v4.7._
*/
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
// `proof` array.
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];
}
}
/**
* @dev Calldata version of {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
// `proof` array.
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) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @author: manifold.xyz
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* Burn Redeem Core interface
*/
interface IBurnRedeemCore is IERC165, IERC721Receiver, IERC1155Receiver {
error NotAdmin(address);
error UnsupportedContractVersion();
error InvalidToken(uint256);
error InvalidInput();
error InvalidTokenSpec();
error InvalidBurnSpec();
error InvalidData();
error TransferFailure();
error BurnRedeemDoesNotExist(uint256);
error BurnRedeemInactive(uint256);
error InvalidBurnAmount();
error InvalidRedeemAmount();
error InvalidPaymentAmount();
enum StorageProtocol { INVALID, NONE, ARWEAVE, IPFS }
/**
* @notice the validation type used for a `BurnItem`
* CONTRACT any token from a specific contract is valid
* RANGE token IDs within a range (inclusive) are valid
* MERKLE_TREE various individual token IDs included in a merkle tree are valid
* ANY any token from any contract
*/
enum ValidationType { INVALID, CONTRACT, RANGE, MERKLE_TREE, ANY }
enum TokenSpec { INVALID, ERC721, ERC1155 }
enum BurnSpec { NONE, MANIFOLD, OPENZEPPELIN }
/**
* @notice a `BurnItem` indicates which tokens are eligible to be burned
* @param validationType which type of validation used to check that the burn item is
* satisfied
* @param tokenSpec whether the token is an ERC721 or ERC1155
* @param burnSpec whether the contract for a token has a `burn` function and, if so,
* what interface
* @param amount (only for ERC1155 tokens) the amount (value) required to burn
* @param minTokenId (only for RANGE validation) the minimum valid token ID
* @param maxTokenId (only for RANGE validation) the maximum valid token ID
* @param merkleRoot (only for MERKLE_TREE validation) the root of the merkle tree of
* valid token IDs
*/
struct BurnItem {
ValidationType validationType;
address contractAddress;
TokenSpec tokenSpec;
BurnSpec burnSpec;
uint72 amount;
uint256 minTokenId;
uint256 maxTokenId;
bytes32 merkleRoot;
}
/**
* @notice a `BurnGroup` is a group of valid `BurnItem`s
* @param requiredCount the number of `BurnItem`s (0 < requiredCount <= items.length) that
* need to be included in a burn
* @param items the list of `BurnItem`s
*/
struct BurnGroup {
uint256 requiredCount;
BurnItem[] items;
}
/**
* @notice parameters for burn redeem intialization/updates
* @param paymentReceiver the address to forward proceeds from paid burn redeems
* @param storageProtocol the type of storage used for the redeem token URIs
* @param redeemAmount the number of redeem tokens to mint for each burn redeem
* @param totalSupply the maximum number of redeem tokens to mint (0 for unlimited)
* @param startDate the starting time for the burn redeem (0 for immediately)
* @param endDate the end time for the burn redeem (0 for never)
* @param cost the cost for each burn redeem
* @param location used to construct the token URI (Arweave hash, full URI, etc.)
* @param burnSet a list of `BurnGroup`s that must each be satisfied for a burn redeem
*/
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;
}
/**
* @notice a pointer to a `BurnItem` in a `BurnGroup` used in calls to `burnRedeem`
* @param groupIndex the index of the `BurnGroup` in `BurnRedeem.burnSet`
* @param itemIndex the index of the `BurnItem` in `BurnGroup.items`
* @param contractAddress the address of the contract for the token
* @param id the token ID
* @param merkleProof the merkle proof for the token ID (only for MERKLE_TREE validation)
*/
struct BurnToken {
uint48 groupIndex;
uint48 itemIndex;
address contractAddress;
uint256 id;
bytes32[] merkleProof;
}
/**
* @notice get a burn redeem corresponding to a creator contract and instanceId
* @param creatorContractAddress the address of the creator contract
* @param instanceId the instanceId of the burn redeem for the creator contract
* @return BurnRedeem the burn redeem object
*/
function getBurnRedeem(address creatorContractAddress, uint256 instanceId) external view returns(BurnRedeem memory);
/**
* @notice get a burn redeem corresponding to a creator contract and tokenId
* @param creatorContractAddress the address of the creator contract
* @param tokenId the token to retrieve the burn redeem for
* @return the burn redeem instanceId and burn redeem object
*/
function getBurnRedeemForToken(address creatorContractAddress, uint256 tokenId) external view returns(uint256, BurnRedeem memory);
/**
* @notice burn tokens and mint a redeem token
* @param creatorContractAddress the address of the creator contract
* @param instanceId the instanceId of the burn redeem for the creator contract
* @param burnRedeemCount the number of burn redeems we want to do
* @param burnTokens the tokens to burn with pointers to the corresponding BurnItem requirement
*/
function burnRedeem(address creatorContractAddress, uint256 instanceId, uint32 burnRedeemCount, BurnToken[] calldata burnTokens) external payable;
/**
* @notice burn tokens and mint redeem tokens multiple times in a single transaction
* @param creatorContractAddresses the addresses of the creator contracts
* @param instanceIds the instanceIds of the burn redeems for the corresponding creator contract
* @param burnRedeemCounts the burn redeem counts for each burn
* @param burnTokens the tokens to burn for each burn redeem with pointers to the corresponding BurnItem requirement
*/
function burnRedeem(address[] calldata creatorContractAddresses, uint256[] calldata instanceIds, uint32[] calldata burnRedeemCounts, BurnToken[][] calldata burnTokens) external payable;
/**
* @notice burn tokens and mint a redeem token
* @param creatorContractAddress the address of the creator contract
* @param instanceId the instanceId of the burn redeem for the creator contract
* @param burnRedeemCount the number of burn redeems we want to do
* @param burnTokens the tokens to burn with pointers to the corresponding BurnItem requirement
* @param data the data to emit with the BurnRedeemMint event
*/
function burnRedeemWithData(address creatorContractAddress, uint256 instanceId, uint32 burnRedeemCount, BurnToken[] calldata burnTokens, bytes calldata data) external payable;
/**
* @notice allow admin to airdrop arbitrary tokens
* @param creatorContractAddress the creator contract to mint tokens for
* @param instanceId the instanceId of the burn redeem for the creator contract
* @param recipients addresses to airdrop to
* @param amounts number of redeems to perform for each address in recipients
*/
function airdrop(address creatorContractAddress, uint256 instanceId, address[] calldata recipients, uint32[] calldata amounts) external;
/**
* @notice recover a token that was sent to the contract without safeTransferFrom
* @param tokenAddress the address of the token contract
* @param tokenId the id of the token
* @param destination the address to send the token to
*/
function recoverERC721(address tokenAddress, uint256 tokenId, address destination) external;
/**
* @notice withdraw Manifold fee proceeds from the contract
* @param recipient recepient of the funds
* @param amount amount to withdraw in Wei
*/
function withdraw(address payable recipient, uint256 amount) external;
/**
* @notice set the Manifold Membership contract address
* @param addr the address of the Manifold Membership contract
*/
function setMembershipAddress(address addr) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}