Transaction Hash:
Block:
12362434 at May-03-2021 04:57:22 PM +UTC
Transaction Fee:
0.018083754 ETH
$39.64
Gas Used:
165,906 Gas / 109 Gwei
Emitted Events:
254 |
Meebits.Mint( index=2357, minter=[Sender] 0x9df2d651c837c7c5fac430fcf69b811c7906333d, createdVia=0 )
|
255 |
Meebits.Transfer( from=0x00000000...000000000, to=[Sender] 0x9df2d651c837c7c5fac430fcf69b811c7906333d, tokenId=2357 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x04668Ec2...D451c8F7F
Miner
| (zhizhu.top) | 1,994.235018210245762486 Eth | 1,994.253101964245762486 Eth | 0.018083754 | |
0x7Bd29408...3bB716Bc7 | |||||
0x9Df2d651...C7906333D |
3.980407636637445862 Eth
Nonce: 1
|
1.46348129004485327 Eth
Nonce: 2
| 2.516926346592592592 | ||
0xC352B534...53488e56a | (Autoglyphs: Deployer) | 476.04568140875929857 Eth | 478.544524001351891162 Eth | 2.498842592592592592 |
Execution Trace
ETH 2.499384093915343915
Meebits.CALL( )

- ETH 0.000541501322751323
0x9df2d651c837c7c5fac430fcf69b811c7906333d.CALL( )
- ETH 2.498842592592592592
Autoglyphs: Deployer.CALL( )
pragma solidity 0.7.6; /** * __ __ _ _ _ * | \/ | | | (_) | * | \ / | ___ ___| |__ _| |_ ___ * | |\/| |/ _ \/ _ \ '_ \| | __/ __| * | | | | __/ __/ |_) | | |_\__ \ * |_| |_|\___|\___|_.__/|_|\__|___/ * * An NFT project from Larva Labs. * */ interface IERC165 { function supportsInterface(bytes4 interfaceId) external view returns (bool); } 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) external; function transferFrom(address from, address to, uint256 tokenId) external; function approve(address to, uint256 tokenId) external; function getApproved(uint256 tokenId) external view returns (address operator); function setApprovalForAll(address operator, bool _approved) external; function isApprovedForAll(address owner, address operator) external view returns (bool); function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; } /** * Minimal interface to Cryptopunks for verifying ownership during Community Grant. */ interface Cryptopunks { function punkIndexToAddress(uint index) external view returns(address); } interface ERC721TokenReceiver { function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) external returns(bytes4); } library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { if (a == 0) { return 0; } c = a * b; require(c / a == b); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 // uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return a / b; } /** * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a); return a - b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256 c) { c = a + b; require(c >= a); return c; } } contract Meebits is IERC721 { using SafeMath for uint256; /** * Event emitted when minting a new NFT. "createdVia" is the index of the Cryptopunk/Autoglyph that was used to mint, or 0 if not applicable. */ event Mint(uint indexed index, address indexed minter, uint createdVia); /** * Event emitted when a trade is executed. */ event Trade(bytes32 indexed hash, address indexed maker, address taker, uint makerWei, uint[] makerIds, uint takerWei, uint[] takerIds); /** * Event emitted when ETH is deposited into the contract. */ event Deposit(address indexed account, uint amount); /** * Event emitted when ETH is withdrawn from the contract. */ event Withdraw(address indexed account, uint amount); /** * Event emitted when a trade offer is cancelled. */ event OfferCancelled(bytes32 hash); /** * Event emitted when the public sale begins. */ event SaleBegins(); /** * Event emitted when the community grant period ends. */ event CommunityGrantEnds(); bytes4 internal constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02; // IPFS Hash to the NFT content string public contentHash = "QmfXYgfX1qNfzQ6NRyFnupniZusasFPMeiWn5aaDnx7YXo"; uint public constant TOKEN_LIMIT = 20000; uint public constant SALE_LIMIT = 9000; mapping(bytes4 => bool) internal supportedInterfaces; mapping (uint256 => address) internal idToOwner; mapping (uint256 => uint256) public creatorNftMints; mapping (uint256 => address) internal idToApproval; mapping (address => mapping (address => bool)) internal ownerToOperators; mapping(address => uint256[]) internal ownerToIds; mapping(uint256 => uint256) internal idToOwnerIndex; string internal nftName = "Meebits"; string internal nftSymbol = unicode"⚇"; uint internal numTokens = 0; uint internal numSales = 0; // Cryptopunks contract address internal punks; // Autoglyphs contract address internal glyphs; address payable internal deployer; address payable internal beneficiary; bool public communityGrant = true; bool public publicSale = false; uint private price; uint public saleStartTime; uint public saleDuration; //// Random index assignment uint internal nonce = 0; uint[TOKEN_LIMIT] internal indices; //// Market bool public marketPaused; bool public contractSealed; mapping (address => uint256) public ethBalance; mapping (bytes32 => bool) public cancelledOffers; modifier onlyDeployer() { require(msg.sender == deployer, "Only deployer."); _; } bool private reentrancyLock = false; /* Prevent a contract function from being reentrant-called. */ modifier reentrancyGuard { if (reentrancyLock) { revert(); } reentrancyLock = true; _; reentrancyLock = false; } modifier canOperate(uint256 _tokenId) { address tokenOwner = idToOwner[_tokenId]; require(tokenOwner == msg.sender || ownerToOperators[tokenOwner][msg.sender], "Cannot operate."); _; } modifier canTransfer(uint256 _tokenId) { address tokenOwner = idToOwner[_tokenId]; require( tokenOwner == msg.sender || idToApproval[_tokenId] == msg.sender || ownerToOperators[tokenOwner][msg.sender], "Cannot transfer." ); _; } modifier validNFToken(uint256 _tokenId) { require(idToOwner[_tokenId] != address(0), "Invalid token."); _; } constructor(address _punks, address _glyphs, address payable _beneficiary) { supportedInterfaces[0x01ffc9a7] = true; // ERC165 supportedInterfaces[0x80ac58cd] = true; // ERC721 supportedInterfaces[0x780e9d63] = true; // ERC721 Enumerable supportedInterfaces[0x5b5e139f] = true; // ERC721 Metadata deployer = msg.sender; punks = _punks; glyphs = _glyphs; beneficiary = _beneficiary; } function startSale(uint _price, uint _saleDuration) external onlyDeployer { require(!publicSale); price = _price; saleDuration = _saleDuration; saleStartTime = block.timestamp; publicSale = true; emit SaleBegins(); } function endCommunityGrant() external onlyDeployer { require(communityGrant); communityGrant = false; emit CommunityGrantEnds(); } function pauseMarket(bool _paused) external onlyDeployer { require(!contractSealed, "Contract sealed."); marketPaused = _paused; } function sealContract() external onlyDeployer { contractSealed = true; } ////////////////////////// //// ERC 721 and 165 //// ////////////////////////// function isContract(address _addr) internal view returns (bool addressCheck) { uint256 size; assembly { size := extcodesize(_addr) } // solhint-disable-line addressCheck = size > 0; } function supportsInterface(bytes4 _interfaceID) external view override returns (bool) { return supportedInterfaces[_interfaceID]; } function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata _data) external override { _safeTransferFrom(_from, _to, _tokenId, _data); } function safeTransferFrom(address _from, address _to, uint256 _tokenId) external override { _safeTransferFrom(_from, _to, _tokenId, ""); } function transferFrom(address _from, address _to, uint256 _tokenId) external override canTransfer(_tokenId) validNFToken(_tokenId) { address tokenOwner = idToOwner[_tokenId]; require(tokenOwner == _from, "Wrong from address."); require(_to != address(0), "Cannot send to 0x0."); _transfer(_to, _tokenId); } function approve(address _approved, uint256 _tokenId) external override canOperate(_tokenId) validNFToken(_tokenId) { address tokenOwner = idToOwner[_tokenId]; require(_approved != tokenOwner); idToApproval[_tokenId] = _approved; emit Approval(tokenOwner, _approved, _tokenId); } function setApprovalForAll(address _operator, bool _approved) external override { ownerToOperators[msg.sender][_operator] = _approved; emit ApprovalForAll(msg.sender, _operator, _approved); } function balanceOf(address _owner) external view override returns (uint256) { require(_owner != address(0)); return _getOwnerNFTCount(_owner); } function ownerOf(uint256 _tokenId) external view override returns (address _owner) { require(idToOwner[_tokenId] != address(0)); _owner = idToOwner[_tokenId]; } function getApproved(uint256 _tokenId) external view override validNFToken(_tokenId) returns (address) { return idToApproval[_tokenId]; } function isApprovedForAll(address _owner, address _operator) external override view returns (bool) { return ownerToOperators[_owner][_operator]; } function _transfer(address _to, uint256 _tokenId) internal { address from = idToOwner[_tokenId]; _clearApproval(_tokenId); _removeNFToken(from, _tokenId); _addNFToken(_to, _tokenId); emit Transfer(from, _to, _tokenId); } function randomIndex() internal returns (uint) { uint totalSize = TOKEN_LIMIT - numTokens; uint index = uint(keccak256(abi.encodePacked(nonce, msg.sender, block.difficulty, block.timestamp))) % totalSize; uint value = 0; if (indices[index] != 0) { value = indices[index]; } else { value = index; } // Move last value to selected position if (indices[totalSize - 1] == 0) { // Array position not initialized, so use position indices[index] = totalSize - 1; } else { // Array position holds a value so use that indices[index] = indices[totalSize - 1]; } nonce++; // Don't allow a zero index, start counting at 1 return value.add(1); } // Calculate the mint price function getPrice() public view returns (uint) { require(publicSale, "Sale not started."); uint elapsed = block.timestamp.sub(saleStartTime); if (elapsed >= saleDuration) { return 0; } else { return saleDuration.sub(elapsed).mul(price).div(saleDuration); } } // The deployer can mint in bulk without paying function devMint(uint quantity, address recipient) external onlyDeployer { for (uint i = 0; i < quantity; i++) { _mint(recipient, 0); } } function mintsRemaining() external view returns (uint) { return SALE_LIMIT.sub(numSales); } /** * Community grant minting. */ function mintWithPunkOrGlyph(uint _createVia) external reentrancyGuard returns (uint) { require(communityGrant); require(!marketPaused); require(_createVia > 0 && _createVia <= 10512, "Invalid punk/glyph index."); require(creatorNftMints[_createVia] == 0, "Already minted with this punk/glyph"); if (_createVia > 10000) { // It's a glyph // Compute the glyph ID uint glyphId = _createVia.sub(10000); // Make sure the sender owns the glyph require(IERC721(glyphs).ownerOf(glyphId) == msg.sender, "Not the owner of this glyph."); } else { // It's a punk // Compute the punk ID uint punkId = _createVia.sub(1); // Make sure the sender owns the punk require(Cryptopunks(punks).punkIndexToAddress(punkId) == msg.sender, "Not the owner of this punk."); } creatorNftMints[_createVia]++; return _mint(msg.sender, _createVia); } /** * Public sale minting. */ function mint() external payable reentrancyGuard returns (uint) { require(publicSale, "Sale not started."); require(!marketPaused); require(numSales < SALE_LIMIT, "Sale limit reached."); uint salePrice = getPrice(); require(msg.value >= salePrice, "Insufficient funds to purchase."); if (msg.value > salePrice) { msg.sender.transfer(msg.value.sub(salePrice)); } beneficiary.transfer(salePrice); numSales++; return _mint(msg.sender, 0); } function _mint(address _to, uint createdVia) internal returns (uint) { require(_to != address(0), "Cannot mint to 0x0."); require(numTokens < TOKEN_LIMIT, "Token limit reached."); uint id = randomIndex(); numTokens = numTokens + 1; _addNFToken(_to, id); emit Mint(id, _to, createdVia); emit Transfer(address(0), _to, id); return id; } function _addNFToken(address _to, uint256 _tokenId) internal { require(idToOwner[_tokenId] == address(0), "Cannot add, already owned."); idToOwner[_tokenId] = _to; ownerToIds[_to].push(_tokenId); idToOwnerIndex[_tokenId] = ownerToIds[_to].length.sub(1); } function _removeNFToken(address _from, uint256 _tokenId) internal { require(idToOwner[_tokenId] == _from, "Incorrect owner."); delete idToOwner[_tokenId]; uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId]; uint256 lastTokenIndex = ownerToIds[_from].length.sub(1); if (lastTokenIndex != tokenToRemoveIndex) { uint256 lastToken = ownerToIds[_from][lastTokenIndex]; ownerToIds[_from][tokenToRemoveIndex] = lastToken; idToOwnerIndex[lastToken] = tokenToRemoveIndex; } ownerToIds[_from].pop(); } function _getOwnerNFTCount(address _owner) internal view returns (uint256) { return ownerToIds[_owner].length; } function _safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) private canTransfer(_tokenId) validNFToken(_tokenId) { address tokenOwner = idToOwner[_tokenId]; require(tokenOwner == _from, "Incorrect owner."); require(_to != address(0)); _transfer(_to, _tokenId); if (isContract(_to)) { bytes4 retval = ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data); require(retval == MAGIC_ON_ERC721_RECEIVED); } } function _clearApproval(uint256 _tokenId) private { if (idToApproval[_tokenId] != address(0)) { delete idToApproval[_tokenId]; } } //// Enumerable function totalSupply() public view returns (uint256) { return numTokens; } function tokenByIndex(uint256 index) public pure returns (uint256) { require(index >= 0 && index < TOKEN_LIMIT); return index + 1; } function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256) { require(_index < ownerToIds[_owner].length); return ownerToIds[_owner][_index]; } //// Metadata /** * @dev Converts a `uint256` to its ASCII `string` representation. */ 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); uint256 index = digits - 1; temp = value; while (temp != 0) { buffer[index--] = bytes1(uint8(48 + temp % 10)); temp /= 10; } return string(buffer); } /** * @dev Returns a descriptive name for a collection of NFTokens. * @return _name Representing name. */ function name() external view returns (string memory _name) { _name = nftName; } /** * @dev Returns an abbreviated name for NFTokens. * @return _symbol Representing symbol. */ function symbol() external view returns (string memory _symbol) { _symbol = nftSymbol; } /** * @dev A distinct URI (RFC 3986) for a given NFT. * @param _tokenId Id for which we want uri. * @return _tokenId URI of _tokenId. */ function tokenURI(uint256 _tokenId) external view validNFToken(_tokenId) returns (string memory) { return string(abi.encodePacked("https://meebits.larvalabs.com/meebit/", toString(_tokenId))); } //// MARKET struct Offer { address maker; address taker; uint256 makerWei; uint256[] makerIds; uint256 takerWei; uint256[] takerIds; uint256 expiry; uint256 salt; } function hashOffer(Offer memory offer) private pure returns (bytes32){ return keccak256(abi.encode( offer.maker, offer.taker, offer.makerWei, keccak256(abi.encodePacked(offer.makerIds)), offer.takerWei, keccak256(abi.encodePacked(offer.takerIds)), offer.expiry, offer.salt )); } function hashToSign(address maker, address taker, uint256 makerWei, uint256[] memory makerIds, uint256 takerWei, uint256[] memory takerIds, uint256 expiry, uint256 salt) public pure returns (bytes32) { Offer memory offer = Offer(maker, taker, makerWei, makerIds, takerWei, takerIds, expiry, salt); return hashOffer(offer); } function hashToVerify(Offer memory offer) private pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hashOffer(offer))); } function verify(address signer, bytes32 hash, bytes memory signature) internal pure returns (bool) { require(signer != address(0)); require(signature.length == 65); bytes32 r; bytes32 s; uint8 v; assembly { r := mload(add(signature, 32)) s := mload(add(signature, 64)) v := byte(0, mload(add(signature, 96))) } if (v < 27) { v += 27; } require(v == 27 || v == 28); return signer == ecrecover(hash, v, r, s); } function tradeValid(address maker, address taker, uint256 makerWei, uint256[] memory makerIds, uint256 takerWei, uint256[] memory takerIds, uint256 expiry, uint256 salt, bytes memory signature) view public returns (bool) { Offer memory offer = Offer(maker, taker, makerWei, makerIds, takerWei, takerIds, expiry, salt); // Check for cancellation bytes32 hash = hashOffer(offer); require(cancelledOffers[hash] == false, "Trade offer was cancelled."); // Verify signature bytes32 verifyHash = hashToVerify(offer); require(verify(offer.maker, verifyHash, signature), "Signature not valid."); // Check for expiry require(block.timestamp < offer.expiry, "Trade offer expired."); // Only one side should ever have to pay, not both require(makerWei == 0 || takerWei == 0, "Only one side of trade must pay."); // At least one side should offer tokens require(makerIds.length > 0 || takerIds.length > 0, "One side must offer tokens."); // Make sure the maker has funded the trade require(ethBalance[offer.maker] >= offer.makerWei, "Maker does not have sufficient balance."); // Ensure the maker owns the maker tokens for (uint i = 0; i < offer.makerIds.length; i++) { require(idToOwner[offer.makerIds[i]] == offer.maker, "At least one maker token doesn't belong to maker."); } // If the taker can be anybody, then there can be no taker tokens if (offer.taker == address(0)) { // If taker not specified, then can't specify IDs require(offer.takerIds.length == 0, "If trade is offered to anybody, cannot specify tokens from taker."); } else { // Ensure the taker owns the taker tokens for (uint i = 0; i < offer.takerIds.length; i++) { require(idToOwner[offer.takerIds[i]] == offer.taker, "At least one taker token doesn't belong to taker."); } } return true; } function cancelOffer(address maker, address taker, uint256 makerWei, uint256[] memory makerIds, uint256 takerWei, uint256[] memory takerIds, uint256 expiry, uint256 salt) external { require(maker == msg.sender, "Only the maker can cancel this offer."); Offer memory offer = Offer(maker, taker, makerWei, makerIds, takerWei, takerIds, expiry, salt); bytes32 hash = hashOffer(offer); cancelledOffers[hash] = true; emit OfferCancelled(hash); } function acceptTrade(address maker, address taker, uint256 makerWei, uint256[] memory makerIds, uint256 takerWei, uint256[] memory takerIds, uint256 expiry, uint256 salt, bytes memory signature) external payable reentrancyGuard { require(!marketPaused, "Market is paused."); require(msg.sender != maker, "Can't accept ones own trade."); Offer memory offer = Offer(maker, taker, makerWei, makerIds, takerWei, takerIds, expiry, salt); if (msg.value > 0) { ethBalance[msg.sender] = ethBalance[msg.sender].add(msg.value); emit Deposit(msg.sender, msg.value); } require(offer.taker == address(0) || offer.taker == msg.sender, "Not the recipient of this offer."); require(tradeValid(maker, taker, makerWei, makerIds, takerWei, takerIds, expiry, salt, signature), "Trade not valid."); require(ethBalance[msg.sender] >= offer.takerWei, "Insufficient funds to execute trade."); // Transfer ETH ethBalance[offer.maker] = ethBalance[offer.maker].sub(offer.makerWei); ethBalance[msg.sender] = ethBalance[msg.sender].add(offer.makerWei); ethBalance[msg.sender] = ethBalance[msg.sender].sub(offer.takerWei); ethBalance[offer.maker] = ethBalance[offer.maker].add(offer.takerWei); // Transfer maker ids to taker (msg.sender) for (uint i = 0; i < makerIds.length; i++) { _transfer(msg.sender, makerIds[i]); } // Transfer taker ids to maker for (uint i = 0; i < takerIds.length; i++) { _transfer(maker, takerIds[i]); } // Prevent a replay attack on this offer bytes32 hash = hashOffer(offer); cancelledOffers[hash] = true; emit Trade(hash, offer.maker, msg.sender, offer.makerWei, offer.makerIds, offer.takerWei, offer.takerIds); } function withdraw(uint amount) external reentrancyGuard { require(amount <= ethBalance[msg.sender]); ethBalance[msg.sender] = ethBalance[msg.sender].sub(amount); (bool success, ) = msg.sender.call{value:amount}(""); require(success); emit Withdraw(msg.sender, amount); } function deposit() external payable { ethBalance[msg.sender] = ethBalance[msg.sender].add(msg.value); emit Deposit(msg.sender, msg.value); } }