文件 1 的 8:ERC165.sol
pragma solidity ^0.8.0;
interface ERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 2 的 8:ERC173.sol
pragma solidity ^0.8.0;
interface ERC173 {
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function owner() view external returns (address);
function transferOwnership(address _newOwner) external;
}
文件 3 的 8:ERC721.sol
pragma solidity ^0.8.0;
interface ERC721 {
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);
function ownerOf(uint256 _tokenId) external view returns (address);
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 _approved, uint256 _tokenId) external;
function setApprovalForAll(address _operator, bool _approved) external;
function getApproved(uint256 _tokenId) external view returns (address);
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
文件 4 的 8:ERC721Metadata.sol
pragma solidity ^0.8.0;
interface ERC721Metadata {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 _tokenId) external view returns (string memory);
}
文件 5 的 8:ERC721Receiver.sol
pragma solidity ^0.8.0;
interface ERC721Receiver {
function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) external returns (bytes4);
}
文件 6 的 8:FeatheredFrens.sol
pragma solidity ^0.8.0;
import "./Package.sol";
contract FeatheredFrens is Package {
receive() external payable {}
fallback() external payable {}
event Withdraw(address operator, address receiver, uint256 value);
mapping(address => bool) private _whitelist;
mapping(address => uint256) _mintLimit;
uint256 private _limit;
bool private _mintPaused;
bool private _freeForAllPaused;
bool private _locked;
modifier gate() {
require(_locked == false, "FF: reentrancy denied");
_locked = true;
_;
_locked = false;
}
constructor(address _contractOwner, bytes32 _merkleRoot) Package("Feathered Frens", "FF") {
_transferOwnership(_contractOwner);
_mintPaused = true;
_freeForAllPaused = true;
_locked == false;
setMintLimit(10);
setMerkleRoot(_merkleRoot);
}
function mintPause(bool _bool) public ownership {
_mintPaused = _bool;
}
function mintPauseStatus() public view returns (bool) {
return _mintPaused;
}
function freeForAllPause(bool _bool) public ownership {
_freeForAllPaused = _bool;
}
function freeForAllPauseStatus() public view returns (bool) {
return _freeForAllPaused;
}
function setMintLimit(uint256 _amount) public ownership {
_limit = _amount;
}
function mintLimit() public view returns (uint256) {
return _limit;
}
function setMerkleRoot(bytes32 _merkleRoot) public ownership {
_setMerkleRoot(_merkleRoot);
}
function totalMinted(address _account) public view returns (uint256) {
return _mintLimit[_account];
}
function freeForAll(address _to, uint256 _quantity) public gate {
require(_quantity + totalSupply() <= 5555, "FF: maximum tokens minted");
require(_quantity <= mintLimit(), "FF: 10 tokens allowed to mint");
require(_quantity + _mintLimit[_to] <= mintLimit(), "FF: 10 tokens allowed to mint");
require(_freeForAllPaused != true, "FF: minting is paused");
_mintLimit[_to] += _quantity;
for (uint256 i=0; i < _quantity; i++) {
_mint(_to);
}
}
function mint(address _to, bytes32[] calldata _merkleProof, uint256 _quantity) public gate {
require(_quantity + totalSupply() <= 5555, "FF: maximum tokens minted");
require(_quantity <= mintLimit(), "FF: 10 tokens allowed to mint");
require(_quantity + _mintLimit[_to] <= mintLimit(), "FF: 10 tokens allowed to mint");
require(_mintPaused != true, "FF: minting is paused");
_mintLimit[_to] += _quantity;
for (uint256 i=0; i < _quantity; i++) {
_whitelistMint(_to, _merkleProof, merkleRoot());
}
}
function airdropBatch(address[] memory _to) public ownership {
require(_to.length + totalSupply() <= 5555, "FF: maximum tokens minted");
for (uint256 i = 0; i < _to.length; i++) {
_mint(_to[i]);
}
}
function airdrop(address _to, uint256 _quantity) public ownership {
require(_quantity + totalSupply() <= 5555, "FF: maximum tokens minted");
for (uint256 i=0; i < _quantity; i++) {
_mint(_to);
}
}
function withdraw(address _account) public ownership {
uint256 balance = address(this).balance;
(bool success, ) = payable(_account).call{value: address(this).balance}("");
require(success, "FF: ether transfer failed");
emit Withdraw(msg.sender, _account, balance);
}
}
文件 7 的 8:Package.sol
pragma solidity ^0.8.0;
import "./ERC/721/ERC721.sol";
import "./ERC/721/extensions/ERC721Metadata.sol";
import "./ERC/721/receiver/ERC721Receiver.sol";
import "./ERC/173/ERC173.sol";
import "./ERC/165/ERC165.sol";
import "./library/utils.sol";
contract Package is ERC721, ERC721Metadata, ERC173, ERC165 {
mapping(uint256 => address) private _tokenOwner;
mapping(address => uint256) private _ownerBalance;
mapping(uint256 => address) private _tokenApproval;
mapping(address => mapping(address => bool)) private _operatorApproval;
bool private _reveal = false;
bool private _baseSet = false;
bool private _baseLock = false;
bool _jsonExtension = false;
string private _name;
string private _symbol;
string private _extendedBaseUri;
uint256 private _currentId = 0;
uint256 private _totalSupply = 0;
address private _ownership;
bytes32 private root;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view override returns (string memory) {
return _name;
}
function symbol() public view override returns (string memory) {
return _symbol;
}
function transferOwnership(address _newOwner) public override ownership {
_transferOwnership(_newOwner);
}
function _transferOwnership(address _newOwner) internal {
address previousOwner = _ownership;
_ownership = _newOwner;
emit OwnershipTransferred(previousOwner, _newOwner);
}
modifier ownership() {
require(owner() == msg.sender, "ERC173: caller is not the owner");
_;
}
function owner() public view override returns (address) {
return _ownership;
}
function _setMerkleRoot(bytes32 _root) internal {
root = _root;
}
function merkleRoot() internal view returns (bytes32) {
return root;
}
function _whitelistMint(address _to, bytes32[] calldata _merkleProof, bytes32 _merkleRoot) internal {
bytes32 leaf = keccak256(abi.encodePacked(_to));
require(utils.verify(_merkleProof, _merkleRoot, leaf), "FF: invalid merkle proof.");
require(_currentId < 5555, "ERC721: maximum tokens minted");
require(_to != address(0), "ERC721: cannot mint to zero address");
_currentId += 1;
_totalSupply += 1;
_tokenOwner[_currentId] = _to;
_ownerBalance[_to] += 1;
emit Transfer(address(0), _to, _currentId);
}
function _mint(address _to) internal {
require(_currentId < 5555, "ERC721: maximum tokens minted");
require(_to != address(0), "ERC721: cannot mint to zero address");
_currentId += 1;
_totalSupply += 1;
_tokenOwner[_currentId] = _to;
_ownerBalance[_to] += 1;
emit Transfer(address(0), _to, _currentId);
}
function reveal() public ownership {
require(_baseLock == true, "FF: reveal base not locked");
_reveal = true;
}
function tokenURI(uint256 _tokenId) public view override returns (string memory) {
require(_tokenId != 0, "FF: token ID out of range");
require(_currentId >= _tokenId, "FF: token ID out of range");
if (_reveal == true) {
if (_jsonExtension == true) {
return string(abi.encodePacked(_ipfs(), _extendedBaseUri, "/", utils.toString(_tokenId), ".json"));
} else {
return string(abi.encodePacked(_ipfs(), _extendedBaseUri, "/", utils.toString(_tokenId)));
}
} else {
return string(abi.encodePacked(_ipfs(), "bafybeidvzxfejqzlftewxphrrqvee3r6sxf7mf6etdajcoawpz4sf5hve4/prereveal.json"));
}
}
function checkURI(uint256 _tokenId) public view returns (string memory) {
require(_baseSet == true, "FF: CID has not been set");
require(_baseLock == false, "FF: URI has been set");
if (_jsonExtension == true) {
return string(abi.encodePacked(_ipfs(), _extendedBaseUri, "/", utils.toString(_tokenId), ".json"));
} else {
return string(abi.encodePacked(_ipfs(), _extendedBaseUri, "/", utils.toString(_tokenId)));
}
}
function _ipfs() internal pure returns (string memory) {
return "ipfs://";
}
function revealBaseLocked() public view returns (bool) {
return _baseLock;
}
function lockRevealBase(bool _lockStatus) public ownership {
require(_reveal == false, "FF: reveal has already occured");
require(_baseSet == true, "FF: reveal base not set");
_baseLock = _lockStatus;
}
function setRevealBase(string memory _cid, bool _isExtension) public ownership {
require(_baseLock == false, "FF: already revealed");
_extendedBaseUri = _cid;
_jsonExtension = _isExtension;
_baseSet = true;
}
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
function balanceOf(address _owner) public view override returns (uint256) {
return _ownerBalance[_owner];
}
function ownerOf(uint256 _tokenId) public view override returns (address) {
return _tokenOwner[_tokenId];
}
function safeTransferFrom(address _from, address _to, uint256 _tokenId) public override {
safeTransferFrom(_from, _to, _tokenId, "");
}
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) public override {
_transfer(_from, _to, _tokenId);
_onERC721Received(_from, _to, _tokenId, _data);
}
function transferFrom(address _from, address _to, uint256 _tokenId) public override {
_transfer(_from, _to, _tokenId);
}
function approve(address _approved, uint256 _tokenId) public override {
require(_tokenOwner[_tokenId] == msg.sender);
_tokenApproval[_tokenId] = _approved;
emit Approval(msg.sender, _approved, _tokenId);
}
function setApprovalForAll(address _operator, bool _approved) public override {
require(msg.sender != _operator, "ERC721: cannot approve the owner");
_operatorApproval[msg.sender][_operator] = _approved;
emit ApprovalForAll(msg.sender, _operator, _approved);
}
function getApproved(uint256 _tokenId) public view override returns (address) {
return _tokenApproval[_tokenId];
}
function isApprovedForAll(address _owner, address _operator) public view override returns (bool) {
return _operatorApproval[_owner][_operator];
}
function _transfer(address _from, address _to, uint256 _tokenId) internal {
require(ownerOf(_tokenId) == _from, "ERC721: from address is not owner of token");
require(_tokenOwner[_tokenId] == msg.sender || _tokenApproval[_tokenId] == msg.sender || _operatorApproval[_from][msg.sender] == true, "ERC721: unauthorized transfer");
require(_to != address(0), "ERC721: cannot transfer to the zero address");
_ownerBalance[_from] -= 1;
_tokenOwner[_tokenId] = _to;
_tokenApproval[_tokenId] = address(0);
_ownerBalance[_to] += 1;
emit Transfer(_from, _to, _tokenId);
}
function _onERC721Received(address _from, address _to, uint256 _tokenId, bytes memory _data) private {
uint256 size;
assembly {
size := extcodesize(_to)
}
if (size > 0) {
try ERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) returns (bytes4 response) {
if (response != ERC721Receiver.onERC721Received.selector) {
revert("ERC721: ERC721Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC721: transfer to non ERC721Receiver implementer");
}
}
}
function supportsInterface(bytes4 interfaceId) public pure override(ERC165) returns (bool) {
return
interfaceId == type(ERC165).interfaceId ||
interfaceId == type(ERC173).interfaceId ||
interfaceId == type(ERC721).interfaceId ||
interfaceId == type(ERC721Metadata).interfaceId ||
interfaceId == type(ERC721Receiver).interfaceId;
}
}
文件 8 的 8:utils.sol
pragma solidity ^0.8.0;
library utils {
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 verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProof(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++) {
bytes32 proofElement = proof[i];
if (computedHash <= proofElement) {
computedHash = _efficientHash(computedHash, proofElement);
} else {
computedHash = _efficientHash(proofElement, computedHash);
}
}
return computedHash;
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
{
"compilationTarget": {
"contracts/FeatheredFrens.sol": "FeatheredFrens"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_contractOwner","type":"address"},{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_operator","type":"address"},{"indexed":false,"internalType":"bool","name":"_approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Withdraw","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_quantity","type":"uint256"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_to","type":"address[]"}],"name":"airdropBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_approved","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"checkURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_quantity","type":"uint256"}],"name":"freeForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_bool","type":"bool"}],"name":"freeForAllPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"freeForAllPauseStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_lockStatus","type":"bool"}],"name":"lockRevealBase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"bytes32[]","name":"_merkleProof","type":"bytes32[]"},{"internalType":"uint256","name":"_quantity","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_bool","type":"bool"}],"name":"mintPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintPauseStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reveal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revealBaseLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setMintLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_cid","type":"string"},{"internalType":"bool","name":"_isExtension","type":"bool"}],"name":"setRevealBase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"totalMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]