编译器
0.8.13+commit.abaa5c0e
文件 1 的 6:ERC20.sol
pragma solidity >=0.8.0;
abstract contract ERC20 {
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
string public name;
string public symbol;
uint8 public immutable decimals;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender];
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
文件 2 的 6:ERC721.sol
pragma solidity >=0.8.0;
abstract contract ERC721 {
event Transfer(address indexed from, address indexed to, uint256 indexed id);
event Approval(address indexed owner, address indexed spender, uint256 indexed id);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
string public name;
string public symbol;
function tokenURI(uint256 id) public view virtual returns (string memory);
mapping(uint256 => address) internal _ownerOf;
mapping(address => uint256) internal _balanceOf;
function ownerOf(uint256 id) public view virtual returns (address owner) {
require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
}
function balanceOf(address owner) public view virtual returns (uint256) {
require(owner != address(0), "ZERO_ADDRESS");
return _balanceOf[owner];
}
mapping(uint256 => address) public getApproved;
mapping(address => mapping(address => bool)) public isApprovedForAll;
constructor(string memory _name, string memory _symbol) {
name = _name;
symbol = _symbol;
}
function approve(address spender, uint256 id) public virtual {
address owner = _ownerOf[id];
require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");
getApproved[id] = spender;
emit Approval(owner, spender, id);
}
function setApprovalForAll(address operator, bool approved) public virtual {
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function transferFrom(
address from,
address to,
uint256 id
) public virtual {
require(from == _ownerOf[id], "WRONG_FROM");
require(to != address(0), "INVALID_RECIPIENT");
require(
msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
"NOT_AUTHORIZED"
);
unchecked {
_balanceOf[from]--;
_balanceOf[to]++;
}
_ownerOf[id] = to;
delete getApproved[id];
emit Transfer(from, to, id);
}
function safeTransferFrom(
address from,
address to,
uint256 id
) public virtual {
transferFrom(from, to, id);
if (to.code.length != 0)
require(
ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
function safeTransferFrom(
address from,
address to,
uint256 id,
bytes calldata data
) public virtual {
transferFrom(from, to, id);
if (to.code.length != 0)
require(
ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return
interfaceId == 0x01ffc9a7 ||
interfaceId == 0x80ac58cd ||
interfaceId == 0x5b5e139f;
}
function _mint(address to, uint256 id) internal virtual {
require(to != address(0), "INVALID_RECIPIENT");
require(_ownerOf[id] == address(0), "ALREADY_MINTED");
unchecked {
_balanceOf[to]++;
}
_ownerOf[id] = to;
emit Transfer(address(0), to, id);
}
function _burn(uint256 id) internal virtual {
address owner = _ownerOf[id];
require(owner != address(0), "NOT_MINTED");
unchecked {
_balanceOf[owner]--;
}
delete _ownerOf[id];
delete getApproved[id];
emit Transfer(owner, address(0), id);
}
function _safeMint(address to, uint256 id) internal virtual {
_mint(to, id);
if (to.code.length != 0)
require(
ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
function _safeMint(
address to,
uint256 id,
bytes memory data
) internal virtual {
_mint(to, id);
if (to.code.length != 0)
require(
ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
}
abstract contract ERC721TokenReceiver {
function onERC721Received(
address,
address,
uint256,
bytes calldata
) external virtual returns (bytes4) {
return ERC721TokenReceiver.onERC721Received.selector;
}
}
文件 3 的 6:LibBitmap.sol
pragma solidity >=0.8.0;
library LibBitmap {
struct Bitmap {
mapping(uint256 => uint256) map;
}
function get(Bitmap storage bitmap, uint256 index) internal view returns (bool isSet) {
uint256 value = bitmap.map[index >> 8] & (1 << (index & 0xff));
assembly {
isSet := value
}
}
function set(Bitmap storage bitmap, uint256 index) internal {
bitmap.map[index >> 8] |= (1 << (index & 0xff));
}
function unset(Bitmap storage bitmap, uint256 index) internal {
bitmap.map[index >> 8] &= ~(1 << (index & 0xff));
}
function setTo(
Bitmap storage bitmap,
uint256 index,
bool shouldSet
) internal {
uint256 value = bitmap.map[index >> 8];
assembly {
let shift := and(index, 0xff)
let x := and(shr(shift, value), 1)
x := xor(x, shouldSet)
value := xor(value, shl(shift, x))
}
bitmap.map[index >> 8] = value;
}
}
文件 4 的 6:LibString.sol
pragma solidity >=0.8.0;
library LibString {
function toString(uint256 n) internal pure returns (string memory str) {
if (n == 0) return "0";
assembly {
let k := 78
str := mload(0x40)
mstore(str, k)
mstore(0x40, add(str, 128))
for {} n {} {
let char := add(48, mod(n, 10))
mstore(add(str, k), char)
k := sub(k, 1)
n := div(n, 10)
}
str := add(str, k)
mstore(str, sub(78, k))
}
}
}
文件 5 的 6:MannysCrowd.sol
pragma solidity ^0.8.13;
import {ERC721} from "solmate/tokens/ERC721.sol";
import {ERC20} from "solmate/tokens/ERC20.sol";
import {Owned} from "solmate/auth/Owned.sol";
import {LibString} from "solmate/utils/LibString.sol";
import {LibBitmap} from "solmate/utils/LibBitmap.sol";
interface MannysGame {
function ownerOf(uint256 _tokenId) external view returns (address);
function tokensByOwner(address _owner)
external
view
returns (uint16[] memory);
}
contract MannysCrowd is ERC721, Owned {
MannysGame private constant MANNYS_GAME =
MannysGame(0x2bd58A19C7E4AbF17638c5eE6fA96EE5EB53aed9);
address private constant MANNY_DAO =
0xd0fA4e10b39f3aC9c95deA8151F90b20c497d187;
uint256 public constant PUBLIC_MINT_PRICE = 0.0404 ether;
uint256 public immutable PUBLIC_MINT_ENABLED_AFTER;
using LibBitmap for LibBitmap.Bitmap;
LibBitmap.Bitmap private mints;
string private _baseURI = "https://mannys-crowd.32swords.com/token/";
bool public MERGING_ENABLED = false;
mapping(uint256 => uint256[]) public merged;
event CrowdsMerged(uint256 tokenIdBase, uint256 tokenIdMerge);
event MetadataUpdate(uint256 tokenId);
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
error AlreadyMinted(uint256 tokenId);
error NothingToMint(address owner);
error NotOwner(uint256 tokenId);
error MintingNotOpen();
error InvalidMintFee();
error OwnerMintClosed();
error MergingNotOpen();
constructor() ERC721("Manny Crowds", "MC") Owned(msg.sender) {
PUBLIC_MINT_ENABLED_AFTER = block.timestamp + 4.04 days;
}
function mintOne(uint256 tokenId) external payable {
if (MANNYS_GAME.ownerOf(tokenId) != msg.sender) {
if (block.timestamp < PUBLIC_MINT_ENABLED_AFTER)
revert MintingNotOpen();
if (msg.value != PUBLIC_MINT_PRICE) revert InvalidMintFee();
} else if (block.timestamp > PUBLIC_MINT_ENABLED_AFTER) {
if (msg.value != PUBLIC_MINT_PRICE) revert InvalidMintFee();
}
if (mints.get(tokenId)) revert AlreadyMinted(tokenId);
mints.set(tokenId);
_mint(msg.sender, tokenId);
}
function mintSomeOwned(uint16[] calldata tokenIds) external {
if (block.timestamp > PUBLIC_MINT_ENABLED_AFTER)
revert OwnerMintClosed();
if (tokenIds.length == 0) revert NothingToMint(msg.sender);
for (uint256 i = 0; i < tokenIds.length; i++) {
if (MANNYS_GAME.ownerOf(tokenIds[i]) != msg.sender)
revert NotOwner(tokenIds[i]);
if (!mints.get(tokenIds[i])) {
mints.set(tokenIds[i]);
_mint(msg.sender, tokenIds[i]);
}
}
}
function mintAllOwned() external {
if (block.timestamp > PUBLIC_MINT_ENABLED_AFTER)
revert OwnerMintClosed();
uint16[] memory tokenIds = MANNYS_GAME.tokensByOwner(msg.sender);
if (tokenIds.length == 0) revert NothingToMint(msg.sender);
for (uint256 i = 0; i < tokenIds.length; i++) {
if (!mints.get(tokenIds[i])) {
mints.set(tokenIds[i]);
_mint(msg.sender, tokenIds[i]);
}
}
}
function merge(uint256 tokenIdToKeep, uint256 tokenIdToBurn) external {
if (!MERGING_ENABLED) revert MergingNotOpen();
if (ownerOf(tokenIdToKeep) != msg.sender)
revert NotOwner(tokenIdToKeep);
if (ownerOf(tokenIdToBurn) != msg.sender)
revert NotOwner(tokenIdToBurn);
merged[tokenIdToKeep].push(tokenIdToBurn);
if (merged[tokenIdToBurn].length > 0) {
for (uint256 i = 0; i < merged[tokenIdToBurn].length; i++) {
merged[tokenIdToKeep].push(merged[tokenIdToBurn][i]);
}
}
delete merged[tokenIdToBurn];
_burn(tokenIdToBurn);
emit CrowdsMerged(tokenIdToKeep, tokenIdToBurn);
}
function tokenURI(uint256 tokenId)
public
view
override
returns (string memory)
{
return string.concat(_baseURI, LibString.toString(tokenId));
}
function refreshMetadata(uint256 tokenId) external {
emit MetadataUpdate(tokenId);
}
function refreshMetadataBatch(uint256 fromTokenId, uint256 toTokenId)
external
{
emit BatchMetadataUpdate(fromTokenId, toTokenId);
}
function refreshMetadataAll() external {
emit BatchMetadataUpdate(0, 1616);
}
function withdraw() external {
(bool sent, ) = MANNY_DAO.call{value: address(this).balance}("");
require(sent, "Failed to send Ether");
}
function withdrawERC20(address tokenAddress, uint256 amount) external {
ERC20(tokenAddress).transfer(MANNY_DAO, amount);
}
function setMergingEnabled(bool status) external onlyOwner {
MERGING_ENABLED = status;
}
function setBaseURI(string calldata baseURI) external onlyOwner {
_baseURI = baseURI;
}
}
文件 6 的 6:Owned.sol
pragma solidity >=0.8.0;
abstract contract Owned {
event OwnerUpdated(address indexed user, address indexed newOwner);
address public owner;
modifier onlyOwner() virtual {
require(msg.sender == owner, "UNAUTHORIZED");
_;
}
constructor(address _owner) {
owner = _owner;
emit OwnerUpdated(address(0), _owner);
}
function setOwner(address newOwner) public virtual onlyOwner {
owner = newOwner;
emit OwnerUpdated(msg.sender, newOwner);
}
}
{
"compilationTarget": {
"src/MannysCrowd.sol": "MannysCrowd"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":solmate/=lib/solmate/src/"
]
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"AlreadyMinted","type":"error"},{"inputs":[],"name":"InvalidMintFee","type":"error"},{"inputs":[],"name":"MergingNotOpen","type":"error"},{"inputs":[],"name":"MintingNotOpen","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"NothingToMint","type":"error"},{"inputs":[],"name":"OwnerMintClosed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","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":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenIdBase","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenIdMerge","type":"uint256"}],"name":"CrowdsMerged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","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":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"MERGING_ENABLED","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PUBLIC_MINT_ENABLED_AFTER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PUBLIC_MINT_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","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":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenIdToKeep","type":"uint256"},{"internalType":"uint256","name":"tokenIdToBurn","type":"uint256"}],"name":"merge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"merged","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintAllOwned","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mintOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"tokenIds","type":"uint16[]"}],"name":"mintSomeOwned","outputs":[],"stateMutability":"nonpayable","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":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"refreshMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refreshMetadataAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"internalType":"uint256","name":"toTokenId","type":"uint256"}],"name":"refreshMetadataBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","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":"id","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":"string","name":"baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"status","type":"bool"}],"name":"setMergingEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"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":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"}]