Contract Name:
NFT721AirdropV1
Contract Source Code:
<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity =0.8.3;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@shoyunft/contracts/contracts/interfaces/INFT721.sol";
import "@shoyunft/contracts/contracts/interfaces/INFTLockable.sol";
import "./MerkleProof.sol";
contract NFT721AirdropV1 is Ownable, MerkleProof {
struct TokenIdRange {
uint256 from;
uint256 length;
}
address public immutable nftContract;
mapping(bytes32 => TokenIdRange) public tokenIdRanges;
mapping(bytes32 => uint256) public tokensClaimed;
mapping(bytes32 => mapping(address => bool)) public claimed;
event AddMerkleRoot(bytes32 indexed merkleRoot, uint256 indexed fromTokenId, uint256 length);
event Claim(bytes32 indexed merkleRoot, uint256 indexed tokenId, address indexed account);
constructor(
address _nftContract,
bytes32 merkleRoot,
uint256 fromTokenId,
uint256 length
) {
nftContract = _nftContract;
if (merkleRoot != bytes32("")) {
tokenIdRanges[merkleRoot].from = fromTokenId;
tokenIdRanges[merkleRoot].length = length;
emit AddMerkleRoot(merkleRoot, fromTokenId, length);
}
}
function setRoyaltyFeeRecipient(address _royaltyFeeRecipient) external onlyOwner {
INFT721(nftContract).setRoyaltyFeeRecipient(_royaltyFeeRecipient);
}
function setRoyaltyFee(uint8 _royaltyFee) external onlyOwner {
INFT721(nftContract).setRoyaltyFee(_royaltyFee);
}
function setTokenURI(uint256 tokenId, string memory uri) external onlyOwner {
INFT721(nftContract).setTokenURI(tokenId, uri);
}
function setBaseURI(string memory baseURI) external onlyOwner {
INFT721(nftContract).setBaseURI(baseURI);
}
function parkTokenIds(uint256 toTokenId) external onlyOwner {
INFT721(nftContract).parkTokenIds(toTokenId);
}
function mintBatch(
address to,
uint256[] calldata tokenIds,
bytes calldata data
) external onlyOwner {
INFT721(nftContract).mintBatch(to, tokenIds, data);
}
function burnBatch(uint256[] calldata tokenIds) external onlyOwner {
INFT721(nftContract).burnBatch(tokenIds);
}
function setLocked(bool locked) external onlyOwner {
INFTLockable(nftContract).setLocked(locked);
}
function addMerkleRoot(
bytes32 merkleRoot,
uint256 fromTokenId,
uint256 length
) external onlyOwner {
require(tokenIdRanges[merkleRoot].length == 0, "SHOYU: DUPLICATE_ROOT");
tokenIdRanges[merkleRoot].from = fromTokenId;
tokenIdRanges[merkleRoot].length = length;
emit AddMerkleRoot(merkleRoot, fromTokenId, length);
}
function claim(bytes32 merkleRoot, bytes32[] calldata merkleProof) external {
TokenIdRange storage range = tokenIdRanges[merkleRoot];
uint256 length = range.length;
require(length > 0, "SHOYU: INVALID_ROOT");
require(!claimed[merkleRoot][msg.sender], "SHOYU: FORBIDDEN");
require(verify(merkleRoot, keccak256(abi.encodePacked(msg.sender)), merkleProof), "SHOYU: INVALID_PROOF");
uint256 tokens = tokensClaimed[merkleRoot];
require(tokens < length, "SHOYU: ALL_CLAIMED");
uint256 tokenId = range.from + tokens;
claimed[merkleRoot][msg.sender] = true;
tokensClaimed[merkleRoot] += 1;
INFT721(nftContract).mint(msg.sender, tokenId, "");
emit Claim(merkleRoot, tokenId, msg.sender);
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity =0.8.3;
contract MerkleProof {
function verify(
bytes32 root,
bytes32 leaf,
bytes32[] memory proof
) public pure returns (bool) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
bytes32 proofElement = proof[i];
if (computedHash < proofElement) {
// Hash(current computed hash + current element of the proof)
computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
} else {
// Hash(current element of the proof + current computed hash)
computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
}
}
// Check if the computed hash (root) is equal to the provided root
return computedHash == root;
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity =0.8.3;
interface INFTLockable {
event SetLocked(bool locked);
function locked() external view returns (bool);
function setLocked(bool _locked) external;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
import "./IBaseNFT721.sol";
import "./IBaseExchange.sol";
interface INFT721 is IBaseNFT721, IBaseExchange {
event SetRoyaltyFeeRecipient(address recipient);
event SetRoyaltyFee(uint8 fee);
function initialize(
address _owner,
string calldata _name,
string calldata _symbol,
uint256[] calldata tokenIds,
address royaltyFeeRecipient,
uint8 royaltyFee
) external;
function initialize(
address _owner,
string calldata _name,
string calldata _symbol,
uint256 toTokenId,
address royaltyFeeRecipient,
uint8 royaltyFee
) external;
function DOMAIN_SEPARATOR() external view override(IBaseNFT721, IBaseExchange) returns (bytes32);
function factory() external view override(IBaseNFT721, IBaseExchange) returns (address);
function setRoyaltyFeeRecipient(address _royaltyFeeRecipient) external;
function setRoyaltyFee(uint8 _royaltyFee) external;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_setOwner(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
import "../libraries/Orders.sol";
interface IBaseExchange {
event Cancel(bytes32 indexed hash);
event Claim(
bytes32 indexed hash,
address bidder,
uint256 amount,
uint256 price,
address recipient,
address referrer
);
event Bid(bytes32 indexed hash, address bidder, uint256 amount, uint256 price, address recipient, address referrer);
event UpdateApprovedBidHash(
address indexed proxy,
bytes32 indexed askHash,
address indexed bidder,
bytes32 bidHash
);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function factory() external view returns (address);
function canTrade(address token) external view returns (bool);
function bestBid(bytes32 hash)
external
view
returns (
address bidder,
uint256 amount,
uint256 price,
address recipient,
address referrer,
uint256 blockNumber
);
function isCancelledOrClaimed(bytes32 hash) external view returns (bool);
function amountFilled(bytes32 hash) external view returns (uint256);
function approvedBidHash(
address proxy,
bytes32 askHash,
address bidder
) external view returns (bytes32 bidHash);
function cancel(Orders.Ask memory order) external;
function updateApprovedBidHash(
bytes32 askHash,
address bidder,
bytes32 bidHash
) external;
function bid(Orders.Ask memory askOrder, Orders.Bid memory bidOrder) external returns (bool executed);
function bid(
Orders.Ask memory askOrder,
uint256 bidAmount,
uint256 bidPrice,
address bidRecipient,
address bidReferrer
) external returns (bool executed);
function claim(Orders.Ask memory order) external;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import "./IOwnable.sol";
interface IBaseNFT721 is IERC721, IERC721Metadata, IOwnable {
event SetTokenURI(uint256 indexed tokenId, string uri);
event SetBaseURI(string uri);
event ParkTokenIds(uint256 toTokenId);
event Burn(uint256 indexed tokenId, uint256 indexed label, bytes32 data);
function PERMIT_TYPEHASH() external view returns (bytes32);
function PERMIT_ALL_TYPEHASH() external view returns (bytes32);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function factory() external view returns (address);
function nonces(uint256 tokenId) external view returns (uint256);
function noncesForAll(address account) external view returns (uint256);
function parked(uint256 tokenId) external view returns (bool);
function initialize(
string calldata name,
string calldata symbol,
address _owner
) external;
function setTokenURI(uint256 id, string memory uri) external;
function setBaseURI(string memory uri) external;
function parkTokenIds(uint256 toTokenId) external;
function mint(
address to,
uint256 tokenId,
bytes calldata data
) external;
function mintBatch(
address to,
uint256[] calldata tokenIds,
bytes calldata data
) external;
function burn(
uint256 tokenId,
uint256 label,
bytes32 data
) external;
function burnBatch(uint256[] calldata tokenIds) external;
function permit(
address spender,
uint256 tokenId,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function permitAll(
address owner,
address spender,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
interface IOwnable {
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function owner() external view returns (address);
function renounceOwnership() external;
function transferOwnership(address newOwner) external;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity =0.8.3;
library Orders {
// keccak256("Ask(address signer,address proxy,address token,uint256 tokenId,uint256 amount,address strategy,address currency,address recipient,uint256 deadline,bytes params)")
bytes32 internal constant ASK_TYPEHASH = 0x5fbc9a24e1532fa5245d1ec2dc5592849ae97ac5475f361b1a1f7a6e2ac9b2fd;
// keccak256("Bid(bytes32 askHash,address signer,uint256 amount,uint256 price,address recipient,address referrer)")
bytes32 internal constant BID_TYPEHASH = 0xb98e1dc48988064e6dfb813618609d7da80a8841e5f277039788ac4b50d497b2;
struct Ask {
address signer;
address proxy;
address token;
uint256 tokenId;
uint256 amount;
address strategy;
address currency;
address recipient;
uint256 deadline;
bytes params;
uint8 v;
bytes32 r;
bytes32 s;
}
struct Bid {
bytes32 askHash;
address signer;
uint256 amount;
uint256 price;
address recipient;
address referrer;
uint8 v;
bytes32 r;
bytes32 s;
}
function hash(Ask memory ask) internal pure returns (bytes32) {
return
keccak256(
abi.encode(
ASK_TYPEHASH,
ask.signer,
ask.proxy,
ask.token,
ask.tokenId,
ask.amount,
ask.strategy,
ask.currency,
ask.recipient,
ask.deadline,
keccak256(ask.params)
)
);
}
function hash(Bid memory bid) internal pure returns (bytes32) {
return
keccak256(
abi.encode(BID_TYPEHASH, bid.askHash, bid.signer, bid.amount, bid.price, bid.recipient, bid.referrer)
);
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
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);
}