Transaction Hash:
Block:
15514531 at Sep-11-2022 11:16:09 AM +UTC
Transaction Fee:
0.000208596094284808 ETH
$0.56
Gas Used:
46,031 Gas / 4.531643768 Gwei
Emitted Events:
628 |
EvolutionSerum.ApprovalForAll( owner=[Sender] 0x5c0b862b8b4e9881bac9ea01c43f6b58fc50e227, operator=0x1E004978...d54003c71, approved=True )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x5c0b862b...8fC50E227 |
0.2911166023930511 Eth
Nonce: 281
|
0.290908006298766292 Eth
Nonce: 282
| 0.000208596094284808 | ||
0x829BD824...93333A830
Miner
| (F2Pool Old) | 1,681.870104280705098502 Eth | 1,681.870173327205098502 Eth | 0.0000690465 | |
0xADaE0Dda...041D13220 |
Execution Trace
EvolutionSerum.setApprovalForAll( operator=0x1E0049783F008A0085193E00003D00cd54003c71, approved=True )
{"Context.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n"},"ERC1155.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity \u003e=0.8.0;\n\n/// @notice Minimalist and gas efficient standard ERC1155 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol)\nabstract contract ERC1155 {\n /*///////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event TransferSingle(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256 id,\n uint256 amount\n );\n\n event TransferBatch(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256[] ids,\n uint256[] amounts\n );\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n event URI(string value, uint256 indexed id);\n\n /*///////////////////////////////////////////////////////////////\n ERC1155 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(address =\u003e mapping(uint256 =\u003e uint256)) public balanceOf;\n\n mapping(address =\u003e mapping(address =\u003e bool)) public isApprovedForAll;\n\n /*///////////////////////////////////////////////////////////////\n METADATA LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function uri(uint256 id) public view virtual returns (string memory);\n\n /*///////////////////////////////////////////////////////////////\n ERC1155 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function setApprovalForAll(address operator, bool approved) public virtual {\n isApprovedForAll[msg.sender][operator] = approved;\n\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n uint256 amount,\n bytes memory data\n ) public virtual {\n require(msg.sender == from || isApprovedForAll[from][msg.sender], \"NOT_AUTHORIZED\");\n\n balanceOf[from][id] -= amount;\n balanceOf[to][id] += amount;\n\n emit TransferSingle(msg.sender, from, to, id, amount);\n\n require(\n to.code.length == 0\n ? to != address(0)\n : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) ==\n ERC1155TokenReceiver.onERC1155Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function safeBatchTransferFrom(\n address from,\n address to,\n uint256[] memory ids,\n uint256[] memory amounts,\n bytes memory data\n ) public virtual {\n uint256 idsLength = ids.length; // Saves MLOADs.\n\n require(idsLength == amounts.length, \"LENGTH_MISMATCH\");\n\n require(msg.sender == from || isApprovedForAll[from][msg.sender], \"NOT_AUTHORIZED\");\n\n for (uint256 i = 0; i \u003c idsLength; ) {\n uint256 id = ids[i];\n uint256 amount = amounts[i];\n\n balanceOf[from][id] -= amount;\n balanceOf[to][id] += amount;\n\n // An array can\u0027t have a total length\n // larger than the max uint256 value.\n unchecked {\n i++;\n }\n }\n\n emit TransferBatch(msg.sender, from, to, ids, amounts);\n\n require(\n to.code.length == 0\n ? to != address(0)\n : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) ==\n ERC1155TokenReceiver.onERC1155BatchReceived.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function balanceOfBatch(address[] memory owners, uint256[] memory ids)\n public\n view\n virtual\n returns (uint256[] memory balances)\n {\n uint256 ownersLength = owners.length; // Saves MLOADs.\n\n require(ownersLength == ids.length, \"LENGTH_MISMATCH\");\n\n balances = new uint256[](owners.length);\n\n // Unchecked because the only math done is incrementing\n // the array index counter which cannot possibly overflow.\n unchecked {\n for (uint256 i = 0; i \u003c ownersLength; i++) {\n balances[i] = balanceOf[owners[i]][ids[i]];\n }\n }\n }\n\n /*///////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId) public pure virtual returns (bool) {\n return\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155\n interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI\n }\n\n /*///////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(\n address to,\n uint256 id,\n uint256 amount,\n bytes memory data\n ) internal {\n balanceOf[to][id] += amount;\n\n emit TransferSingle(msg.sender, address(0), to, id, amount);\n\n require(\n to.code.length == 0\n ? to != address(0)\n : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) ==\n ERC1155TokenReceiver.onERC1155Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _batchMint(\n address to,\n uint256[] memory ids,\n uint256[] memory amounts,\n bytes memory data\n ) internal {\n uint256 idsLength = ids.length; // Saves MLOADs.\n\n require(idsLength == amounts.length, \"LENGTH_MISMATCH\");\n\n for (uint256 i = 0; i \u003c idsLength; ) {\n balanceOf[to][ids[i]] += amounts[i];\n\n // An array can\u0027t have a total length\n // larger than the max uint256 value.\n unchecked {\n i++;\n }\n }\n\n emit TransferBatch(msg.sender, address(0), to, ids, amounts);\n\n require(\n to.code.length == 0\n ? to != address(0)\n : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) ==\n ERC1155TokenReceiver.onERC1155BatchReceived.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _batchBurn(\n address from,\n uint256[] memory ids,\n uint256[] memory amounts\n ) internal {\n uint256 idsLength = ids.length; // Saves MLOADs.\n\n require(idsLength == amounts.length, \"LENGTH_MISMATCH\");\n\n for (uint256 i = 0; i \u003c idsLength; ) {\n balanceOf[from][ids[i]] -= amounts[i];\n\n // An array can\u0027t have a total length\n // larger than the max uint256 value.\n unchecked {\n i++;\n }\n }\n\n emit TransferBatch(msg.sender, from, address(0), ids, amounts);\n }\n\n function _burn(\n address from,\n uint256 id,\n uint256 amount\n ) internal {\n balanceOf[from][id] -= amount;\n\n emit TransferSingle(msg.sender, from, address(0), id, amount);\n }\n}\n\n/// @notice A generic interface for a contract which properly accepts ERC1155 tokens.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol)\ninterface ERC1155TokenReceiver {\n function onERC1155Received(\n address operator,\n address from,\n uint256 id,\n uint256 amount,\n bytes calldata data\n ) external returns (bytes4);\n\n function onERC1155BatchReceived(\n address operator,\n address from,\n uint256[] calldata ids,\n uint256[] calldata amounts,\n bytes calldata data\n ) external returns (bytes4);\n}\n"},"ERC721.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity \u003e=0.8.0;\n\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\n/// @dev Note that balanceOf does not revert if passed the zero address, in defiance of the ERC.\nabstract contract ERC721 {\n /*///////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /*///////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*///////////////////////////////////////////////////////////////\n ERC721 STORAGE \n //////////////////////////////////////////////////////////////*/\n\n uint256 public totalSupply;\n\n mapping(address =\u003e uint256) public balanceOf;\n\n mapping(uint256 =\u003e address) public ownerOf;\n\n mapping(uint256 =\u003e address) public getApproved;\n\n mapping(address =\u003e mapping(address =\u003e bool)) public isApprovedForAll;\n\n /*///////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n }\n\n /*///////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 id) public virtual {\n address owner = ownerOf[id];\n\n require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \"NOT_AUTHORIZED\");\n\n getApproved[id] = spender;\n\n emit Approval(owner, spender, id);\n }\n\n function setApprovalForAll(address operator, bool approved) public virtual {\n isApprovedForAll[msg.sender][operator] = approved;\n\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n require(from == ownerOf[id], \"WRONG_FROM\");\n\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(\n msg.sender == from || msg.sender == getApproved[id] || isApprovedForAll[from][msg.sender],\n \"NOT_AUTHORIZED\"\n );\n\n // Underflow of the sender\u0027s balance is impossible because we check for\n // ownership above and the recipient\u0027s balance can\u0027t realistically overflow.\n unchecked {\n balanceOf[from]--;\n\n balanceOf[to]++;\n }\n\n ownerOf[id] = to;\n\n delete getApproved[id];\n\n emit Transfer(from, to, id);\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n transferFrom(from, to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n bytes memory data\n ) public virtual {\n transferFrom(from, to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n /*///////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId) public pure virtual returns (bool) {\n return\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\n interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\n }\n\n /*///////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 id) internal virtual {\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(ownerOf[id] == address(0), \"ALREADY_MINTED\");\n\n // Counter overflow is incredibly unrealistic.\n unchecked {\n totalSupply++;\n\n balanceOf[to]++;\n }\n\n ownerOf[id] = to;\n\n emit Transfer(address(0), to, id);\n }\n\n function _burn(uint256 id) internal virtual {\n address owner = ownerOf[id];\n\n require(ownerOf[id] != address(0), \"NOT_MINTED\");\n\n // Ownership check above ensures no underflow.\n unchecked {\n totalSupply--;\n\n balanceOf[owner]--;\n }\n\n delete ownerOf[id];\n\n delete getApproved[id];\n\n emit Transfer(owner, address(0), id);\n }\n\n /*///////////////////////////////////////////////////////////////\n INTERNAL SAFE MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _safeMint(address to, uint256 id) internal virtual {\n _mint(to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _safeMint(\n address to,\n uint256 id,\n bytes memory data\n ) internal virtual {\n _mint(to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n}\n\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\ninterface ERC721TokenReceiver {\n function onERC721Received(\n address operator,\n address from,\n uint256 id,\n bytes calldata data\n ) external returns (bytes4);\n}\n"},"EvolutionSerum.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.14;\n\nimport \"./Pixelmon.sol\";\nimport \"./ERC721.sol\";\nimport \"./ERC1155.sol\";\nimport \"./Ownable.sol\";\nimport \"./Strings.sol\";\n\nerror InvalidNonce();\nerror InvalidOwner();\nerror InvalidEvolution();\nerror InvalidVoucher();\nerror NotEnoughEther();\n\ncontract EvolutionSerum is ERC1155, Ownable, ERC1155TokenReceiver {\n using Strings for uint256;\n\n /*///////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Evolution(uint indexed tokenId, uint evolutionStage);\n\n /*///////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////*/\n \n address constant public evolutionSigner = 0x00000001DEA29D000f2e99100C503bf1544Da95d;\n address constant public gnosisSafeAddress = 0x813F10aBA9624D2f4b3130a1EcD26da2BB2d09D4;\n\n string constant public name = \"Evolution Serum\";\n string constant public symbol = \"ES\";\n\n /*///////////////////////////////////////////////////////////////\n STORAGE\n //////////////////////////////////////////////////////////////*/\n\n Pixelmon creatures;\n\n mapping(uint =\u003e uint) public serumPrices;\n mapping(address =\u003e uint) public nonces;\n mapping(bytes32 =\u003e bool) public usedVouchers;\n\n string baseURI;\n\n /*///////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address creatureAddress, string memory _baseURI) {\n creatures = Pixelmon(creatureAddress);\n baseURI = _baseURI;\n }\n\n /*///////////////////////////////////////////////////////////////\n MODIFIERS\n //////////////////////////////////////////////////////////////*/\n\n modifier correctNonce(uint nonce) {\n if(nonce != nonces[msg.sender]) revert InvalidNonce();\n nonces[msg.sender]++;\n _;\n }\n\n /*///////////////////////////////////////////////////////////////\n METADATA LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function setBaseURI(string memory _baseURI) public onlyOwner {\n baseURI = _baseURI;\n }\n\n function setSerumPrice(uint serumId, uint price) public onlyOwner {\n serumPrices[serumId] = price;\n }\n\n function uri(uint256 id) public view override returns (string memory) {\n return string(abi.encodePacked(baseURI, id.toString()));\n }\n\n /*///////////////////////////////////////////////////////////////\n MINTING LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function claim(uint serumId, uint count, bytes memory signature) public payable {\n if(msg.value \u003c count * serumPrices[serumId]) revert NotEnoughEther();\n if(!validMint(msg.sender, serumId, count, signature)) revert InvalidVoucher();\n _mint(msg.sender, serumId, count, \"\");\n }\n\n function airdrop(uint serumId, address[] calldata users) public onlyOwner {\n for (uint256 i = 0; i \u003c users.length; i++) {\n _mint(users[i], serumId, 1, \"\"); \n }\n }\n\n function ownerMint(uint id, uint amount, address receiver) public onlyOwner {\n _mint(receiver, id, amount, \"\");\n }\n\n /*///////////////////////////////////////////////////////////////\n EVOLUTION LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function evolve(uint tokenId, uint serumId, uint nonce, uint evolutionStage, bytes memory signature) public correctNonce(nonce) {\n if(creatures.ownerOf(tokenId) != msg.sender) revert InvalidOwner();\n if(!validEvolution(msg.sender, serumId, tokenId, evolutionStage, nonce, signature)) revert InvalidEvolution();\n _burn(msg.sender, serumId, 1);\n creatures.mintEvolvedPixelmon(msg.sender, evolutionStage);\n emit Evolution(tokenId, evolutionStage);\n }\n\n /*///////////////////////////////////////////////////////////////\n UTILS\n //////////////////////////////////////////////////////////////*/\n\n function validMint(address user, uint serumId, uint count, bytes memory signature) public returns (bool) {\n bytes32 messageHash = keccak256(abi.encodePacked(user, serumId, count));\n if(usedVouchers[messageHash]) return false;\n\n usedVouchers[messageHash] = true;\n bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);\n return recoverSigner(ethSignedMessageHash, signature) == evolutionSigner;\n }\n\n function validEvolution(address user, uint serumId, uint creatureId, uint evolutionStage, uint nonce, bytes memory signature)\n public\n pure\n returns (bool)\n {\n bytes32 messageHash = keccak256(abi.encodePacked(user, serumId, creatureId, evolutionStage, nonce));\n bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);\n\n return recoverSigner(ethSignedMessageHash, signature) == evolutionSigner;\n }\n\n function getEthSignedMessageHash(bytes32 _messageHash)\n private\n pure\n returns (bytes32)\n {\n /*\n Signature is produced by signing a keccak256 hash with the following format:\n \"\\x19Ethereum Signed Message\\n\" + len(msg) + msg\n */\n return\n keccak256(\n abi.encodePacked(\n \"\\x19Ethereum Signed Message:\\n32\",\n _messageHash\n )\n );\n }\n\n function recoverSigner(\n bytes32 _ethSignedMessageHash,\n bytes memory _signature\n ) private pure returns (address) {\n (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);\n return ecrecover(_ethSignedMessageHash, v, r, s);\n }\n\n function splitSignature(bytes memory sig)\n private\n pure\n returns (\n bytes32 r,\n bytes32 s,\n uint8 v\n )\n {\n require(sig.length == 65, \"sig invalid\");\n\n assembly {\n /*\n First 32 bytes stores the length of the signature\n\n add(sig, 32) = pointer of sig + 32\n effectively, skips first 32 bytes of signature\n\n mload(p) loads next 32 bytes starting at the memory address p into memory\n */\n\n // first 32 bytes, after the length prefix\n r := mload(add(sig, 32))\n // second 32 bytes\n s := mload(add(sig, 64))\n // final byte (first byte of the next 32 bytes)\n v := byte(0, mload(add(sig, 96)))\n }\n\n // implicitly return (r, s, v)\n }\n\n /// @notice Withdraws collected funds to the Gnosis Safe address\n function withdraw() public onlyOwner {\n (bool success, ) = gnosisSafeAddress.call{value: address(this).balance}(\"\");\n require(success);\n }\n\n function onERC1155Received(\n address operator,\n address from,\n uint256 id,\n uint256 amount,\n bytes calldata data\n ) external returns (bytes4) {\n return ERC1155TokenReceiver.onERC1155Received.selector;\n }\n\n function onERC1155BatchReceived(\n address operator,\n address from,\n uint256[] calldata ids,\n uint256[] calldata amounts,\n bytes calldata data\n ) external returns (bytes4) {\n return ERC1155TokenReceiver.onERC1155BatchReceived.selector;\n }\n}\n"},"Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n"},"Pixelmon.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.14;\n\nimport \"./ERC721.sol\";\nimport \"./Ownable.sol\";\nimport \"./Strings.sol\";\n\n/// @notice Thrown when completing the transaction results in overallocation of Pixelmon.\nerror MintedOut();\n/// @notice Thrown when the dutch auction phase has not yet started, or has already ended.\nerror AuctionNotStarted();\n/// @notice Thrown when the user has already minted two Pixelmon in the dutch auction.\nerror MintingTooMany();\n/// @notice Thrown when the value of the transaction is not enough for the current dutch auction or mintlist price.\nerror ValueTooLow();\n/// @notice Thrown when the user is not on the mintlist.\nerror NotMintlisted();\n/// @notice Thrown when the caller is not the EvolutionSerum contract, and is trying to evolve a Pixelmon.\nerror UnauthorizedEvolution();\n/// @notice Thrown when an invalid evolution is given by the EvolutionSerum contract.\nerror UnknownEvolution();\n\n\n// ______ __ __ __ ______ __ __ __ ______ __ __ \n// /\\ == \\ /\\ \\ /\\_\\_\\_\\ /\\ ___\\ /\\ \\ /\\ \"-./ \\ /\\ __ \\ /\\ \"-.\\ \\ \n// \\ \\ _-/ \\ \\ \\ \\/_/\\_\\/_ \\ \\ __\\ \\ \\ \\____ \\ \\ \\-./\\ \\ \\ \\ \\/\\ \\ \\ \\ \\-. \\ \n// \\ \\_\\ \\ \\_\\ /\\_\\/\\_\\ \\ \\_____\\ \\ \\_____\\ \\ \\_\\ \\ \\_\\ \\ \\_____\\ \\ \\_\\\\\"\\_\\ \n// \\/_/ \\/_/ \\/_/\\/_/ \\/_____/ \\/_____/ \\/_/ \\/_/ \\/_____/ \\/_/ \\/_/ \n//\n/// @title Generation 1 Pixelmon NFTs\n/// @author delta devs (https://www.twitter.com/deltadevelopers)\ncontract Pixelmon is ERC721, Ownable {\n using Strings for uint256;\n\n /*///////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////*/\n\n /// @dev Determines the order of the species for each tokenId, mechanism for choosing starting index explained post mint, explanation hash: acb427e920bde46de95103f14b8e57798a603abcf87ff9d4163e5f61c6a56881.\n uint constant public provenanceHash = 0x9912e067bd3802c3b007ce40b6c125160d2ccb5352d199e20c092fdc17af8057;\n\n /// @dev Sole receiver of collected contract funds, and receiver of 330 Pixelmon in the constructor.\n address constant gnosisSafeAddress = 0xF6BD9Fc094F7aB74a846E5d82a822540EE6c6971;\n\n /// @dev 7750, plus 330 for the Pixelmon Gnosis Safe\n uint constant auctionSupply = 7750 + 330;\n\n /// @dev The offsets are the tokenIds that the corresponding evolution stage will begin minting at.\n uint constant secondEvolutionOffset = 10005;\n uint constant thirdEvolutionOffset = secondEvolutionOffset + 4013;\n uint constant fourthEvolutionOffset = thirdEvolutionOffset + 1206;\n\n /*///////////////////////////////////////////////////////////////\n EVOLUTIONARY STORAGE\n //////////////////////////////////////////////////////////////*/\n\n /// @dev The next tokenID to be minted for each of the evolution stages\n uint secondEvolutionSupply = 0;\n uint thirdEvolutionSupply = 0;\n uint fourthEvolutionSupply = 0;\n\n /// @notice The address of the contract permitted to mint evolved Pixelmon.\n address public serumContract;\n\n /// @notice Returns true if the user is on the mintlist, if they have not already minted.\n mapping(address =\u003e bool) public mintlisted;\n\n /*///////////////////////////////////////////////////////////////\n AUCTION STORAGE\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Starting price of the auction.\n uint256 constant public auctionStartPrice = 3 ether;\n\n /// @notice Unix Timestamp of the start of the auction.\n /// @dev Monday, February 7th 2022, 13:00:00 converted to 1644256800 (GMT -5)\n uint256 constant public auctionStartTime = 1644256800;\n\n /// @notice Current mintlist price, which will be updated after the end of the auction phase.\n /// @dev We started with signatures, then merkle tree, but landed on mapping to reduce USER gas fees.\n uint256 public mintlistPrice = 0.75 ether;\n\n /*///////////////////////////////////////////////////////////////\n METADATA STORAGE\n //////////////////////////////////////////////////////////////*/\n\n string public baseURI;\n\n /*///////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Deploys the contract, minting 330 Pixelmon to the Gnosis Safe and setting the initial metadata URI.\n constructor(string memory _baseURI) ERC721(\"Pixelmon\", \"PXLMN\") {\n baseURI = _baseURI;\n unchecked {\n balanceOf[gnosisSafeAddress] += 330;\n totalSupply += 330;\n for (uint256 i = 0; i \u003c 330; i++) {\n ownerOf[i] = gnosisSafeAddress;\n emit Transfer(address(0), gnosisSafeAddress, i);\n }\n }\n }\n\n /*///////////////////////////////////////////////////////////////\n METADATA LOGIC\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Allows the contract deployer to set the metadata URI.\n /// @param _baseURI The new metadata URI.\n function setBaseURI(string memory _baseURI) public onlyOwner {\n baseURI = _baseURI;\n }\n\n function tokenURI(uint256 id) public view override returns (string memory) {\n return string(abi.encodePacked(baseURI, id.toString()));\n }\n\n /*///////////////////////////////////////////////////////////////\n DUTCH AUCTION LOGIC\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Calculates the auction price with the accumulated rate deduction since the auction\u0027s begin\n /// @return The auction price at the current time, or 0 if the deductions are greater than the auction\u0027s start price.\n function validCalculatedTokenPrice() private view returns (uint) {\n uint priceReduction = ((block.timestamp - auctionStartTime) / 10 minutes) * 0.1 ether;\n return auctionStartPrice \u003e= priceReduction ? (auctionStartPrice - priceReduction) : 0;\n }\n\n /// @notice Calculates the current dutch auction price, given accumulated rate deductions and a minimum price.\n /// @return The current dutch auction price\n function getCurrentTokenPrice() public view returns (uint256) {\n return max(validCalculatedTokenPrice(), 0.2 ether);\n }\n\n /// @notice Purchases a Pixelmon NFT in the dutch auction\n /// @param mintingTwo True if the user is minting two Pixelmon, otherwise false.\n /// @dev balanceOf is fine, team is aware and accepts that transferring out and repurchasing can be done, even by contracts. \n function auction(bool mintingTwo) public payable {\n if(block.timestamp \u003c auctionStartTime || block.timestamp \u003e auctionStartTime + 1 days) revert AuctionNotStarted();\n\n uint count = mintingTwo ? 2 : 1;\n uint price = getCurrentTokenPrice();\n\n if(totalSupply + count \u003e auctionSupply) revert MintedOut();\n if(balanceOf[msg.sender] + count \u003e 2) revert MintingTooMany();\n if(msg.value \u003c price * count) revert ValueTooLow();\n\n mintingTwo ? _mintTwo(msg.sender) : _mint(msg.sender, totalSupply);\n }\n \n /// @notice Mints two Pixelmons to an address\n /// @param to Receiver of the two newly minted NFTs\n /// @dev errors taken from super._mint\n function _mintTwo(address to) internal {\n require(to != address(0), \"INVALID_RECIPIENT\");\n require(ownerOf[totalSupply] == address(0), \"ALREADY_MINTED\");\n uint currentId = totalSupply;\n\n /// @dev unchecked because no arithmetic can overflow\n unchecked {\n totalSupply += 2;\n balanceOf[to] += 2;\n ownerOf[currentId] = to;\n ownerOf[currentId + 1] = to;\n emit Transfer(address(0), to, currentId);\n emit Transfer(address(0), to, currentId + 1);\n }\n }\n\n\n /*///////////////////////////////////////////////////////////////\n MINTLIST MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Allows the contract deployer to set the price of the mintlist. To be called before uploading the mintlist.\n /// @param price The price in wei of a Pixelmon NFT to be purchased from the mintlist supply.\n function setMintlistPrice(uint256 price) public onlyOwner {\n mintlistPrice = price;\n }\n\n /// @notice Allows the contract deployer to add a single address to the mintlist.\n /// @param user Address to be added to the mintlist.\n function mintlistUser(address user) public onlyOwner {\n mintlisted[user] = true;\n }\n\n /// @notice Allows the contract deployer to add a list of addresses to the mintlist.\n /// @param users Addresses to be added to the mintlist.\n function mintlistUsers(address[] calldata users) public onlyOwner {\n for (uint256 i = 0; i \u003c users.length; i++) {\n mintlisted[users[i]] = true; \n }\n }\n\n /// @notice Purchases a Pixelmon NFT from the mintlist supply\n /// @dev We do not check if auction is over because the mintlist will be uploaded after the auction. \n function mintlistMint() public payable {\n if(totalSupply \u003e= secondEvolutionOffset) revert MintedOut();\n if(!mintlisted[msg.sender]) revert NotMintlisted();\n if(msg.value \u003c mintlistPrice) revert ValueTooLow();\n\n mintlisted[msg.sender] = false;\n _mint(msg.sender, totalSupply);\n }\n\n /// @notice Withdraws collected funds to the Gnosis Safe address\n function withdraw() public onlyOwner {\n (bool success, ) = gnosisSafeAddress.call{value: address(this).balance}(\"\");\n require(success);\n }\n\n /*///////////////////////////////////////////////////////////////\n ROLL OVER LOGIC\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Allows the contract deployer to airdrop Pixelmon to a list of addresses, in case the auction doesn\u0027t mint out\n /// @param addresses Array of addresses to receive Pixelmon\n function rollOverPixelmons(address[] calldata addresses) public onlyOwner {\n if(totalSupply + addresses.length \u003e secondEvolutionOffset) revert MintedOut();\n\n for (uint256 i = 0; i \u003c addresses.length; i++) {\n _mint(msg.sender, totalSupply);\n }\n }\n\n /*///////////////////////////////////////////////////////////////\n EVOLUTIONARY LOGIC\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Sets the address of the contract permitted to call mintEvolvedPixelmon\n /// @param _serumContract The address of the EvolutionSerum contract\n function setSerumContract(address _serumContract) public onlyOwner {\n serumContract = _serumContract; \n }\n\n /// @notice Mints an evolved Pixelmon\n /// @param receiver Receiver of the evolved Pixelmon\n /// @param evolutionStage The evolution (2-4) that the Pixelmon is undergoing\n function mintEvolvedPixelmon(address receiver, uint evolutionStage) public payable {\n if(msg.sender != serumContract) revert UnauthorizedEvolution();\n\n if (evolutionStage == 2) {\n if(secondEvolutionSupply \u003e= 4013) revert MintedOut();\n _mint(receiver, secondEvolutionOffset + secondEvolutionSupply);\n unchecked {\n secondEvolutionSupply++;\n }\n } else if (evolutionStage == 3) {\n if(thirdEvolutionSupply \u003e= 1206) revert MintedOut();\n _mint(receiver, thirdEvolutionOffset + thirdEvolutionSupply);\n unchecked {\n thirdEvolutionSupply++;\n }\n } else if (evolutionStage == 4) {\n if(fourthEvolutionSupply \u003e= 33) revert MintedOut();\n _mint(receiver, fourthEvolutionOffset + fourthEvolutionSupply);\n unchecked {\n fourthEvolutionSupply++;\n }\n } else {\n revert UnknownEvolution();\n }\n }\n\n\n /*///////////////////////////////////////////////////////////////\n UTILS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Returns the greater of two numbers.\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a \u003e= b ? a : b;\n }\n\n}\n"},"Strings.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI\u0027s implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp \u003e\u003e= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i \u003e 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value \u0026 0xf];\n value \u003e\u003e= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n"}}